001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2022, by David Gilbert and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ---------------- 028 * ExportUtils.java 029 * ---------------- 030 * (C) Copyright 2014-2022 by David Gilbert and Contributors. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.chart.util; 038 039import java.awt.Graphics2D; 040import java.awt.Rectangle; 041import java.awt.geom.Rectangle2D; 042import java.awt.image.BufferedImage; 043import java.io.BufferedOutputStream; 044import java.io.File; 045import java.io.FileNotFoundException; 046import java.io.FileOutputStream; 047import java.io.IOException; 048import java.io.OutputStream; 049import java.lang.reflect.Constructor; 050import java.lang.reflect.InvocationTargetException; 051import java.lang.reflect.Method; 052import javax.imageio.ImageIO; 053import org.jfree.chart.Drawable; 054import org.jfree.chart.internal.Args; 055 056/** 057 * Utility functions for exporting charts to SVG and PDF format. 058 */ 059public class ExportUtils { 060 061 /** 062 * Returns {@code true} if JFreeSVG is on the classpath, and 063 * {@code false} otherwise. The JFreeSVG library can be found at 064 * http://www.jfree.org/jfreesvg/ 065 * 066 * @return A boolean. 067 */ 068 public static boolean isJFreeSVGAvailable() { 069 Class<?> svgClass = null; 070 try { 071 svgClass = Class.forName("org.jfree.svg.SVGGraphics2D"); 072 } catch (ClassNotFoundException e) { 073 // see if there is maybe an older version of JFreeSVG (different package name) 074 try { 075 svgClass = Class.forName("org.jfree.graphics2d.svg.SVGGraphics2D"); 076 } catch (ClassNotFoundException e2) { 077 // svgClass will be null so the function will return false 078 } 079 } 080 return (svgClass != null); 081 } 082 083 /** 084 * Returns {@code true} if OrsonPDF is on the classpath, and 085 * {@code false} otherwise. The OrsonPDF library can be found at 086 * http://www.object-refinery.com/orsonpdf/ 087 * 088 * @return A boolean. 089 */ 090 public static boolean isOrsonPDFAvailable() { 091 Class<?> pdfDocumentClass = null; 092 try { 093 pdfDocumentClass = Class.forName("com.orsonpdf.PDFDocument"); 094 } catch (ClassNotFoundException e) { 095 // pdfDocumentClass will be null so the function will return false 096 } 097 return (pdfDocumentClass != null); 098 } 099 100 /** 101 * Writes the current content to the specified file in SVG format. This 102 * will only work when the JFreeSVG library is found on the classpath. 103 * Reflection is used to ensure there is no compile-time dependency on 104 * JFreeSVG. 105 * 106 * @param drawable the drawable ({@code null} not permitted). 107 * @param w the chart width. 108 * @param h the chart height. 109 * @param file the output file ({@code null} not permitted). 110 */ 111 public static void writeAsSVG(Drawable drawable, int w, int h, File file) { 112 if (!ExportUtils.isJFreeSVGAvailable()) { 113 throw new IllegalStateException( 114 "JFreeSVG is not present on the classpath."); 115 } 116 Args.nullNotPermitted(drawable, "drawable"); 117 Args.nullNotPermitted(file, "file"); 118 try { 119 Class<?> svg2Class = Class.forName( 120 "org.jfree.graphics2d.svg.SVGGraphics2D"); 121 Constructor<?> c1 = svg2Class.getConstructor(int.class, int.class); 122 Graphics2D svg2 = (Graphics2D) c1.newInstance(w, h); 123 Rectangle2D drawArea = new Rectangle2D.Double(0, 0, w, h); 124 drawable.draw(svg2, drawArea); 125 Class<?> svgUtilsClass = Class.forName( 126 "org.jfree.graphics2d.svg.SVGUtils"); 127 Method m1 = svg2Class.getMethod("getSVGElement", (Class[]) null); 128 String element = (String) m1.invoke(svg2, (Object[]) null); 129 Method m2 = svgUtilsClass.getMethod("writeToSVG", File.class, 130 String.class); 131 m2.invoke(svgUtilsClass, file, element); 132 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | 133 NoSuchMethodException | SecurityException | IllegalArgumentException | 134 InvocationTargetException ex) { 135 throw new RuntimeException(ex); 136 } 137 } 138 139 /** 140 * Writes a {@link Drawable} to the specified file in PDF format. This 141 * will only work when the OrsonPDF library is found on the classpath. 142 * Reflection is used to ensure there is no compile-time dependency on 143 * OrsonPDF. 144 * 145 * @param drawable the drawable ({@code null} not permitted). 146 * @param w the chart width. 147 * @param h the chart height. 148 * @param file the output file ({@code null} not permitted). 149 */ 150 public static final void writeAsPDF(Drawable drawable, 151 int w, int h, File file) { 152 if (!ExportUtils.isOrsonPDFAvailable()) { 153 throw new IllegalStateException( 154 "OrsonPDF is not present on the classpath."); 155 } 156 Args.nullNotPermitted(drawable, "drawable"); 157 Args.nullNotPermitted(file, "file"); 158 try { 159 Class<?> pdfDocClass = Class.forName("com.orsonpdf.PDFDocument"); 160 Object pdfDoc = pdfDocClass.getDeclaredConstructor().newInstance(); 161 Method m = pdfDocClass.getMethod("createPage", Rectangle2D.class); 162 Rectangle2D rect = new Rectangle(w, h); 163 Object page = m.invoke(pdfDoc, rect); 164 Method m2 = page.getClass().getMethod("getGraphics2D"); 165 Graphics2D g2 = (Graphics2D) m2.invoke(page); 166 Rectangle2D drawArea = new Rectangle2D.Double(0, 0, w, h); 167 drawable.draw(g2, drawArea); 168 Method m3 = pdfDocClass.getMethod("writeToFile", File.class); 169 m3.invoke(pdfDoc, file); 170 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | 171 NoSuchMethodException | SecurityException | IllegalArgumentException | 172 InvocationTargetException ex) { 173 throw new RuntimeException(ex); 174 } 175 } 176 177 /** 178 * Writes the current content to the specified file in PNG format. 179 * 180 * @param drawable the drawable ({@code null} not permitted). 181 * @param w the chart width. 182 * @param h the chart height. 183 * @param file the output file ({@code null} not permitted). 184 * 185 * @throws FileNotFoundException if the file is not found. 186 * @throws IOException if there is an I/O problem. 187 */ 188 public static void writeAsPNG(Drawable drawable, int w, int h, 189 File file) throws FileNotFoundException, IOException { 190 BufferedImage image = new BufferedImage(w, h, 191 BufferedImage.TYPE_INT_ARGB); 192 Graphics2D g2 = image.createGraphics(); 193 drawable.draw(g2, new Rectangle(w, h)); 194 try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) { 195 ImageIO.write(image, "png", out); 196 } 197 } 198 199 /** 200 * Writes the current content to the specified file in JPEG format. 201 * 202 * @param drawable the drawable ({@code null} not permitted). 203 * @param w the chart width. 204 * @param h the chart height. 205 * @param file the output file ({@code null} not permitted). 206 * 207 * @throws FileNotFoundException if the file is not found. 208 * @throws IOException if there is an I/O problem. 209 */ 210 public static void writeAsJPEG(Drawable drawable, int w, int h, 211 File file) throws FileNotFoundException, IOException { 212 BufferedImage image = new BufferedImage(w, h, 213 BufferedImage.TYPE_INT_RGB); 214 Graphics2D g2 = image.createGraphics(); 215 drawable.draw(g2, new Rectangle(w, h)); 216 try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) { 217 ImageIO.write(image, "jpg", out); 218 } 219 } 220 221}