Mercurial > dive4elements > river
diff artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java @ 5838:5aa05a7a34b7
Rename modules to more fitting names.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 15:23:37 +0200 |
parents | flys-artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java@bd047b71ab37 |
children | 36404dc7fea0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java Thu Apr 25 15:23:37 2013 +0200 @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2011 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ +package org.dive4elements.river.exports; + +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.PageSize; +import com.lowagie.text.Rectangle; + +import com.lowagie.text.pdf.PdfContentByte; +import com.lowagie.text.pdf.PdfTemplate; +import com.lowagie.text.pdf.PdfWriter; + +import java.awt.Graphics2D; +import java.awt.Transparency; + +import java.awt.geom.Rectangle2D.Double; + +import java.awt.geom.Rectangle2D; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import org.jfree.chart.ChartRenderingInfo; + +import javax.imageio.ImageIO; + +import au.com.bytecode.opencsv.CSVWriter; + +import org.apache.batik.svggen.SVGGraphics2D; +import org.apache.batik.svggen.SVGGraphics2DIOException; + +import org.apache.log4j.Logger; + +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYDataset; + +import org.dive4elements.artifacts.CallContext; + +import org.dive4elements.artifacts.common.utils.XMLUtils; + + +/** + * This class is a helper class which supports some methods to export charts + * into specific formats. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class ChartExportHelper { + + public static final String FORMAT_PNG = "png"; + + public static final String FORMAT_PDF = "pdf"; + + public static final String FORMAT_SVG = "svg"; + + public static final String FORMAT_CSV = "csv"; + + /** + * Constant field to define A4 as default page size. + */ + public static final String DEFAULT_PAGE_SIZE = "A4"; + + /** + * Constant field to define UTF-8 as default encoding. + */ + public static final String DEFAULT_ENCODING = "UTF-8"; + + /** The default separator for the CSV export. */ + public static final char DEFAULT_CSV_SEPARATOR = ','; + + + /** + * Logger used for logging with log4j. + */ + private static Logger log = Logger.getLogger(ChartExportHelper.class); + + + /** + * A method to export a <code>JFreeChart</code> as image to an + * <code>OutputStream</code> with a given format, width and height. + * + * @param out OutputStream + * @param chart JFreeChart object to be exported. + * @param cc context, in which e.g. size is stored. + * + * @throws IOException if writing image to OutputStream failed. + */ + public static void exportImage( + OutputStream out, + JFreeChart chart, + CallContext cc + ) + throws IOException + { + log.info("export chart as png"); + + ChartRenderingInfo info = new ChartRenderingInfo(); + + String format = (String) cc.getContextValue("chart.image.format"); + + int[] size = getSize(cc); + + ImageIO.write( + chart.createBufferedImage( + size[0], size[1], Transparency.BITMASK, info + ), + format, + out + ); + } + + + /** + * A method to export a <code>JFreeChart</code> as SVG to an + * <code>OutputStream</code>. + * + * @param out OutputStream + * @param chart JFreeChart to be exported + * @param context The CallContext object that contains extra chart + * parameters. + */ + public static void exportSVG( + OutputStream out, + JFreeChart chart, + CallContext context + ) { + String encoding = (String) context.getContextValue("chart.encoding"); + + log.info("export chart as svg"); + + if (encoding == null) + encoding = DEFAULT_ENCODING; + + org.w3c.dom.Document document = XMLUtils.newDocument(); + SVGGraphics2D graphics = new SVGGraphics2D(document); + + int[] size = getSize(context); + + ChartRenderingInfo info = new ChartRenderingInfo(); + + chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,size[0],size[1]), info); + + try { + graphics.stream(new OutputStreamWriter(out, encoding)); + } + catch (SVGGraphics2DIOException svge) { + log.error("Error while writing svg export to output stream.", svge); + } + catch (UnsupportedEncodingException uee) { + log.error("Unsupported encoding: " + encoding, uee); + } + } + + + /** + * A method to export a <code>JFreeChart</code> as PDF to an + * <code>OutputStream</code>. + * + * @param out OutputStream + * @param chart JFreeChart + */ + public static void exportPDF( + OutputStream out, + JFreeChart chart, + CallContext cc + ) { + log.info("export chart as pdf."); + + String pageFormat = (String) cc.getContextValue("chart.page.format"); + + if (pageFormat == null) + pageFormat = DEFAULT_PAGE_SIZE; + + // Max size of the chart. + Rectangle page = PageSize.getRectangle(pageFormat); + float pageWidth = page.getWidth(); + float pageHeight = page.getHeight(); + + // The chart width. + int[] size = getSize(cc); + + boolean landscape = size[0] > size[1]; + + float width = 0; + float height = 0; + if (landscape) { + width = pageHeight; + height = pageWidth; + } + else { + width = pageWidth; + height = pageHeight; + } + + float marginLeft = (Float) cc.getContextValue( + "chart.marginLeft"); + + float marginRight = (Float) cc.getContextValue( + "chart.marginRight"); + + float marginTop = (Float) cc.getContextValue( + "chart.marginTop"); + + float marginBottom = (Float) cc.getContextValue( + "chart.marginBottom"); + + float spaceX = width - marginLeft - marginRight; + if (size[0] > spaceX) { + log.warn("Width of the chart is too big for pdf -> resize it now."); + double ratio = ((double)spaceX) / size[0]; + size[0] *= ratio; + size[1] *= ratio; + log.debug("Resized chart to " + size[0] + "x" + size[1]); + } + + float spaceY = height - marginTop - marginBottom; + if (size[1] > spaceY) { + log.warn("Height of the chart is too big for pdf -> resize it now."); + double ratio = ((double)spaceY) / size[1]; + size[0] *= ratio; + size[1] *= ratio; + log.debug("Resized chart to " + size[0] + "x" + size[1]); + } + + Document document = null; + if (landscape) { + document = new Document(page.rotate()); + log.debug("Create landscape pdf."); + } + else + document = new Document(page); + + try { + PdfWriter writer = PdfWriter.getInstance(document, out); + + document.addSubject(chart.getTitle().getText()); + document.addCreationDate(); + document.open(); + + PdfContentByte content = writer.getDirectContent(); + + PdfTemplate template = content.createTemplate(width, height); + Graphics2D graphics = template.createGraphics(width, height); + + double[] origin = getCenteredAnchor( + marginLeft, marginRight, marginBottom, marginTop, + width, height, + size[0], size[1]); + + Rectangle2D area = new Rectangle2D.Double( + origin[0], origin[1], size[0], size[1]); + + ChartRenderingInfo info = new ChartRenderingInfo(); + + chart.draw(graphics, area, info); + graphics.dispose(); + content.addTemplate(template, 0f, 0f); + } + catch (DocumentException de) { + log.error("Error while exporting chart to pdf.", de); + } + finally { + document.close(); + } + } + + + /** + * A method to export a CSV file to an + * <code>OutputStream</code>. + * + * @param out OutputStream + * @param chart JFreeChart containing the data. + * @param context The CallContext object that contains extra parameters. + */ + public static void exportCSV( + OutputStream out, + JFreeChart chart, + CallContext context) + { + log.debug("export chart as CSV"); + CSVWriter writer = null; + try { + writer = new CSVWriter( + new OutputStreamWriter( + out, + DEFAULT_ENCODING), + DEFAULT_CSV_SEPARATOR); + } + catch(UnsupportedEncodingException uee) { + log.warn("Wrong encoding for CSV export."); + return; + } + XYPlot plot = chart.getXYPlot(); + int count = plot.getDatasetCount(); + for (int i = 0; i < count; i++) { + XYDataset data = plot.getDataset(i); + int scount = data.getSeriesCount(); + for (int j = 0; j < scount; j++) { + Comparable seriesKey = data.getSeriesKey(j); + log.debug("series key: " + seriesKey.toString()); + writeCSVHeader(writer, seriesKey.toString()); + writeCSVData(writer, data); + } + } + try { + writer.close(); + } + catch(IOException ioe) { + log.error("Writing CSV export failed!"); + } + } + + + protected static void writeCSVHeader(CSVWriter writer, String key) { + writer.writeNext(new String[] {"#"}); + writer.writeNext(new String[] {"# " + key}); + writer.writeNext(new String[] {"#"}); + writer.writeNext(new String[] {"X", "Y"}); + } + + + protected static void writeCSVData(CSVWriter writer, XYDataset data) { + int series = data.getSeriesCount(); + for (int i = 0; i < series; i++) { + int items = data.getItemCount(i); + for (int j = 0; j < items; j++) { + log.debug("write data: " + data.getX(i, j) + ", " + data.getY(i, j)); + writer.writeNext(new String[] { + data.getX(i, j).toString(), + data.getY(i, j).toString()}); + } + } + } + + + public static int[] getSize(CallContext cc) { + int[] size = new int[2]; + + size[0] = (Integer) cc.getContextValue("chart.width"); + size[1] = (Integer) cc.getContextValue("chart.height"); + + return size; + } + + + /** + * This method returns the anchor of the chart so that the chart is centered + * according to the given parameters. + * + * @param mLeft Left margin + * @param mRight Right margin + * @param mBottom Bottom margin + * @param mTop Top margin + * @param width The complete width of the drawing area. + * @param height The complete height of the drawing area. + * @param chartWidth The width of the chart. + * @param chartHeight The height of the chart. + * + * @return an array that contains the anchor for a chart with the given + * parameters. The first value is the x point, the second value is the y + * point. + */ + public static double[] getCenteredAnchor( + double mLeft, double mRight, double mBottom, double mTop, + double width, double height, + double chartWidth, double chartHeight + ) { + if (log.isDebugEnabled()) { + log.debug("Calculate centered origin..."); + log.debug("-> PDF width : " + width); + log.debug("-> PDF height : " + height); + log.debug("-> Chart width : " + chartWidth); + log.debug("-> Chart height : " + chartHeight); + log.debug("-> margin left : " + mLeft); + log.debug("-> margin right : " + mRight); + log.debug("-> margin bottom: " + mBottom); + log.debug("-> margin top : " + mTop); + } + + double[] origin = new double[2]; + + double centerX = width / 2; + double centerY = height / 2; + + origin[0] = centerX - chartWidth / 2; + origin[1] = centerY - chartHeight / 2; + + origin[0] = origin[0] >= mLeft ? origin[0] : mLeft; + origin[1] = origin[1] >= mTop ? origin[1] : mTop; + + if (log.isDebugEnabled()) { + log.debug("==> centered left origin: " + origin[0]); + log.debug("==> centered top origin: " + origin[1]); + } + + return origin; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :