9b699fe7386c70f5dbea592cf019785bcd79c9ce
[scilab.git] / scilab / modules / graphic_export / src / java / org / scilab / modules / graphic_export / Export.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.graphic_export;
14
15 import java.awt.Graphics2D;
16 import java.awt.Dimension;
17 import java.awt.geom.AffineTransform;
18 import java.awt.image.BufferedImage;
19 import javax.imageio.ImageIO;
20 import java.io.File;
21 import java.io.BufferedOutputStream;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.io.OutputStreamWriter;
26 import java.io.Writer;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import org.apache.batik.svggen.SVGGeneratorContext;
31 import org.apache.batik.svggen.SVGGraphics2D;
32 import org.apache.batik.dom.GenericDOMImplementation;
33
34 import org.apache.fop.svg.PDFDocumentGraphics2D;
35 import org.apache.xmlgraphics.java2d.GraphicContext;
36 import org.apache.xmlgraphics.java2d.ps.AbstractPSDocumentGraphics2D;
37 import org.apache.xmlgraphics.java2d.ps.EPSDocumentGraphics2D;
38 import org.apache.xmlgraphics.java2d.ps.PSDocumentGraphics2D;
39 import org.apache.xmlgraphics.ps.DSCConstants;
40
41 import org.scilab.forge.scirenderer.Canvas;
42 import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvasFactory;
43 import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvas;
44 import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvasFactory;
45
46 import org.scilab.modules.commons.ScilabCommonsUtils;
47 import org.scilab.modules.graphic_export.convertToPPM.PPMEncoder;
48 import org.scilab.modules.graphic_objects.figure.Figure;
49 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
50 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
51
52 import org.w3c.dom.DOMImplementation;
53 import org.w3c.dom.Document;
54
55
56 /**
57  * Main class to export
58  * Dependancies are put in inner classes to avoid the deps loading.
59  *
60  * @author Calixte DENIZET
61  */
62 public class Export {
63
64     public static final int SUCCESS = 0;
65     public static final int IOEXCEPTION_ERROR = 1;
66     public static final int INVALID_FILE = 2;
67
68     private static final String CLASSPATH_PDF_PS_EPS_EXPORT_NAME = "pdf_ps_eps_graphic_export";
69     private static final String CLASSPATH_SVG_EXPORT_NAME = "svg_graphic_export";
70
71     private static final Map<String, Integer> extToType = new HashMap<String, Integer>();
72     static {
73         extToType.put("bmp", 1);
74         extToType.put("gif", 2);
75         extToType.put("jpeg", 3);
76         extToType.put("jpg", 3);
77         extToType.put("png", 4);
78         extToType.put("ppm", 5);
79         extToType.put("eps", 6);
80         extToType.put("pdf", 7);
81         extToType.put("svg", 8);
82         extToType.put("ps", 9);
83     }
84
85     private static boolean svgLoaded;
86     private static boolean pdfLoaded;
87
88     public enum TYPE { PNG, JPEG, GIF, BMP, PPM, SVG, PS, EPS, PDF }
89     private static final TYPE[] types = new TYPE[]{TYPE.PNG, TYPE.BMP, TYPE.GIF, TYPE.JPEG, TYPE.PNG, TYPE.PPM, TYPE.EPS, TYPE.PDF, TYPE.SVG, TYPE.PS};
90
91     /**
92      * @param type the image type
93      * @return true if bitmap image format
94      */
95     public static boolean isBitmapFormat(TYPE type) {
96         return type == TYPE.PNG || type == TYPE.JPEG || type == TYPE.GIF || type == TYPE.BMP || type == TYPE.PPM;
97     }
98
99     public static int getType(String ext) {
100         return extToType.get(ext);
101     }
102
103     /**
104      * Export in drawing in a Graphics2D
105      * @param uid the figure uid
106      * @param type the export type
107      * @param fileName the file name
108      * @param params the export paramaters
109      * @return the export status
110      */
111     public static int export(String uid, int type, String fileName, ExportParams params) {
112         DrawerVisitor visitor = DrawerVisitor.getVisitor(uid);
113         if (visitor != null) {
114             Canvas canvas = visitor.getCanvas();
115             if (canvas instanceof JoGLCanvas && isBitmapFormat(types[type])) {
116                 return exportBitmap(uid, type, fileName, true, params);
117             }
118         }
119
120         return exportVectorial(uid, type, fileName, params);
121     }
122
123     /**
124      * Export in drawing in a Graphics2D
125      * @param uid the figure uid
126      * @param type the export type
127      * @param fileName the file name
128      * @param params the export paramaters
129      * @return the export status
130      */
131     public static int exportVectorial(String uid, int type, String fileName, ExportParams params) {
132         File f = new File(fileName);
133         int ret = Utils.checkWritePermission(f);
134         if (ret != SUCCESS) {
135             return ret;
136         }
137
138         try {
139             exportVectorial(uid, types[type], f, params);
140         } catch (IOException e) {
141             return IOEXCEPTION_ERROR;
142         }
143
144         return SUCCESS;
145     }
146
147     /**
148      * Export in drawing in a Graphics2D
149      * @param uid the figure uid
150      * @param type the export type
151      * @param file the file where to export
152      * @param params the export paramaters
153      */
154     public static void exportVectorial(String uid, TYPE type, File file, ExportParams params) throws IOException {
155         Exporter exporter = getExporter(type);
156         Figure figure = (Figure) GraphicController.getController().getObjectFromId(uid);
157         Integer[] dims = figure.getAxesSize();
158         int width = dims[0];
159         int height = dims[1];
160
161         Graphics2D g2d = exporter.getGraphics2D(width, height, file, params);
162         params.setParamsOnGraphics(g2d);
163
164         Canvas canvas = G2DCanvasFactory.createCanvas(g2d, width, height);
165         DrawerVisitor oldVisitor = DrawerVisitor.getVisitor(uid);
166         DrawerVisitor visitor = new DrawerVisitor(null, canvas, figure) {
167                 @Override
168                 public void updateObject(String id, String property) {
169                     // Don't update during the export
170                 }
171             };
172         canvas.setMainDrawer(visitor);
173         canvas.redraw();
174         GraphicController.getController().unregister(visitor);
175         DrawerVisitor.changeVisitor(figure, oldVisitor);
176
177         exporter.write(params);
178         g2d.dispose();
179     }
180
181     /**
182      * Export in getting a buffered image from JoGL
183      * @param uid the figure uid
184      * @param type the export type
185      * @param fileName the file name
186      * @param fromScreen if true, then use the screen view
187      * @param params the export paramaters
188      * @return the export status
189      */
190     public static int exportBitmap(String uid, int type, String fileName, boolean fromScreen, ExportParams params) {
191         File f = new File(fileName);
192         int ret = Utils.checkWritePermission(f);
193         if (ret != SUCCESS) {
194             return ret;
195         }
196
197         try {
198             exportBitmap(uid, types[type], f, fromScreen, params);
199         } catch (IOException e) {
200             return IOEXCEPTION_ERROR;
201         }
202
203         return SUCCESS;
204     }
205
206     /**
207      * Export in getting a buffered image from JoGL
208      * @param uid the figure uid
209      * @param type the export type
210      * @param file the file where to export
211      * @param fromScreen if true, then use the screen view
212      * @param params the export paramaters
213      */
214     public static void exportBitmap(String uid, TYPE type, File file, boolean fromScreen, ExportParams params) throws IOException {
215         if (isBitmapFormat(type)) {
216             JoGLCanvas joglCanvas = null;
217             if (fromScreen) {
218                 DrawerVisitor visitor = DrawerVisitor.getVisitor(uid);
219                 Canvas canvas = visitor.getCanvas();
220                 if (canvas instanceof JoGLCanvas) {
221                     joglCanvas = (JoGLCanvas) canvas;
222                 }
223             } else {
224                 Figure figure = (Figure) GraphicController.getController().getObjectFromId(uid);
225                 Integer[] dims = figure.getAxesSize();
226                 DrawerVisitor oldVisitor = DrawerVisitor.getVisitor(uid);
227                 joglCanvas = (JoGLCanvas) JoGLCanvasFactory.createCanvas(dims[0], dims[1]);
228                 DrawerVisitor visitor = new DrawerVisitor(null, joglCanvas, figure) {
229                         @Override
230                         public void updateObject(String id, String property) {
231                             // Don't update during the export
232                         }
233                     };
234                 joglCanvas.setMainDrawer(visitor);
235                 joglCanvas.redraw();
236                 GraphicController.getController().unregister(visitor);
237                 DrawerVisitor.changeVisitor(figure, oldVisitor);
238             }
239
240             if (joglCanvas != null) {
241                 BufferedImage image = joglCanvas.getImage();
242                 joglCanvas.destroy();
243                 PNGExporter exporter = (PNGExporter) getExporter(type);
244                 exporter.setImage(file, image);
245                 exporter.write(params);
246             }
247         }
248     }
249
250     /**
251      * Get an exporter from a type
252      * @param type the exporter type.
253      * @return the corresponding exporter/
254      */
255     private static Exporter getExporter(TYPE type) {
256         switch (type) {
257         case PNG :
258             return new PNGExporter();
259         case GIF :
260             return new GIFExporter();
261         case JPEG :
262             return new JPEGExporter();
263         case BMP :
264             return new BMPExporter();
265         case PPM :
266             return new PPMExporter();
267         case SVG :
268             if (!svgLoaded) {
269                 ScilabCommonsUtils.loadOnUse(CLASSPATH_SVG_EXPORT_NAME);
270                 svgLoaded = true;
271             }
272             return new SVGExporter();
273         case PDF :
274             loadPDF();
275             return new PDFExporter();
276         case PS :
277             loadPDF();
278             return new PSExporter();
279         case EPS :
280             loadPDF();
281             return new PSExporter();
282         default :
283             break;
284         }
285
286         return null;
287     }
288
289     /**
290      * Load the PDF/PS/EPS dependencies
291      */
292     private static final void loadPDF() {
293         if (!pdfLoaded) {
294             ScilabCommonsUtils.loadOnUse(CLASSPATH_PDF_PS_EPS_EXPORT_NAME);
295             pdfLoaded = true;
296         }
297     }
298
299     /**
300      * Interface to export
301      */
302     private interface Exporter {
303
304         /**
305          * @param width graphics width
306          * @param height graphisc height
307          * @param file the file
308          * @param params the export parameters
309          */
310         Graphics2D getGraphics2D(int width, int height, File file, ExportParams params);
311
312         /**
313          * Write the file
314          * @param params export parameters
315          */
316         void write(ExportParams params) throws IOException;
317     }
318
319     /**
320      * PNG Exporter
321      */
322     private static class PNGExporter implements Exporter {
323
324         protected BufferedImage image;
325         protected Graphics2D g2d;
326         protected File file;
327
328         public PNGExporter() { }
329
330         public void setImage(File file, BufferedImage image) {
331             this.file = file;
332             this.image = image;
333         }
334
335         @Override
336         public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
337             this.file = file;
338             image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
339             g2d = image.createGraphics();
340
341             return g2d;
342         }
343
344         @Override
345         public void write(ExportParams params) throws IOException {
346             ExportBitmap.writeFile(image, "png", file);
347         }
348     }
349
350     /**
351      * GIF Exporter
352      */
353     private static class GIFExporter extends PNGExporter {
354
355         public GIFExporter() { }
356
357         @Override
358         public void write(ExportParams params) throws IOException {
359             ExportBitmap.writeFile(image, "gif", file);
360         }
361     }
362
363     /**
364      * JPEG Exporter
365      */
366     private static class JPEGExporter extends PNGExporter {
367
368         public JPEGExporter() { }
369
370         @Override
371         public void write(ExportParams params) throws IOException {
372             if (params.compressionQuality == -1) {
373                 ExportBitmap.writeFile(image, "jpeg", file);
374             } else {
375                 ExportBitmap.writeJPEG(image, params.compressionQuality, file);
376             }
377         }
378     }
379
380     /**
381      * BMP Exporter
382      */
383     private static class BMPExporter extends PNGExporter {
384
385         public BMPExporter() { }
386
387         @Override
388         public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
389             this.file = file;
390             image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
391             g2d = image.createGraphics();
392
393             return g2d;
394         }
395
396         @Override
397         public void write(ExportParams params) throws IOException {
398             ExportBitmap.writeFile(image, "bmp", file);
399         }
400     }
401
402     /**
403      * PPM Exporter
404      */
405     private static class PPMExporter extends PNGExporter {
406
407         public PPMExporter() { }
408
409         @Override
410         public void write(ExportParams params) throws IOException {
411             OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
412             PPMEncoder encoder = new PPMEncoder(image, out);
413             int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
414             encoder.encodePixels(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
415             out.flush();
416             out.close();
417         }
418     }
419
420     /**
421      * SVG Exporter
422      */
423     private static class SVGExporter implements Exporter {
424
425         private SVGGraphics2D g2d;
426         private File file;
427
428         public SVGExporter() { }
429
430         @Override
431         public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
432             this.file = file;
433             DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
434             Document document = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
435             SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
436             g2d = new SVGGraphics2D(ctx, false);
437             if (params.orientation == ExportParams.LANDSCAPE) {
438                 g2d.setSVGCanvasSize(new Dimension(height, width));
439                 AffineTransform transf = AffineTransform.getRotateInstance(Math.PI / 2);
440                 transf.preConcatenate(AffineTransform.getTranslateInstance(height, 0));
441                 g2d.setTransform(transf);
442             } else {
443                 g2d.setSVGCanvasSize(new Dimension(width, height));
444             }
445             return g2d;
446         }
447
448         @Override
449         public void write(ExportParams params) throws IOException {
450             boolean useCSS = true;
451             OutputStream svgs = new BufferedOutputStream(new FileOutputStream(file));
452             Writer out = new OutputStreamWriter(svgs, "UTF-8");
453             g2d.stream(out, useCSS);
454             svgs.flush();
455             svgs.close();
456         }
457     }
458
459     /**
460      * PDF Exporter
461      */
462     private static class PDFExporter implements Exporter {
463
464         private File file;
465         private OutputStream out;
466         private PDFDocumentGraphics2D g2d;
467
468         public PDFExporter() { }
469
470         @Override
471         public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
472             this.file = file;
473             try {
474                 out = new BufferedOutputStream(new FileOutputStream(file));
475                 g2d = new PDFDocumentGraphics2D(false);
476                 g2d.setGraphicContext(new GraphicContext());
477                 if (params.orientation == ExportParams.LANDSCAPE) {
478                     g2d.setupDocument(out, height, width);
479                     g2d.setSVGDimension(height, width);
480                     double s = PDFDocumentGraphics2D.NORMAL_PDF_RESOLUTION / g2d.getDeviceDPI();
481                     AffineTransform transf = AffineTransform.getRotateInstance(Math.PI / 2);
482                     transf.preConcatenate(AffineTransform.getTranslateInstance(height / s, 0));
483                     g2d.setTransform(transf);
484                 } else {
485                     g2d.setupDocument(out, width, height);
486                     g2d.setSVGDimension(width, height);
487                 }
488             } catch (IOException e) { }
489
490             return g2d;
491         }
492
493         @Override
494         public void write(ExportParams params) throws IOException {
495             if (g2d != null) {
496                 g2d.finish();
497             }
498             if (out != null) {
499                 out.close();
500             }
501         }
502     }
503
504     /**
505      * PS Exporter
506      */
507     private static class PSExporter implements Exporter {
508
509         protected File file;
510         protected OutputStream out;
511         protected AbstractPSDocumentGraphics2D g2d;
512
513         public PSExporter() { }
514
515         @Override
516         public Graphics2D getGraphics2D(int width, int height, File file, final ExportParams params) {
517             this.file = file;
518             try {
519                 out = new BufferedOutputStream(new FileOutputStream(file));
520                 g2d = new PSDocumentGraphics2D(false, out, width, height) {
521                         @Override
522                         protected void writePageHeader() throws IOException {
523                             super.writePageHeader();
524                             if (params.orientation == ExportParams.LANDSCAPE) {
525                                 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape");
526                             } else {
527                                 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Portrait");
528                             }
529                         }
530                     };
531                 g2d.setGraphicContext(new GraphicContext());
532             } catch (IOException e) { }
533
534             return g2d;
535         }
536
537         @Override
538         public void write(ExportParams params) throws IOException {
539             if (g2d != null) {
540                 g2d.finish();
541             }
542             if (out != null) {
543                 out.close();
544             }
545         }
546     }
547
548     /**
549      * EPS Exporter
550      */
551     private static class EPSExporter extends PSExporter {
552
553         public EPSExporter() { }
554
555         @Override
556         public Graphics2D getGraphics2D(int width, int height, File file, final ExportParams params) {
557             this.file = file;
558             try {
559                 out = new BufferedOutputStream(new FileOutputStream(file));
560                 g2d = new EPSDocumentGraphics2D(false) {
561                         @Override
562                         protected void writePageHeader() throws IOException {
563                             super.writePageHeader();
564                             if (params.orientation == ExportParams.LANDSCAPE) {
565                                 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape");
566                             } else {
567                                 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Portrait");
568                             }
569                         }
570                     };
571                 g2d.setupDocument(out, width, height);
572                 g2d.setGraphicContext(new GraphicContext());
573             } catch (IOException e) { }
574
575             return g2d;
576         }
577     }
578 }