view gnv-artifacts/src/main/java/de/intevation/gnv/exports/ChartExportHelper.java @ 1115:f953c9a559d8

Added license file and license headers. gnv-artifacts/trunk@1260 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Tue, 02 Nov 2010 17:46:55 +0000
parents 92fce3b3d07f
children dec4257ad570
line wrap: on
line source
/*
 * Copyright (c) 2010 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 de.intevation.gnv.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 de.intevation.artifacts.CallContext;

import de.intevation.artifactdatabase.XMLUtils;

import de.intevation.gnv.chart.Chart;

import java.awt.Graphics2D;
import java.awt.Transparency;

import java.awt.geom.Rectangle2D.Double;

import java.awt.geom.Rectangle2D;

import java.awt.image.BufferedImage;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;

import javax.imageio.ImageIO;

import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.batik.svggen.SVGGraphics2DIOException;

import org.apache.log4j.Logger;

import org.jfree.chart.JFreeChart;

/**
 * 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 {

    /**
     * Constant field to define A4 as default page size.
     */
    private static final String  DEFAULT_PAGE_SIZE = "A4";

    /**
     * Constant field to define UTF-8 as default encoding.
     */
    private static final String  DEFAULT_ENCODING  = "UTF-8";

    /**
     * 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 format Format (e.g. png, gif, jpg)
     * @param width Width, the image used to be
     * @param height Height, the image used to be
     *
     * @throws IOException if writing image to OutputStream failed.
     */
    public static void exportImage(
        OutputStream out,
        JFreeChart chart,
        String format,
        int width,
        int height
    )
    throws IOException
    {
        log.info("export chart as png");

        ImageIO.write(
            chart.createBufferedImage(
                width, height, Transparency.BITMASK, null
            ),
            format,
            out
        );
    }


    /**
     * A method to export a <code>JFreeChart</code> histogram as image to an
     * <code>OutputStream</code> with a  given format, width and height.
     *
     * @param out OutputStream
     * @param histograms Array of {@link de.intevation.gnv.chart.Chart} objects
     * @param format A format (e.g. png, gif, jpg)
     * @param width Width the image used to be
     * @param height Height the image used to be
     *
     * @throws IOException if writing image to OutputStream failed.
     */
    public static void exportHistograms(
        OutputStream out,
        Chart[]      histograms,
        String       format,
        int          width,
        int          height)
    throws IOException
    {
        log.info("export histograms");

        int size            = histograms.length;
        BufferedImage image = new BufferedImage(
            width, height*size, BufferedImage.TYPE_INT_RGB);
        Graphics2D g        = image.createGraphics();

        for (int i = 0; i < size; i++) {
            JFreeChart chart = histograms[i].generateChart();
            chart.draw(g, new Rectangle2D.Double(0.0D, i*height, width, height));
        }
        g.finalize();

        ImageIO.write(image, format, out);
    }


    /**
     * A method to export a <code>JFreeChart</code> histogram as SVG to an
     * <code>OutputStream</code>.
     *
     * @param out OutputStream
     * @param histograms Array of {@link de.intevation.gnv.chart.Chart}
     * @param encoding Encoding, defaults to {@link #DEFAULT_ENCODING} if null
     * @param width Width the svg used to be
     * @param height Height the svg used to be
     */
    public static void exportHistogramsAsSVG(
        OutputStream out,
        Chart[]      histograms,
        String       encoding,
        int          width,
        int          height
    ) {
        log.info("export histograms as svg");

        if (encoding == null)
            encoding = DEFAULT_ENCODING;

        org.w3c.dom.Document document = XMLUtils.newDocument();
        SVGGraphics2D        graphics = new SVGGraphics2D(document);

        int size = histograms.length;
        for (int i = 0; i < size; i++) {
            JFreeChart chart = histograms[i].generateChart();
            chart.draw(graphics, new Rectangle2D.Double(
                0.0D, i*height,width,height));
        }
        graphics.finalize();

        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 SVG to an
     * <code>OutputStream</code>.
     *
     * @param out OutputStream
     * @param chart JFreeChart to be exported
     * @param encoding Encoding, defaults to {@link #DEFAULT_ENCODING} if null
     * @param width Width the svg used to be
     * @param height Height the svg used to be
     */
    public static void exportSVG(
        OutputStream out,
        JFreeChart   chart,
        String       encoding,
        int          width,
        int          height
    ) {
        log.info("export chart as svg");

        if (encoding == null)
            encoding = DEFAULT_ENCODING;

        org.w3c.dom.Document document = XMLUtils.newDocument();
        SVGGraphics2D        graphics = new SVGGraphics2D(document);

        chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,width,height));

        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
     * @param pageFormat String to specify a page format, {@link
     * #DEFAULT_PAGE_SIZE} is used if no pageFormat is given
     * @param landscape If this is true, the pdf is delivered in landscape
     * format
     * @param marginLeft Space to left border
     * @param marginRight Space to right border
     * @param marginTop Space to upper border
     * @param marginBottom Space to lower border
     */
    public static void exportPDF(
        OutputStream out,
        JFreeChart   chart,
        String       pageFormat,
        float        marginLeft,
        float        marginRight,
        float        marginTop,
        float        marginBottom,
        CallContext  context
    ) {
        log.info("export chart as pdf.");

        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 chartWidth  = (Integer) context.getContextValue("chart.width");
        int chartHeight = (Integer) context.getContextValue("chart.height");

        boolean landscape = chartWidth > chartHeight ? true : false;

        float width  = 0;
        float height = 0;
        if (landscape) {
            width  = pageHeight;
            height = pageWidth;
        }
        else {
            width  = pageWidth;
            height = pageHeight;
        }

        float spaceX = width  - marginLeft - marginRight;
        if (chartWidth > spaceX) {
            log.warn("Width of the chart is too big for pdf -> resize it now.");
            double ratio = ((double)spaceX) / chartWidth;
            chartWidth  *= ratio;
            chartHeight *= ratio;
            log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
        }

        float spaceY = height - marginTop  - marginBottom;
        if (chartHeight > spaceY) {
            log.warn("Height of the chart is too big for pdf -> resize it now.");
            double ratio = ((double)spaceY) / chartHeight;
            chartWidth  *= ratio;
            chartHeight *= ratio;
            log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
        }

        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,
                chartWidth, chartHeight);

            Rectangle2D area = new Rectangle2D.Double(
                origin[0], origin[1], chartWidth, chartHeight);

            chart.draw(graphics, area);
            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 <code>JFreeChart</code> histograms as PDF to an
     * <code>OutputStream</code>. Each histogram contained in histograms is
     * drawn to an own page in the resulting pdf.
     *
     * @param out OutputStream
     * @param histograms JFreeChart histograms
     * @param pageFormat String to specify a page format, {@link
     * #DEFAULT_PAGE_SIZE} is used if no pageFormat is given
     * @param landscape If this is true, the pdf is delivered in landscape
     * format
     * @param marginLeft Space to left border
     * @param marginRight Space to right border
     * @param marginTop Space to upper border
     * @param marginBottom Space to lower border
     */
    public static void exportHistogramsAsPDF(
        OutputStream out,
        Chart[]      histograms,
        String       pageFormat,
        float        marginLeft,
        float        marginRight,
        float        marginTop,
        float        marginBottom,
        CallContext  context
    ) {
        log.info("export histogram as pdf.");

        if (pageFormat == null)
            pageFormat = DEFAULT_PAGE_SIZE;

        Rectangle page = PageSize.getRectangle(pageFormat);
        float pageWidth  = page.getWidth();
        float pageHeight = page.getHeight();

        // the chart width
        int chartWidth  = (Integer) context.getContextValue("chart.width");
        int chartHeight = (Integer) context.getContextValue("chart.height");

        boolean landscape = chartWidth > chartHeight ? true : false;

        float width  = 0;
        float height = 0;
        if (landscape) {
            width  = pageHeight;
            height = pageWidth;
        }
        else {
            width  = pageWidth;
            height = pageHeight;
        }

        float spaceX = width  - marginLeft - marginRight;
        if (chartWidth > spaceX) {
            log.warn("Histogram width is too big for pdf -> resize it now.");
            double ratio = ((double)spaceX) / chartWidth;
            chartWidth  *= ratio;
            chartHeight *= ratio;
            log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
        }

        float spaceY = height - marginTop  - marginBottom;
        if (chartHeight > spaceY) {
            log.warn("Histogram height is too big for pdf -> resize it now.");
            double ratio = ((double)spaceY) / chartHeight;
            chartWidth  *= ratio;
            chartHeight *= ratio;
            log.debug("Resized chart to " + chartWidth + "x" + chartHeight);
        }

        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.addCreationDate();
            document.open();

            PdfContentByte content  = writer.getDirectContent();

            int size = histograms.length;
            for (int i = 0; i < size; i++) {
                if (i > 0) {
                    document.newPage();
                }

                JFreeChart chart     = histograms[i].generateChart();
                PdfTemplate template = content.createTemplate(width, height);
                Graphics2D  graphics = template.createGraphics(width, height);

                double[] origin = getCenteredAnchor(
                    marginLeft, marginRight, marginBottom, marginTop,
                    width, height,
                    chartWidth, chartHeight);

                Rectangle2D area     = new Rectangle2D.Double(
                    origin[0], origin[1], chartWidth, chartHeight);

                chart.draw(graphics, area);
                graphics.dispose();
                content.addTemplate(template, 0f, 0f);
            }
        }
        catch (DocumentException de) {
            log.error("Error while exporting histogram to pdf.", de);
        }
        finally {
            document.close();
        }
    }


    /**
     * 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 :

http://dive4elements.wald.intevation.org