Mercurial > dive4elements > river
comparison 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 |
comparison
equal
deleted
inserted
replaced
5837:d9901a08d0a6 | 5838:5aa05a7a34b7 |
---|---|
1 /* | |
2 * Copyright (c) 2011 by Intevation GmbH | |
3 * | |
4 * This program is free software under the LGPL (>=v2.1) | |
5 * Read the file LGPL.txt coming with the software for details | |
6 * or visit http://www.gnu.org/licenses/ if it does not exist. | |
7 */ | |
8 package org.dive4elements.river.exports; | |
9 | |
10 import com.lowagie.text.Document; | |
11 import com.lowagie.text.DocumentException; | |
12 import com.lowagie.text.PageSize; | |
13 import com.lowagie.text.Rectangle; | |
14 | |
15 import com.lowagie.text.pdf.PdfContentByte; | |
16 import com.lowagie.text.pdf.PdfTemplate; | |
17 import com.lowagie.text.pdf.PdfWriter; | |
18 | |
19 import java.awt.Graphics2D; | |
20 import java.awt.Transparency; | |
21 | |
22 import java.awt.geom.Rectangle2D.Double; | |
23 | |
24 import java.awt.geom.Rectangle2D; | |
25 | |
26 import java.io.IOException; | |
27 import java.io.OutputStream; | |
28 import java.io.OutputStreamWriter; | |
29 import java.io.UnsupportedEncodingException; | |
30 import org.jfree.chart.ChartRenderingInfo; | |
31 | |
32 import javax.imageio.ImageIO; | |
33 | |
34 import au.com.bytecode.opencsv.CSVWriter; | |
35 | |
36 import org.apache.batik.svggen.SVGGraphics2D; | |
37 import org.apache.batik.svggen.SVGGraphics2DIOException; | |
38 | |
39 import org.apache.log4j.Logger; | |
40 | |
41 import org.jfree.chart.JFreeChart; | |
42 import org.jfree.chart.plot.XYPlot; | |
43 import org.jfree.data.xy.XYDataset; | |
44 | |
45 import org.dive4elements.artifacts.CallContext; | |
46 | |
47 import org.dive4elements.artifacts.common.utils.XMLUtils; | |
48 | |
49 | |
50 /** | |
51 * This class is a helper class which supports some methods to export charts | |
52 * into specific formats. | |
53 * | |
54 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
55 */ | |
56 public class ChartExportHelper { | |
57 | |
58 public static final String FORMAT_PNG = "png"; | |
59 | |
60 public static final String FORMAT_PDF = "pdf"; | |
61 | |
62 public static final String FORMAT_SVG = "svg"; | |
63 | |
64 public static final String FORMAT_CSV = "csv"; | |
65 | |
66 /** | |
67 * Constant field to define A4 as default page size. | |
68 */ | |
69 public static final String DEFAULT_PAGE_SIZE = "A4"; | |
70 | |
71 /** | |
72 * Constant field to define UTF-8 as default encoding. | |
73 */ | |
74 public static final String DEFAULT_ENCODING = "UTF-8"; | |
75 | |
76 /** The default separator for the CSV export. */ | |
77 public static final char DEFAULT_CSV_SEPARATOR = ','; | |
78 | |
79 | |
80 /** | |
81 * Logger used for logging with log4j. | |
82 */ | |
83 private static Logger log = Logger.getLogger(ChartExportHelper.class); | |
84 | |
85 | |
86 /** | |
87 * A method to export a <code>JFreeChart</code> as image to an | |
88 * <code>OutputStream</code> with a given format, width and height. | |
89 * | |
90 * @param out OutputStream | |
91 * @param chart JFreeChart object to be exported. | |
92 * @param cc context, in which e.g. size is stored. | |
93 * | |
94 * @throws IOException if writing image to OutputStream failed. | |
95 */ | |
96 public static void exportImage( | |
97 OutputStream out, | |
98 JFreeChart chart, | |
99 CallContext cc | |
100 ) | |
101 throws IOException | |
102 { | |
103 log.info("export chart as png"); | |
104 | |
105 ChartRenderingInfo info = new ChartRenderingInfo(); | |
106 | |
107 String format = (String) cc.getContextValue("chart.image.format"); | |
108 | |
109 int[] size = getSize(cc); | |
110 | |
111 ImageIO.write( | |
112 chart.createBufferedImage( | |
113 size[0], size[1], Transparency.BITMASK, info | |
114 ), | |
115 format, | |
116 out | |
117 ); | |
118 } | |
119 | |
120 | |
121 /** | |
122 * A method to export a <code>JFreeChart</code> as SVG to an | |
123 * <code>OutputStream</code>. | |
124 * | |
125 * @param out OutputStream | |
126 * @param chart JFreeChart to be exported | |
127 * @param context The CallContext object that contains extra chart | |
128 * parameters. | |
129 */ | |
130 public static void exportSVG( | |
131 OutputStream out, | |
132 JFreeChart chart, | |
133 CallContext context | |
134 ) { | |
135 String encoding = (String) context.getContextValue("chart.encoding"); | |
136 | |
137 log.info("export chart as svg"); | |
138 | |
139 if (encoding == null) | |
140 encoding = DEFAULT_ENCODING; | |
141 | |
142 org.w3c.dom.Document document = XMLUtils.newDocument(); | |
143 SVGGraphics2D graphics = new SVGGraphics2D(document); | |
144 | |
145 int[] size = getSize(context); | |
146 | |
147 ChartRenderingInfo info = new ChartRenderingInfo(); | |
148 | |
149 chart.draw(graphics, new Rectangle2D.Double(0.0D, 0.0D,size[0],size[1]), info); | |
150 | |
151 try { | |
152 graphics.stream(new OutputStreamWriter(out, encoding)); | |
153 } | |
154 catch (SVGGraphics2DIOException svge) { | |
155 log.error("Error while writing svg export to output stream.", svge); | |
156 } | |
157 catch (UnsupportedEncodingException uee) { | |
158 log.error("Unsupported encoding: " + encoding, uee); | |
159 } | |
160 } | |
161 | |
162 | |
163 /** | |
164 * A method to export a <code>JFreeChart</code> as PDF to an | |
165 * <code>OutputStream</code>. | |
166 * | |
167 * @param out OutputStream | |
168 * @param chart JFreeChart | |
169 */ | |
170 public static void exportPDF( | |
171 OutputStream out, | |
172 JFreeChart chart, | |
173 CallContext cc | |
174 ) { | |
175 log.info("export chart as pdf."); | |
176 | |
177 String pageFormat = (String) cc.getContextValue("chart.page.format"); | |
178 | |
179 if (pageFormat == null) | |
180 pageFormat = DEFAULT_PAGE_SIZE; | |
181 | |
182 // Max size of the chart. | |
183 Rectangle page = PageSize.getRectangle(pageFormat); | |
184 float pageWidth = page.getWidth(); | |
185 float pageHeight = page.getHeight(); | |
186 | |
187 // The chart width. | |
188 int[] size = getSize(cc); | |
189 | |
190 boolean landscape = size[0] > size[1]; | |
191 | |
192 float width = 0; | |
193 float height = 0; | |
194 if (landscape) { | |
195 width = pageHeight; | |
196 height = pageWidth; | |
197 } | |
198 else { | |
199 width = pageWidth; | |
200 height = pageHeight; | |
201 } | |
202 | |
203 float marginLeft = (Float) cc.getContextValue( | |
204 "chart.marginLeft"); | |
205 | |
206 float marginRight = (Float) cc.getContextValue( | |
207 "chart.marginRight"); | |
208 | |
209 float marginTop = (Float) cc.getContextValue( | |
210 "chart.marginTop"); | |
211 | |
212 float marginBottom = (Float) cc.getContextValue( | |
213 "chart.marginBottom"); | |
214 | |
215 float spaceX = width - marginLeft - marginRight; | |
216 if (size[0] > spaceX) { | |
217 log.warn("Width of the chart is too big for pdf -> resize it now."); | |
218 double ratio = ((double)spaceX) / size[0]; | |
219 size[0] *= ratio; | |
220 size[1] *= ratio; | |
221 log.debug("Resized chart to " + size[0] + "x" + size[1]); | |
222 } | |
223 | |
224 float spaceY = height - marginTop - marginBottom; | |
225 if (size[1] > spaceY) { | |
226 log.warn("Height of the chart is too big for pdf -> resize it now."); | |
227 double ratio = ((double)spaceY) / size[1]; | |
228 size[0] *= ratio; | |
229 size[1] *= ratio; | |
230 log.debug("Resized chart to " + size[0] + "x" + size[1]); | |
231 } | |
232 | |
233 Document document = null; | |
234 if (landscape) { | |
235 document = new Document(page.rotate()); | |
236 log.debug("Create landscape pdf."); | |
237 } | |
238 else | |
239 document = new Document(page); | |
240 | |
241 try { | |
242 PdfWriter writer = PdfWriter.getInstance(document, out); | |
243 | |
244 document.addSubject(chart.getTitle().getText()); | |
245 document.addCreationDate(); | |
246 document.open(); | |
247 | |
248 PdfContentByte content = writer.getDirectContent(); | |
249 | |
250 PdfTemplate template = content.createTemplate(width, height); | |
251 Graphics2D graphics = template.createGraphics(width, height); | |
252 | |
253 double[] origin = getCenteredAnchor( | |
254 marginLeft, marginRight, marginBottom, marginTop, | |
255 width, height, | |
256 size[0], size[1]); | |
257 | |
258 Rectangle2D area = new Rectangle2D.Double( | |
259 origin[0], origin[1], size[0], size[1]); | |
260 | |
261 ChartRenderingInfo info = new ChartRenderingInfo(); | |
262 | |
263 chart.draw(graphics, area, info); | |
264 graphics.dispose(); | |
265 content.addTemplate(template, 0f, 0f); | |
266 } | |
267 catch (DocumentException de) { | |
268 log.error("Error while exporting chart to pdf.", de); | |
269 } | |
270 finally { | |
271 document.close(); | |
272 } | |
273 } | |
274 | |
275 | |
276 /** | |
277 * A method to export a CSV file to an | |
278 * <code>OutputStream</code>. | |
279 * | |
280 * @param out OutputStream | |
281 * @param chart JFreeChart containing the data. | |
282 * @param context The CallContext object that contains extra parameters. | |
283 */ | |
284 public static void exportCSV( | |
285 OutputStream out, | |
286 JFreeChart chart, | |
287 CallContext context) | |
288 { | |
289 log.debug("export chart as CSV"); | |
290 CSVWriter writer = null; | |
291 try { | |
292 writer = new CSVWriter( | |
293 new OutputStreamWriter( | |
294 out, | |
295 DEFAULT_ENCODING), | |
296 DEFAULT_CSV_SEPARATOR); | |
297 } | |
298 catch(UnsupportedEncodingException uee) { | |
299 log.warn("Wrong encoding for CSV export."); | |
300 return; | |
301 } | |
302 XYPlot plot = chart.getXYPlot(); | |
303 int count = plot.getDatasetCount(); | |
304 for (int i = 0; i < count; i++) { | |
305 XYDataset data = plot.getDataset(i); | |
306 int scount = data.getSeriesCount(); | |
307 for (int j = 0; j < scount; j++) { | |
308 Comparable seriesKey = data.getSeriesKey(j); | |
309 log.debug("series key: " + seriesKey.toString()); | |
310 writeCSVHeader(writer, seriesKey.toString()); | |
311 writeCSVData(writer, data); | |
312 } | |
313 } | |
314 try { | |
315 writer.close(); | |
316 } | |
317 catch(IOException ioe) { | |
318 log.error("Writing CSV export failed!"); | |
319 } | |
320 } | |
321 | |
322 | |
323 protected static void writeCSVHeader(CSVWriter writer, String key) { | |
324 writer.writeNext(new String[] {"#"}); | |
325 writer.writeNext(new String[] {"# " + key}); | |
326 writer.writeNext(new String[] {"#"}); | |
327 writer.writeNext(new String[] {"X", "Y"}); | |
328 } | |
329 | |
330 | |
331 protected static void writeCSVData(CSVWriter writer, XYDataset data) { | |
332 int series = data.getSeriesCount(); | |
333 for (int i = 0; i < series; i++) { | |
334 int items = data.getItemCount(i); | |
335 for (int j = 0; j < items; j++) { | |
336 log.debug("write data: " + data.getX(i, j) + ", " + data.getY(i, j)); | |
337 writer.writeNext(new String[] { | |
338 data.getX(i, j).toString(), | |
339 data.getY(i, j).toString()}); | |
340 } | |
341 } | |
342 } | |
343 | |
344 | |
345 public static int[] getSize(CallContext cc) { | |
346 int[] size = new int[2]; | |
347 | |
348 size[0] = (Integer) cc.getContextValue("chart.width"); | |
349 size[1] = (Integer) cc.getContextValue("chart.height"); | |
350 | |
351 return size; | |
352 } | |
353 | |
354 | |
355 /** | |
356 * This method returns the anchor of the chart so that the chart is centered | |
357 * according to the given parameters. | |
358 * | |
359 * @param mLeft Left margin | |
360 * @param mRight Right margin | |
361 * @param mBottom Bottom margin | |
362 * @param mTop Top margin | |
363 * @param width The complete width of the drawing area. | |
364 * @param height The complete height of the drawing area. | |
365 * @param chartWidth The width of the chart. | |
366 * @param chartHeight The height of the chart. | |
367 * | |
368 * @return an array that contains the anchor for a chart with the given | |
369 * parameters. The first value is the x point, the second value is the y | |
370 * point. | |
371 */ | |
372 public static double[] getCenteredAnchor( | |
373 double mLeft, double mRight, double mBottom, double mTop, | |
374 double width, double height, | |
375 double chartWidth, double chartHeight | |
376 ) { | |
377 if (log.isDebugEnabled()) { | |
378 log.debug("Calculate centered origin..."); | |
379 log.debug("-> PDF width : " + width); | |
380 log.debug("-> PDF height : " + height); | |
381 log.debug("-> Chart width : " + chartWidth); | |
382 log.debug("-> Chart height : " + chartHeight); | |
383 log.debug("-> margin left : " + mLeft); | |
384 log.debug("-> margin right : " + mRight); | |
385 log.debug("-> margin bottom: " + mBottom); | |
386 log.debug("-> margin top : " + mTop); | |
387 } | |
388 | |
389 double[] origin = new double[2]; | |
390 | |
391 double centerX = width / 2; | |
392 double centerY = height / 2; | |
393 | |
394 origin[0] = centerX - chartWidth / 2; | |
395 origin[1] = centerY - chartHeight / 2; | |
396 | |
397 origin[0] = origin[0] >= mLeft ? origin[0] : mLeft; | |
398 origin[1] = origin[1] >= mTop ? origin[1] : mTop; | |
399 | |
400 if (log.isDebugEnabled()) { | |
401 log.debug("==> centered left origin: " + origin[0]); | |
402 log.debug("==> centered top origin: " + origin[1]); | |
403 } | |
404 | |
405 return origin; | |
406 } | |
407 } | |
408 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : |