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