001: /* ================================================================
002: * Cewolf : Chart enabling Web Objects Framework
003: * ================================================================
004: *
005: * Project Info: http://cewolf.sourceforge.net
006: * Project Lead: Guido Laures (guido@laures.de);
007: *
008: * (C) Copyright 2002, by Guido Laures
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: */
022:
023: package de.laures.cewolf.util;
024:
025: import java.awt.Color;
026: import java.awt.Dimension;
027: import java.awt.Graphics2D;
028: import java.awt.Rectangle;
029: import java.awt.geom.Rectangle2D;
030: import java.awt.image.BufferedImage;
031: import java.io.ByteArrayOutputStream;
032: import java.io.IOException;
033: import java.io.OutputStreamWriter;
034: import java.util.Iterator;
035: import java.util.List;
036:
037: import org.apache.batik.dom.GenericDOMImplementation;
038: import org.apache.batik.svggen.SVGGeneratorContext;
039: import org.apache.batik.svggen.SVGGraphics2D;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042: import org.jfree.chart.ChartRenderingInfo;
043: import org.jfree.chart.ChartUtilities;
044: import org.jfree.chart.JFreeChart;
045: import org.jfree.chart.block.RectangleConstraint;
046: import org.jfree.chart.entity.StandardEntityCollection;
047: import org.jfree.chart.title.LegendTitle;
048: import org.jfree.ui.RectangleEdge;
049: import org.w3c.dom.DOMImplementation;
050: import org.w3c.dom.Document;
051:
052: import com.sun.image.codec.jpeg.JPEGCodec;
053: import com.sun.image.codec.jpeg.JPEGEncodeParam;
054: import com.sun.image.codec.jpeg.JPEGImageEncoder;
055:
056: import de.laures.cewolf.CewolfException;
057: import de.laures.cewolf.ChartImage;
058: import de.laures.cewolf.ChartRenderingException;
059: import de.laures.cewolf.ConfigurationException;
060: import de.laures.cewolf.WebConstants;
061:
062: /**
063: * Renderer for ChartImageDefinitions.
064: *
065: * @author glaures
066: * @author tbardzil
067: * @see de.laures.cewolf.ChartImage
068: */
069: public class Renderer implements WebConstants {
070:
071: private final static Log log = LogFactory.getLog(Renderer.class);
072:
073: /** Creates a new instance of Renderer */
074: private Renderer() {
075: };
076:
077: /**
078: * Renders a chart image
079: *
080: * @param cd the chart to render
081: * @return the rendered image
082: * @throws CewolfException
083: */
084: public static RenderedImage render(ChartImage cd, Object chart)
085: throws CewolfException {
086: log.debug("rendering " + cd);
087: switch (cd.getType()) {
088: case ChartImage.IMG_TYPE_CHART:
089: return renderChart(cd, chart);
090: case ChartImage.IMG_TYPE_LEGEND:
091: return renderLegend(cd, chart);
092: default:
093: throw new ConfigurationException(cd.getType()
094: + " is not a supported image type");
095: }
096: }
097:
098: /**
099: * Renders a chart
100: * @param cd the chart image to be rendered
101: * @return the rendered image
102: * @throws CewolfException
103: */
104: private static RenderedImage renderChart(ChartImage cd, Object chart)
105: throws CewolfException {
106: try {
107: final ByteArrayOutputStream baos = new ByteArrayOutputStream();
108: final ChartRenderingInfo info = new ChartRenderingInfo(
109: new StandardEntityCollection());
110: final String mimeType = cd.getMimeType();
111: if (MIME_PNG.equals(mimeType)) {
112: handlePNG(baos, (JFreeChart) chart, cd.getWidth(), cd
113: .getHeight(), info);
114: } else if (MIME_JPEG.equals(mimeType)) {
115: handleJPEG(baos, (JFreeChart) chart, cd.getWidth(), cd
116: .getHeight(), info);
117: } else if (MIME_SVG.equals(mimeType)) {
118: handleSVG(baos, (JFreeChart) chart, cd.getWidth(), cd
119: .getHeight());
120: } else {
121: throw new RenderingException("Mime type " + mimeType
122: + " is unsupported.");
123: }
124: baos.close();
125: return new RenderedImage(baos.toByteArray(), mimeType, info);
126: } catch (IOException ioe) {
127: log.error(ioe);
128: throw new ChartRenderingException(ioe.getMessage(), ioe);
129: }
130: }
131:
132: /**
133: * Handles rendering a chart as a PNG. Currently this method is synchronized
134: * because of concurrency issues with JFreeChart.
135: *
136: * @param baos
137: * @param chart
138: * @param width
139: * @param height
140: * @param info
141: * @throws IOException
142: */
143: private static synchronized void handlePNG(
144: ByteArrayOutputStream baos, JFreeChart chart, int width,
145: int height, ChartRenderingInfo info) throws IOException {
146: ChartUtilities
147: .writeChartAsPNG(baos, chart, width, height, info);
148: }
149:
150: /**
151: * Handles rendering a chart as a JPEG. Currently this method is synchronized
152: * because of concurrency issues with JFreeChart.
153: *
154: * @param baos
155: * @param chart
156: * @param width
157: * @param height
158: * @param info
159: * @throws IOException
160: */
161: private static synchronized void handleJPEG(
162: ByteArrayOutputStream baos, JFreeChart chart, int width,
163: int height, ChartRenderingInfo info) throws IOException {
164: ChartUtilities.writeChartAsJPEG(baos, chart, width, height,
165: info);
166: }
167:
168: /**
169: * Handles rendering a chart as a SVG. Currently this method is synchronized
170: * because of concurrency issues with JFreeChart.
171: *
172: * @param baos
173: * @param chart
174: * @param width
175: * @param height
176: * @throws IOException
177: */
178: private static synchronized void handleSVG(
179: ByteArrayOutputStream baos, JFreeChart chart, int width,
180: int height) throws IOException {
181: OutputStreamWriter writer = new OutputStreamWriter(baos,
182: "UTF-8");
183: DOMImplementation domImpl = GenericDOMImplementation
184: .getDOMImplementation();
185: Document document = domImpl.createDocument("cewolf-svg", "svg",
186: null);
187: SVGGeneratorContext ctx = SVGGeneratorContext
188: .createDefault(document);
189: ctx
190: .setComment("Generated by Cewolf using JFreeChart and Apache Batik SVG Generator");
191: SVGGraphics2D svgGenerator = new SVGGraphics2D(ctx, false);
192: svgGenerator.setSVGCanvasSize(new Dimension(width, height));
193: chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width,
194: height), null);
195: svgGenerator.stream(writer, false);
196: writer.close();
197: }
198:
199: //gets first legend in the list
200: public static LegendTitle getLegend(JFreeChart chart) {
201: //i need to find the legend now.
202: LegendTitle legend = null;
203: List subTitles = chart.getSubtitles();
204: Iterator iter = subTitles.iterator();
205: while (iter.hasNext()) {
206: Object o = iter.next();
207: if (o instanceof LegendTitle) {
208: legend = (LegendTitle) o;
209: break;
210: }
211: }
212: return legend;
213: }
214:
215: //removes first legend in the list
216: public static void removeLegend(JFreeChart chart) {
217: List subTitles = chart.getSubtitles();
218: Iterator iter = subTitles.iterator();
219: while (iter.hasNext()) {
220: Object o = iter.next();
221: if (o instanceof LegendTitle) {
222: iter.remove();
223: break;
224: }
225: }
226: }
227:
228: /**
229: * Renders a legend
230: * @param cd the chart iamge to be rendred
231: * @return the rendered image
232: * @throws CewolfException
233: */
234: private static RenderedImage renderLegend(ChartImage cd, Object c)
235: throws CewolfException {
236: try {
237: JFreeChart chart = (JFreeChart) c;
238: final int width = cd.getWidth();
239: final int height = cd.getHeight();
240: LegendTitle legend = getLegend(chart);
241: boolean haslegend = true;
242:
243: // with JFreeChart v0.9.20, the only way to get a valid legend,
244: // is either to retrieve it from the chart or to assign a new
245: // one to the chart. In the case where the chart has no legend,
246: // a new one must be assigned, but just for rendering. After, we
247: // have to reset the legend to null in the chart.
248: if (null == legend) {
249: haslegend = false;
250: legend = new LegendTitle(chart.getPlot());
251: }
252: legend.setPosition(RectangleEdge.BOTTOM);
253: BufferedImage bimage = ImageHelper.createImage(width,
254: height);
255: Graphics2D g = bimage.createGraphics();
256: g.setColor(Color.white);
257: g.fillRect(0, 0, width, height);
258: legend.arrange(g, new RectangleConstraint(width, height));
259: legend.draw(g, new Rectangle(width, height));
260: ByteArrayOutputStream out = new ByteArrayOutputStream();
261: JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
262: JPEGEncodeParam param = encoder
263: .getDefaultJPEGEncodeParam(bimage);
264: param.setQuality(1.0f, true);
265: encoder.encode(bimage, param);
266: out.close();
267:
268: // if the chart had no legend, reset it to null in order to give back the
269: // chart in the state we received it.
270: if (!haslegend) {
271: removeLegend(chart);
272: }
273:
274: return new RenderedImage(out.toByteArray(), "image/jpeg",
275: new ChartRenderingInfo(
276: new StandardEntityCollection()));
277: } catch (IOException ioex) {
278: log.error(ioex);
279: throw new ChartRenderingException(ioex.getMessage(), ioex);
280: }
281: }
282:
283: }
|