ingo@1115: /* ingo@1115: * Copyright (c) 2010 by Intevation GmbH ingo@1115: * ingo@1115: * This program is free software under the LGPL (>=v2.1) ingo@1115: * Read the file LGPL.txt coming with the software for details ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1115: */ ingo@1115: 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@1117: import de.intevation.artifacts.common.utils.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 :