ingo@318: package de.intevation.gnv.exports;
ingo@318:
ingo@320: import com.lowagie.text.Document;
ingo@320: import com.lowagie.text.DocumentException;
ingo@320: import com.lowagie.text.PageSize;
ingo@320: import com.lowagie.text.Rectangle;
sascha@623:
ingo@320: import com.lowagie.text.pdf.PdfContentByte;
ingo@320: import com.lowagie.text.pdf.PdfTemplate;
ingo@320: import com.lowagie.text.pdf.PdfWriter;
ingo@320:
ingo@1050: import de.intevation.artifacts.CallContext;
ingo@1050:
sascha@623: import de.intevation.artifactdatabase.XMLUtils;
sascha@623:
sascha@623: import de.intevation.gnv.chart.Chart;
sascha@623:
ingo@320: import java.awt.Graphics2D;
sascha@623: import java.awt.Transparency;
sascha@623:
sascha@623: import java.awt.geom.Rectangle2D.Double;
sascha@623:
ingo@320: import java.awt.geom.Rectangle2D;
sascha@623:
ingo@617: import java.awt.image.BufferedImage;
sascha@623:
sascha@623: import java.io.IOException;
ingo@318: import java.io.OutputStream;
ingo@321: import java.io.OutputStreamWriter;
ingo@321: import java.io.UnsupportedEncodingException;
sascha@623:
ingo@318: import javax.imageio.ImageIO;
ingo@318:
ingo@321: import org.apache.batik.svggen.SVGGraphics2D;
ingo@321: import org.apache.batik.svggen.SVGGraphics2DIOException;
sascha@623:
ingo@318: import org.apache.log4j.Logger;
ingo@318:
ingo@318: import org.jfree.chart.JFreeChart;
ingo@318:
ingo@318: /**
ingo@771: * This class is a helper class which supports some methods to export charts
ingo@771: * into specific formats.
ingo@771: *
ingo@771: * @author Ingo Weinzierl
ingo@318: */
ingo@318: public class ChartExportHelper {
ingo@318:
ingo@771: /**
ingo@771: * Constant field to define A4 as default page size.
ingo@771: */
ingo@320: private static final String DEFAULT_PAGE_SIZE = "A4";
ingo@771:
ingo@771: /**
ingo@771: * Constant field to define UTF-8 as default encoding.
ingo@771: */
ingo@321: private static final String DEFAULT_ENCODING = "UTF-8";
ingo@318:
ingo@771: /**
ingo@771: * Logger used for logging with log4j.
ingo@771: */
ingo@318: private static Logger log = Logger.getLogger(ChartExportHelper.class);
ingo@318:
ingo@771:
ingo@771: /**
sascha@778: * A method to export a JFreeChart
as image to an
ingo@771: * OutputStream
with a given format, width and height.
ingo@771: *
ingo@771: * @param out OutputStream
ingo@794: * @param chart JFreeChart object to be exported.
ingo@771: * @param format Format (e.g. png, gif, jpg)
ingo@771: * @param width Width, the image used to be
ingo@771: * @param height Height, the image used to be
ingo@771: *
ingo@771: * @throws IOException if writing image to OutputStream failed.
ingo@771: */
ingo@318: public static void exportImage(
ingo@318: OutputStream out,
ingo@318: JFreeChart chart,
ingo@318: String format,
ingo@318: int width,
ingo@318: int height
ingo@318: )
ingo@318: throws IOException
ingo@318: {
ingo@318: log.info("export chart as png");
ingo@318:
ingo@318: ImageIO.write(
ingo@318: chart.createBufferedImage(
ingo@318: width, height, Transparency.BITMASK, null
ingo@318: ),
ingo@318: format,
ingo@318: out
ingo@318: );
ingo@318: }
ingo@318:
ingo@320:
ingo@771: /**
ingo@771: * A method to export a JFreeChart
histogram as image to an
ingo@771: * OutputStream
with a given format, width and height.
ingo@771: *
ingo@771: * @param out OutputStream
ingo@771: * @param histograms Array of {@link de.intevation.gnv.chart.Chart} objects
ingo@771: * @param format A format (e.g. png, gif, jpg)
ingo@771: * @param width Width the image used to be
ingo@771: * @param height Height the image used to be
ingo@771: *
ingo@771: * @throws IOException if writing image to OutputStream failed.
ingo@771: */
ingo@617: public static void exportHistograms(
ingo@617: OutputStream out,
ingo@617: Chart[] histograms,
ingo@617: String format,
ingo@617: int width,
ingo@617: int height)
ingo@617: throws IOException
ingo@617: {
ingo@617: log.info("export histograms");
ingo@617:
ingo@617: int size = histograms.length;
ingo@617: BufferedImage image = new BufferedImage(
ingo@617: width, height*size, BufferedImage.TYPE_INT_RGB);
ingo@617: Graphics2D g = image.createGraphics();
ingo@617:
ingo@617: for (int i = 0; i < size; i++) {
ingo@617: JFreeChart chart = histograms[i].generateChart();
ingo@617: chart.draw(g, new Rectangle2D.Double(0.0D, i*height, width, height));
ingo@617: }
ingo@617: g.finalize();
ingo@617:
ingo@617: ImageIO.write(image, format, out);
ingo@617: }
ingo@617:
ingo@617:
ingo@771: /**
ingo@771: * A method to export a JFreeChart
histogram as SVG to an
ingo@771: * OutputStream
.
sascha@778: *
ingo@771: * @param out OutputStream
ingo@771: * @param histograms Array of {@link de.intevation.gnv.chart.Chart}
ingo@815: * @param encoding Encoding, defaults to {@link #DEFAULT_ENCODING} if null
ingo@771: * @param width Width the svg used to be
ingo@771: * @param height Height the svg used to be
ingo@771: */
ingo@639: public static void exportHistogramsAsSVG(
ingo@639: OutputStream out,
ingo@639: Chart[] histograms,
ingo@639: String encoding,
ingo@639: int width,
ingo@639: int height
ingo@639: ) {
ingo@639: log.info("export histograms as svg");
ingo@639:
ingo@639: if (encoding == null)
ingo@639: encoding = DEFAULT_ENCODING;
ingo@639:
ingo@639: org.w3c.dom.Document document = XMLUtils.newDocument();
ingo@639: SVGGraphics2D graphics = new SVGGraphics2D(document);
ingo@639:
ingo@639: int size = histograms.length;
ingo@639: for (int i = 0; i < size; i++) {
ingo@639: JFreeChart chart = histograms[i].generateChart();
ingo@639: chart.draw(graphics, new Rectangle2D.Double(
ingo@639: 0.0D, i*height,width,height));
ingo@639: }
ingo@639: graphics.finalize();
ingo@639:
ingo@639: try {
ingo@639: graphics.stream(new OutputStreamWriter(out, encoding));
ingo@639: }
ingo@639: catch (SVGGraphics2DIOException svge) {
ingo@639: log.error("Error while writing svg export to output stream.", svge);
ingo@639: }
ingo@639: catch (UnsupportedEncodingException uee) {
ingo@639: log.error("Unsupported encoding: " + encoding, uee);
ingo@639: }
ingo@639: }
ingo@639:
ingo@639:
ingo@771: /**
ingo@771: * A method to export a JFreeChart
as SVG to an
ingo@771: * OutputStream
.
sascha@778: *
ingo@771: * @param out OutputStream
ingo@771: * @param chart JFreeChart to be exported
ingo@815: * @param encoding Encoding, defaults to {@link #DEFAULT_ENCODING} if null
ingo@771: * @param width Width the svg used to be
ingo@771: * @param height Height the svg used to be
ingo@771: */
ingo@321: public static void exportSVG(
ingo@321: OutputStream out,
ingo@321: JFreeChart chart,
ingo@321: String encoding,
ingo@321: int width,
ingo@321: int height
ingo@321: ) {
ingo@321: log.info("export chart as svg");
ingo@321:
ingo@321: if (encoding == null)
ingo@321: encoding = DEFAULT_ENCODING;
ingo@321:
ingo@323: org.w3c.dom.Document document = XMLUtils.newDocument();
ingo@321: SVGGraphics2D graphics = new SVGGraphics2D(document);
ingo@321:
ingo@321: chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,width,height));
ingo@321:
ingo@321: try {
ingo@321: graphics.stream(new OutputStreamWriter(out, encoding));
ingo@321: }
ingo@321: catch (SVGGraphics2DIOException svge) {
ingo@321: log.error("Error while writing svg export to output stream.", svge);
ingo@321: }
ingo@321: catch (UnsupportedEncodingException uee) {
ingo@321: log.error("Unsupported encoding: " + encoding, uee);
ingo@321: }
ingo@318: }
ingo@318:
ingo@320:
ingo@771: /**
ingo@771: * A method to export a JFreeChart
as PDF to an
ingo@771: * OutputStream
.
ingo@771: *
ingo@771: * @param out OutputStream
ingo@771: * @param chart JFreeChart
ingo@771: * @param pageFormat String to specify a page format, {@link
ingo@815: * #DEFAULT_PAGE_SIZE} is used if no pageFormat is given
ingo@771: * @param landscape If this is true, the pdf is delivered in landscape
ingo@771: * format
ingo@771: * @param marginLeft Space to left border
ingo@771: * @param marginRight Space to right border
ingo@771: * @param marginTop Space to upper border
ingo@771: * @param marginBottom Space to lower border
ingo@771: */
ingo@320: public static void exportPDF(
ingo@320: OutputStream out,
ingo@320: JFreeChart chart,
ingo@320: String pageFormat,
ingo@320: float marginLeft,
ingo@320: float marginRight,
ingo@320: float marginTop,
ingo@1050: float marginBottom,
ingo@1050: CallContext context
ingo@320: ) {
ingo@320: log.info("export chart as pdf.");
ingo@320:
ingo@320: if (pageFormat == null)
ingo@320: pageFormat = DEFAULT_PAGE_SIZE;
ingo@320:
ingo@1050: // max size of the chart
ingo@320: Rectangle page = PageSize.getRectangle(pageFormat);
ingo@1086: float pageWidth = page.getWidth();
ingo@1086: float pageHeight = page.getHeight();
ingo@320:
ingo@1050: // the chart width
ingo@1050: int chartWidth = (Integer) context.getContextValue("chart.width");
ingo@1050: int chartHeight = (Integer) context.getContextValue("chart.height");
ingo@1050:
ingo@1052: boolean landscape = chartWidth > chartHeight ? true : false;
ingo@1052:
ingo@1086: float width = 0;
ingo@1086: float height = 0;
ingo@1050: if (landscape) {
ingo@1050: width = pageHeight;
ingo@1050: height = pageWidth;
ingo@1050: }
ingo@1050: else {
ingo@1050: width = pageWidth;
ingo@1050: height = pageHeight;
ingo@1050: }
ingo@1050:
ingo@1086: float spaceX = width - marginLeft - marginRight;
ingo@1086: if (chartWidth > spaceX) {
ingo@1050: log.warn("Width of the chart is too big for pdf -> resize it now.");
ingo@1086: double ratio = ((double)spaceX) / chartWidth;
ingo@1050: chartWidth *= ratio;
ingo@1050: chartHeight *= ratio;
ingo@1050: log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
ingo@1050: }
ingo@1050:
ingo@1086: float spaceY = height - marginTop - marginBottom;
ingo@1086: if (chartHeight > spaceY) {
ingo@1050: log.warn("Height of the chart is too big for pdf -> resize it now.");
ingo@1086: double ratio = ((double)spaceY) / chartHeight;
ingo@1050: chartWidth *= ratio;
ingo@1050: chartHeight *= ratio;
ingo@1050: log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
ingo@1050: }
ingo@1050:
ingo@320: Document document = null;
ingo@320: if (landscape) {
ingo@320: document = new Document(page.rotate());
ingo@320: log.debug("Create landscape pdf.");
ingo@320: }
ingo@320: else
ingo@320: document = new Document(page);
ingo@320:
ingo@320: try {
ingo@320: PdfWriter writer = PdfWriter.getInstance(document, out);
ingo@320:
ingo@320: document.addSubject(chart.getTitle().getText());
ingo@320: document.addCreationDate();
ingo@320: document.open();
ingo@320:
ingo@320: PdfContentByte content = writer.getDirectContent();
ingo@320:
ingo@320: PdfTemplate template = content.createTemplate(width, height);
ingo@1086: Graphics2D graphics = template.createGraphics(width, height);
ingo@1086:
ingo@1086: double[] origin = getCenteredAnchor(
ingo@1086: marginLeft, marginRight, marginBottom, marginTop,
ingo@1086: width, height,
ingo@1056: chartWidth, chartHeight);
ingo@1086:
ingo@1050: Rectangle2D area = new Rectangle2D.Double(
ingo@1086: origin[0], origin[1], chartWidth, chartHeight);
ingo@320:
ingo@320: chart.draw(graphics, area);
ingo@320: graphics.dispose();
ingo@1086: content.addTemplate(template, 0f, 0f);
ingo@320: }
ingo@320: catch (DocumentException de) {
ingo@320: log.error("Error while exporting chart to pdf.", de);
ingo@320: }
ingo@320: finally {
ingo@320: document.close();
ingo@320: }
ingo@318: }
ingo@640:
ingo@640:
ingo@771: /**
ingo@771: * A method to export JFreeChart
histograms as PDF to an
ingo@771: * OutputStream
. Each histogram contained in histograms is
ingo@771: * drawn to an own page in the resulting pdf.
ingo@771: *
ingo@771: * @param out OutputStream
ingo@771: * @param histograms JFreeChart histograms
ingo@771: * @param pageFormat String to specify a page format, {@link
ingo@815: * #DEFAULT_PAGE_SIZE} is used if no pageFormat is given
ingo@771: * @param landscape If this is true, the pdf is delivered in landscape
ingo@771: * format
ingo@771: * @param marginLeft Space to left border
ingo@771: * @param marginRight Space to right border
ingo@771: * @param marginTop Space to upper border
ingo@771: * @param marginBottom Space to lower border
ingo@771: */
ingo@640: public static void exportHistogramsAsPDF(
ingo@640: OutputStream out,
ingo@640: Chart[] histograms,
ingo@640: String pageFormat,
ingo@640: float marginLeft,
ingo@640: float marginRight,
ingo@640: float marginTop,
ingo@1053: float marginBottom,
ingo@1053: CallContext context
ingo@640: ) {
ingo@640: log.info("export histogram as pdf.");
ingo@640:
ingo@640: if (pageFormat == null)
ingo@640: pageFormat = DEFAULT_PAGE_SIZE;
ingo@640:
ingo@640: Rectangle page = PageSize.getRectangle(pageFormat);
ingo@1087: float pageWidth = page.getWidth();
ingo@1087: float pageHeight = page.getHeight();
ingo@640:
ingo@1053: // the chart width
ingo@1053: int chartWidth = (Integer) context.getContextValue("chart.width");
ingo@1053: int chartHeight = (Integer) context.getContextValue("chart.height");
ingo@1053:
ingo@1053: boolean landscape = chartWidth > chartHeight ? true : false;
ingo@1053:
ingo@1087: float width = 0;
ingo@1087: float height = 0;
ingo@1053: if (landscape) {
ingo@1053: width = pageHeight;
ingo@1053: height = pageWidth;
ingo@1053: }
ingo@1053: else {
ingo@1053: width = pageWidth;
ingo@1053: height = pageHeight;
ingo@1053: }
ingo@1053:
ingo@1087: float spaceX = width - marginLeft - marginRight;
ingo@1087: if (chartWidth > spaceX) {
ingo@1053: log.warn("Histogram width is too big for pdf -> resize it now.");
ingo@1087: double ratio = ((double)spaceX) / chartWidth;
ingo@1053: chartWidth *= ratio;
ingo@1053: chartHeight *= ratio;
ingo@1087: log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
ingo@1053: }
ingo@1053:
ingo@1087: float spaceY = height - marginTop - marginBottom;
ingo@1087: if (chartHeight > spaceY) {
ingo@1053: log.warn("Histogram height is too big for pdf -> resize it now.");
ingo@1087: double ratio = ((double)spaceY) / chartHeight;
ingo@1053: chartWidth *= ratio;
ingo@1053: chartHeight *= ratio;
ingo@1087: log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
ingo@1053: }
ingo@1053:
ingo@640: Document document = null;
ingo@640: if (landscape) {
ingo@640: document = new Document(page.rotate());
ingo@640: log.debug("Create landscape pdf.");
ingo@640: }
ingo@640: else
ingo@640: document = new Document(page);
ingo@640:
ingo@640: try {
ingo@640: PdfWriter writer = PdfWriter.getInstance(document, out);
ingo@640:
ingo@640: document.addCreationDate();
ingo@640: document.open();
ingo@640:
ingo@640: PdfContentByte content = writer.getDirectContent();
ingo@640:
ingo@640: int size = histograms.length;
ingo@640: for (int i = 0; i < size; i++) {
ingo@640: if (i > 0) {
ingo@640: document.newPage();
ingo@640: }
ingo@640:
ingo@640: JFreeChart chart = histograms[i].generateChart();
ingo@640: PdfTemplate template = content.createTemplate(width, height);
ingo@1087: Graphics2D graphics = template.createGraphics(width, height);
ingo@1087:
ingo@1087: double[] origin = getCenteredAnchor(
ingo@1087: marginLeft, marginRight, marginBottom, marginTop,
ingo@1087: width, height,
ingo@1053: chartWidth, chartHeight);
ingo@1087:
ingo@640: Rectangle2D area = new Rectangle2D.Double(
ingo@1087: origin[0], origin[1], chartWidth, chartHeight);
ingo@640:
ingo@640: chart.draw(graphics, area);
ingo@640: graphics.dispose();
ingo@1087: content.addTemplate(template, 0f, 0f);
ingo@640: }
ingo@640: }
ingo@640: catch (DocumentException de) {
ingo@1053: log.error("Error while exporting histogram to pdf.", de);
ingo@640: }
ingo@640: finally {
ingo@640: document.close();
ingo@640: }
ingo@640: }
ingo@1086:
ingo@1086:
ingo@1086: /**
ingo@1086: * This method returns the anchor of the chart so that the chart is centered
ingo@1086: * according to the given parameters.
ingo@1086: *
ingo@1086: * @param mLeft Left margin
ingo@1086: * @param mRight Right margin
ingo@1086: * @param mBottom Bottom margin
ingo@1086: * @param mTop Top margin
ingo@1086: * @param width The complete width of the drawing area.
ingo@1086: * @param height The complete height of the drawing area.
ingo@1086: * @param chartWidth The width of the chart.
ingo@1086: * @param chartHeight The height of the chart.
ingo@1086: *
ingo@1086: * @return an array that contains the anchor for a chart with the given
ingo@1086: * parameters. The first value is the x point, the second value is the y
ingo@1086: * point.
ingo@1086: */
ingo@1086: public static double[] getCenteredAnchor(
ingo@1086: double mLeft, double mRight, double mBottom, double mTop,
ingo@1086: double width, double height,
ingo@1086: double chartWidth, double chartHeight
ingo@1086: ) {
ingo@1086: if (log.isDebugEnabled()) {
ingo@1086: log.debug("Calculate centered origin...");
ingo@1086: log.debug("-> PDF width : " + width);
ingo@1086: log.debug("-> PDF height : " + height);
ingo@1086: log.debug("-> Chart width : " + chartWidth);
ingo@1086: log.debug("-> Chart height : " + chartHeight);
ingo@1086: log.debug("-> margin left : " + mLeft);
ingo@1086: log.debug("-> margin right : " + mRight);
ingo@1086: log.debug("-> margin bottom: " + mBottom);
ingo@1086: log.debug("-> margin top : " + mTop);
ingo@1086: }
ingo@1086:
ingo@1086: double[] origin = new double[2];
ingo@1086:
ingo@1086: double centerX = width / 2;
ingo@1086: double centerY = height / 2;
ingo@1086:
ingo@1086: origin[0] = centerX - chartWidth / 2;
ingo@1086: origin[1] = centerY - chartHeight / 2;
ingo@1086:
ingo@1086: origin[0] = origin[0] >= mLeft ? origin[0] : mLeft;
ingo@1086: origin[1] = origin[1] >= mTop ? origin[1] : mTop;
ingo@1086:
ingo@1086: if (log.isDebugEnabled()) {
ingo@1086: log.debug("==> centered left origin: " + origin[0]);
ingo@1086: log.debug("==> centered top origin: " + origin[1]);
ingo@1086: }
ingo@1086:
ingo@1086: return origin;
ingo@1086: }
ingo@318: }
ingo@320: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :