package org.docbag.chart.jfree;
import java.awt.*;
import java.io.CharArrayWriter;
import java.io.Writer;
import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.converter.Converter;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
/**
* Converter implementation that knows how to convert {@link org.docbag.chart.Chart} into it's SVG representation.
*
* <p>Instead of converting the {@link org.docbag.chart.Chart} itself, the Wrapper wrapper object
* is passed to the conversion. Besides the chart itself the wrapper also carries the width and height data
* making it possible to reuse the same chart object and render it many times in a template in
* different sizes.</p>
*
* @author Jakub Torbicki
*/
public class ChartToSVGConverter implements Converter<BaseChart.Wrapper, String> {
// Empty SVG is returned in case of a conversion error
private static final String EMPTY_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>";
private static final Logger log = LoggerFactory.getLogger(ChartToSVGConverter.class);
public String convert(BaseChart.Wrapper chartHolder) {
return convert(chartHolder.chart, chartHolder.width, chartHolder.height);
}
public String convert(BaseChart chart, int width, int height) {
if (chart == null) {
throw new NullPointerException("chart not set!");
}
if (width <= 0 || height <= 0) {
log.warn("Invalid width \\ height parameters: width=" + width + ", height=" + height);
return EMPTY_SVG;
}
SVGGraphics2D svgGenerator = new SVGGraphics2D(getDocument());
// synchronized has to stay here as long as JFreeChart is not thread-safe.
// (version 1.0.14 is not)
synchronized (chart) {
chart.getChart().draw(svgGenerator, new java.awt.geom.Rectangle2D.Double(0, 0, width, height));
}
// Set rendering properties
svgGenerator.setSVGCanvasSize(new Dimension(width, height));
svgGenerator.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
svgGenerator.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
return generateOutput(svgGenerator);
}
private String generateOutput(SVGGraphics2D svgGenerator) {
Writer writer = new CharArrayWriter();
try {
svgGenerator.stream(writer, true);
String svg = writer.toString();
return svg.substring(svg.indexOf("<svg")); // TODO hack
} catch (SVGGraphics2DIOException e) {
log.error("SVGGraphics2DIOException: ", e.getLocalizedMessage(), e);
}
return EMPTY_SVG;
}
private Document getDocument() {
DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
return domImpl.createDocument(null, "svg", null);
}
}