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