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