franta-hg@1: /* ================================================================ franta-hg@1: * Cewolf : Chart enabling Web Objects Framework franta-hg@1: * ================================================================ franta-hg@1: * franta-hg@1: * Project Info: http://cewolf.sourceforge.net franta-hg@1: * Project Lead: Guido Laures (guido@laures.de); franta-hg@1: * franta-hg@1: * (C) Copyright 2002, by Guido Laures franta-hg@1: * franta-hg@1: * This library is free software; you can redistribute it and/or modify it under the terms franta-hg@1: * of the GNU Lesser General Public License as published by the Free Software Foundation; franta-hg@1: * either version 2.1 of the License, or (at your option) any later version. franta-hg@1: * franta-hg@1: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; franta-hg@1: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. franta-hg@1: * See the GNU Lesser General Public License for more details. franta-hg@1: * franta-hg@1: * You should have received a copy of the GNU Lesser General Public License along with this franta-hg@1: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, franta-hg@1: * Boston, MA 02111-1307, USA. franta-hg@1: */ franta-hg@1: franta-hg@1: package de.laures.cewolf.util; franta-hg@1: franta-hg@1: import java.awt.Color; franta-hg@1: import java.awt.Dimension; franta-hg@1: import java.awt.Graphics2D; franta-hg@1: import java.awt.Rectangle; franta-hg@1: import java.awt.geom.Rectangle2D; franta-hg@1: import java.awt.image.BufferedImage; franta-hg@1: import java.io.ByteArrayOutputStream; franta-hg@1: import java.io.IOException; franta-hg@1: import java.io.OutputStreamWriter; franta-hg@1: import java.util.Iterator; franta-hg@1: import java.util.List; franta-hg@1: franta-hg@1: import org.apache.batik.dom.GenericDOMImplementation; franta-hg@1: import org.apache.batik.svggen.SVGGeneratorContext; franta-hg@1: import org.apache.batik.svggen.SVGGraphics2D; franta-hg@1: import org.apache.commons.logging.Log; franta-hg@1: import org.apache.commons.logging.LogFactory; franta-hg@1: import org.jfree.chart.ChartRenderingInfo; franta-hg@1: import org.jfree.chart.ChartUtilities; franta-hg@1: import org.jfree.chart.JFreeChart; franta-hg@1: import org.jfree.chart.block.RectangleConstraint; franta-hg@1: import org.jfree.chart.entity.StandardEntityCollection; franta-hg@1: import org.jfree.chart.title.LegendTitle; franta-hg@1: import org.jfree.ui.RectangleEdge; franta-hg@1: import org.w3c.dom.DOMImplementation; franta-hg@1: import org.w3c.dom.Document; franta-hg@1: franta-hg@1: import com.sun.image.codec.jpeg.JPEGCodec; franta-hg@1: import com.sun.image.codec.jpeg.JPEGEncodeParam; franta-hg@1: import com.sun.image.codec.jpeg.JPEGImageEncoder; franta-hg@1: franta-hg@1: import de.laures.cewolf.CewolfException; franta-hg@1: import de.laures.cewolf.ChartImage; franta-hg@1: import de.laures.cewolf.ChartRenderingException; franta-hg@1: import de.laures.cewolf.ConfigurationException; franta-hg@1: import de.laures.cewolf.WebConstants; franta-hg@1: franta-hg@1: /** franta-hg@1: * Renderer for ChartImageDefinitions. franta-hg@1: * franta-hg@1: * @author glaures franta-hg@1: * @author tbardzil franta-hg@1: * @see de.laures.cewolf.ChartImage franta-hg@1: */ franta-hg@1: public class Renderer implements WebConstants { franta-hg@1: franta-hg@1: private final static Log log = LogFactory.getLog(Renderer.class); franta-hg@1: franta-hg@1: /** Creates a new instance of Renderer */ franta-hg@1: private Renderer() { franta-hg@1: }; franta-hg@1: franta-hg@1: /** franta-hg@1: * Renders a chart image franta-hg@1: * franta-hg@1: * @param cd the chart to render franta-hg@1: * @return the rendered image franta-hg@1: * @throws CewolfException franta-hg@1: */ franta-hg@1: public static RenderedImage render(ChartImage cd, Object chart) throws CewolfException { franta-hg@1: log.debug("rendering " + cd); franta-hg@1: switch (cd.getType()) { franta-hg@1: case ChartImage.IMG_TYPE_CHART : franta-hg@1: return renderChart(cd, chart); franta-hg@1: case ChartImage.IMG_TYPE_LEGEND : franta-hg@1: return renderLegend(cd, chart); franta-hg@1: default : franta-hg@1: throw new ConfigurationException(cd.getType() + " is not a supported image type"); franta-hg@1: } franta-hg@1: } franta-hg@1: franta-hg@1: /** franta-hg@1: * Renders a chart franta-hg@1: * @param cd the chart image to be rendered franta-hg@1: * @return the rendered image franta-hg@1: * @throws CewolfException franta-hg@1: */ franta-hg@1: private static RenderedImage renderChart(ChartImage cd, Object chart) throws CewolfException { franta-hg@1: try { franta-hg@1: final ByteArrayOutputStream baos = new ByteArrayOutputStream(); franta-hg@1: final ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection()); franta-hg@1: final String mimeType = cd.getMimeType(); franta-hg@1: if (MIME_PNG.equals(mimeType)) { franta-hg@1: handlePNG(baos, (JFreeChart)chart, cd.getWidth(), cd.getHeight(), info); franta-hg@1: } else if (MIME_JPEG.equals(mimeType)) { franta-hg@1: handleJPEG(baos, (JFreeChart)chart, cd.getWidth(), cd.getHeight(), info); franta-hg@1: } else if (MIME_SVG.equals(mimeType)) { franta-hg@1: handleSVG(baos, (JFreeChart)chart, cd.getWidth(), cd.getHeight()); franta-hg@1: } else { franta-hg@1: throw new RenderingException("Mime type " + mimeType + " is unsupported."); franta-hg@1: } franta-hg@1: baos.close(); franta-hg@1: return new RenderedImage(baos.toByteArray(), mimeType, info); franta-hg@1: } catch (IOException ioe) { franta-hg@1: log.error(ioe); franta-hg@1: throw new ChartRenderingException(ioe.getMessage(),ioe); franta-hg@1: } franta-hg@1: } franta-hg@1: franta-hg@1: /** franta-hg@1: * Handles rendering a chart as a PNG. Currently this method is synchronized franta-hg@1: * because of concurrency issues with JFreeChart. franta-hg@1: * franta-hg@1: * @param baos franta-hg@1: * @param chart franta-hg@1: * @param width franta-hg@1: * @param height franta-hg@1: * @param info franta-hg@1: * @throws IOException franta-hg@1: */ franta-hg@1: private static synchronized void handlePNG( franta-hg@1: ByteArrayOutputStream baos, franta-hg@1: JFreeChart chart, franta-hg@1: int width, franta-hg@1: int height, franta-hg@1: ChartRenderingInfo info) franta-hg@1: throws IOException { franta-hg@1: ChartUtilities.writeChartAsPNG(baos, chart, width, height, info); franta-hg@1: } franta-hg@1: franta-hg@1: /** franta-hg@1: * Handles rendering a chart as a JPEG. Currently this method is synchronized franta-hg@1: * because of concurrency issues with JFreeChart. franta-hg@1: * franta-hg@1: * @param baos franta-hg@1: * @param chart franta-hg@1: * @param width franta-hg@1: * @param height franta-hg@1: * @param info franta-hg@1: * @throws IOException franta-hg@1: */ franta-hg@1: private static synchronized void handleJPEG( franta-hg@1: ByteArrayOutputStream baos, franta-hg@1: JFreeChart chart, franta-hg@1: int width, franta-hg@1: int height, franta-hg@1: ChartRenderingInfo info) franta-hg@1: throws IOException { franta-hg@1: ChartUtilities.writeChartAsJPEG(baos, chart, width, height, info); franta-hg@1: } franta-hg@1: franta-hg@1: /** franta-hg@1: * Handles rendering a chart as a SVG. Currently this method is synchronized franta-hg@1: * because of concurrency issues with JFreeChart. franta-hg@1: * franta-hg@1: * @param baos franta-hg@1: * @param chart franta-hg@1: * @param width franta-hg@1: * @param height franta-hg@1: * @throws IOException franta-hg@1: */ franta-hg@1: private static synchronized void handleSVG(ByteArrayOutputStream baos, JFreeChart chart, int width, int height) franta-hg@1: throws IOException { franta-hg@1: OutputStreamWriter writer = new OutputStreamWriter(baos, "UTF-8"); franta-hg@1: DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); franta-hg@1: Document document = domImpl.createDocument("cewolf-svg", "svg", null); franta-hg@1: SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document); franta-hg@1: ctx.setComment("Generated by Cewolf using JFreeChart and Apache Batik SVG Generator"); franta-hg@1: SVGGraphics2D svgGenerator = new SVGGraphics2D(ctx, false); franta-hg@1: svgGenerator.setSVGCanvasSize(new Dimension(width, height)); franta-hg@1: chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width, height), null); franta-hg@1: svgGenerator.stream(writer, false); franta-hg@1: writer.close(); franta-hg@1: } franta-hg@1: franta-hg@1: //gets first legend in the list franta-hg@1: public static LegendTitle getLegend(JFreeChart chart) franta-hg@1: { franta-hg@1: //i need to find the legend now. franta-hg@1: LegendTitle legend = null; franta-hg@1: List subTitles = chart.getSubtitles(); franta-hg@1: Iterator iter = subTitles.iterator(); franta-hg@1: while (iter.hasNext()) franta-hg@1: { franta-hg@1: Object o = iter.next(); franta-hg@1: if (o instanceof LegendTitle) franta-hg@1: { franta-hg@1: legend = (LegendTitle) o; franta-hg@1: break; franta-hg@1: } franta-hg@1: } franta-hg@1: return legend; franta-hg@1: } franta-hg@1: franta-hg@1: //removes first legend in the list franta-hg@1: public static void removeLegend(JFreeChart chart) franta-hg@1: { franta-hg@1: List subTitles = chart.getSubtitles(); franta-hg@1: Iterator iter = subTitles.iterator(); franta-hg@1: while (iter.hasNext()) franta-hg@1: { franta-hg@1: Object o = iter.next(); franta-hg@1: if (o instanceof LegendTitle) franta-hg@1: { franta-hg@1: iter.remove(); franta-hg@1: break; franta-hg@1: } franta-hg@1: } franta-hg@1: } franta-hg@1: franta-hg@1: /** franta-hg@1: * Renders a legend franta-hg@1: * @param cd the chart iamge to be rendred franta-hg@1: * @return the rendered image franta-hg@1: * @throws CewolfException franta-hg@1: */ franta-hg@1: private static RenderedImage renderLegend(ChartImage cd, Object c) throws CewolfException { franta-hg@1: try { franta-hg@1: JFreeChart chart = (JFreeChart) c; franta-hg@1: final int width = cd.getWidth(); franta-hg@1: final int height = cd.getHeight(); franta-hg@1: LegendTitle legend = getLegend(chart); franta-hg@1: boolean haslegend = true; franta-hg@1: franta-hg@1: // with JFreeChart v0.9.20, the only way to get a valid legend, franta-hg@1: // is either to retrieve it from the chart or to assign a new franta-hg@1: // one to the chart. In the case where the chart has no legend, franta-hg@1: // a new one must be assigned, but just for rendering. After, we franta-hg@1: // have to reset the legend to null in the chart. franta-hg@1: if (null == legend) { franta-hg@1: haslegend = false; franta-hg@1: legend = new LegendTitle(chart.getPlot()); franta-hg@1: } franta-hg@1: legend.setPosition(RectangleEdge.BOTTOM); franta-hg@1: BufferedImage bimage = ImageHelper.createImage(width, height); franta-hg@1: Graphics2D g = bimage.createGraphics(); franta-hg@1: g.setColor(Color.white); franta-hg@1: g.fillRect(0, 0, width, height); franta-hg@1: legend.arrange(g,new RectangleConstraint(width,height)); franta-hg@1: legend.draw(g, new Rectangle(width, height)); franta-hg@1: ByteArrayOutputStream out = new ByteArrayOutputStream(); franta-hg@1: JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); franta-hg@1: JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage); franta-hg@1: param.setQuality(1.0f, true); franta-hg@1: encoder.encode(bimage, param); franta-hg@1: out.close(); franta-hg@1: franta-hg@1: // if the chart had no legend, reset it to null in order to give back the franta-hg@1: // chart in the state we received it. franta-hg@1: if (!haslegend) { franta-hg@1: removeLegend(chart); franta-hg@1: } franta-hg@1: franta-hg@1: return new RenderedImage( franta-hg@1: out.toByteArray(), franta-hg@1: "image/jpeg", franta-hg@1: new ChartRenderingInfo(new StandardEntityCollection())); franta-hg@1: } catch (IOException ioex) { franta-hg@1: log.error(ioex); franta-hg@1: throw new ChartRenderingException(ioex.getMessage(), ioex); franta-hg@1: } franta-hg@1: } franta-hg@1: franta-hg@1: }