Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ ChartEncoder.saveChart(chart, outputStream, "png");
byte[] bytes = ChartEncoder.getBytes(chart, "png");
```

To export a chart at a different size than it was built with, for example a chart constructed by code you don't control, resize it first with `setSize`:

```java
chart.setSize(1920, 1080);
ChartEncoder.saveChart(chart, "./MyChart", "png");
```

* **Raster formats** (`png`, `jpg`, `bmp`, `gif`, `tiff`) are delegated to `javax.imageio.ImageIO`. Any other format for which an `ImageWriter` plugin is registered on the classpath works too — e.g. add `com.github.usefulness:webp-imageio` to export `webp` (see the `ExampleWebP` demo), or an AVIF plugin to export `avif`. Call `ChartEncoder.getSupportedRasterFormats()` to see what the current classpath can write. For AVIF, where no bundleable ImageIO writer exists yet, the `ExampleAvif` demo shows a portable fallback that pipes a PNG through the `avifenc` CLI (`brew install libavif`).
* **Vector formats** (`svg`, `eps`, `pdf`) require the optional dependencies below.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.knowm.xchart.standalone.issues;

import java.io.IOException;
import org.knowm.xchart.ChartEncoder;
import org.knowm.xchart.SwingWrapper;
import org.knowm.xchart.XYChart;
import org.knowm.xchart.XYChartBuilder;

/**
* Demonstrates resizing an already constructed chart before export, so a chart received from
* elsewhere can be saved at any dimensions. https://github.com/knowm/XChart/issues/807
*/
public class TestForIssue807 {

public static void main(String[] args) throws IOException {

XYChart chart = getChart();
chart.setSize(1280, 720);
ChartEncoder.saveChart(chart, "./TestForIssue807", "png");
new SwingWrapper<>(chart).displayChart();
}

public static XYChart getChart() {

XYChart chart =
new XYChartBuilder()
.width(640)
.height(480)
.title("Resized before export")
.xAxisTitle("Time")
.yAxisTitle("Value")
.build();
chart.addSeries("Sample", new double[] {0, 1, 2, 3, 4}, new double[] {1, 3, 2, 5, 4});
return chart;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,26 @@ protected void setHeight(int height) {
this.height = height;
}

/**
* Sets the chart's width and height in pixels. This is useful for a chart constructed elsewhere
* that should be exported or displayed at a different size than it was built with. Exporters
* such as {@code ChartEncoder} lay the chart out at these dimensions.
*
* @param width the new width, greater than 0
* @param height the new height, greater than 0
* @return this chart, for chaining
* @throws IllegalArgumentException if either dimension is not positive
*/
public Chart<ST, S> setSize(int width, int height) {

if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Chart width and height must be greater than 0 !!!");
}
this.width = width;
this.height = height;
return this;
}

// TODO remove public
public String getTitle() {

Expand Down
94 changes: 94 additions & 0 deletions xchart/src/test/java/org/knowm/xchart/ChartSizeTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.knowm.xchart;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.junit.jupiter.api.Test;

/** https://github.com/knowm/XChart/issues/807 */
public class ChartSizeTest {

private static XYChart sampleChart() {
XYChart chart = new XYChartBuilder().width(500).height(400).title("Sample").build();
chart.addSeries("y(x)", new double[] {0, 1, 2}, new double[] {2, 1, 0});
return chart;
}

@Test
public void setSizeUpdatesDimensionsAndChains() {

XYChart chart = sampleChart();
assertThat(chart.setSize(1920, 1080)).isSameAs(chart);
assertThat(chart.getWidth()).isEqualTo(1920);
assertThat(chart.getHeight()).isEqualTo(1080);
}

@Test
public void setSizeRejectsNonPositiveDimensions() {

XYChart chart = sampleChart();
for (int[] size : new int[][] {{0, 100}, {100, 0}, {-1, 100}, {100, -1}}) {
assertThatThrownBy(() -> chart.setSize(size[0], size[1]))
.isInstanceOf(IllegalArgumentException.class);
}
assertThat(chart.getWidth()).isEqualTo(500);
assertThat(chart.getHeight()).isEqualTo(400);
}

@Test
public void rasterExportUsesNewSize() throws IOException {

XYChart chart = sampleChart();
chart.setSize(800, 300);
BufferedImage image =
ImageIO.read(new ByteArrayInputStream(ChartEncoder.getBytes(chart, "png")));
assertThat(image.getWidth()).isEqualTo(800);
assertThat(image.getHeight()).isEqualTo(300);
}

@Test
public void vectorExportUsesNewSize() throws IOException {

XYChart chart = sampleChart();
chart.setSize(720, 360);

String svg = new String(ChartEncoder.getBytes(chart, "svg"), StandardCharsets.UTF_8);
Matcher viewBox = Pattern.compile("viewBox=\"([^\"]+)\"").matcher(svg);
assertThat(viewBox.find()).isTrue();
String[] bounds = viewBox.group(1).trim().split("\\s+");
assertThat(Double.parseDouble(bounds[2])).isEqualTo(720.0);
assertThat(Double.parseDouble(bounds[3])).isEqualTo(360.0);

try (PDDocument pdf = Loader.loadPDF(ChartEncoder.getBytes(chart, "pdf"))) {
assertThat(pdf.getPage(0).getMediaBox().getWidth()).isEqualTo(720.0f);
assertThat(pdf.getPage(0).getMediaBox().getHeight()).isEqualTo(360.0f);
}
}

@Test
public void setSizeWorksForOtherChartTypes() throws IOException {

PieChart pie = new PieChartBuilder().width(500).height(400).build();
pie.addSeries("A", 3);
pie.setSize(300, 600);
BufferedImage image = ImageIO.read(new ByteArrayInputStream(ChartEncoder.getBytes(pie, "png")));
assertThat(image.getWidth()).isEqualTo(300);
assertThat(image.getHeight()).isEqualTo(600);

CategoryChart bars = new CategoryChartBuilder().width(500).height(400).build();
bars.addSeries("Sample", new double[] {1, 2, 3}, new double[] {2, 4, 3});
bars.setSize(640, 200);
image = ImageIO.read(new ByteArrayInputStream(ChartEncoder.getBytes(bars, "png")));
assertThat(image.getWidth()).isEqualTo(640);
assertThat(image.getHeight()).isEqualTo(200);
}
}
Loading