2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2012 - Scilab Enterprises - Calixte Denizet
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.1-en.txt
13 package org.scilab.modules.graphic_export;
15 import java.awt.Dimension;
17 import java.awt.Graphics2D;
18 import java.awt.Shape;
19 import java.awt.geom.AffineTransform;
20 import java.awt.geom.Ellipse2D;
21 import java.awt.geom.PathIterator;
22 import java.awt.image.BufferedImage;
23 import java.io.BufferedOutputStream;
24 import java.io.ByteArrayOutputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.io.OutputStreamWriter;
30 import java.io.Writer;
31 import java.nio.charset.Charset;
32 import java.nio.charset.CharsetEncoder;
33 import java.text.AttributedCharacterIterator;
34 import java.util.HashMap;
36 import java.util.WeakHashMap;
38 import org.apache.batik.dom.GenericDOMImplementation;
39 import org.apache.batik.svggen.SVGGeneratorContext;
40 import org.apache.batik.svggen.SVGGraphics2D;
41 import org.apache.fop.Version;
42 import org.apache.fop.svg.PDFDocumentGraphics2D;
43 import org.apache.xmlgraphics.java2d.GraphicContext;
44 import org.apache.xmlgraphics.java2d.ps.AbstractPSDocumentGraphics2D;
45 import org.apache.xmlgraphics.java2d.ps.EPSDocumentGraphics2D;
46 import org.apache.xmlgraphics.java2d.ps.PSDocumentGraphics2D;
47 import org.apache.xmlgraphics.ps.DSCConstants;
48 import org.apache.xmlgraphics.ps.PSGenerator;
49 import org.scilab.forge.scirenderer.Canvas;
50 import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvas;
51 import org.scilab.forge.scirenderer.implementation.g2d.G2DCanvasFactory;
52 import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvas;
53 import org.scilab.forge.scirenderer.implementation.jogl.JoGLCanvasFactory;
54 import org.scilab.modules.commons.ScilabCommonsUtils;
55 import org.scilab.modules.graphic_export.convertToPPM.PPMEncoder;
56 import org.scilab.modules.graphic_objects.figure.Figure;
57 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
58 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
59 import org.scilab.modules.renderer.JoGLView.DrawerVisitor;
60 import org.w3c.dom.DOMImplementation;
61 import org.w3c.dom.Document;
64 * Main class to export
65 * Dependancies are put in inner classes to avoid the deps loading.
67 * @author Calixte DENIZET
71 public static final int SUCCESS = 0;
72 public static final int IOEXCEPTION_ERROR = 1;
73 public static final int INVALID_FILE = 2;
74 public static final int MEMORY_ERROR = 3;
75 public static final int UNKNOWN_ERROR = 4;
77 private static final float DEFAULT_JPEG_COMPRESSION = 0.95f;
79 private static final String CLASSPATH_PDF_PS_EPS_EXPORT_NAME = "pdf_ps_eps_graphic_export";
80 private static final String CLASSPATH_SVG_EXPORT_NAME = "svg_graphic_export";
82 private static final Map<DrawerVisitor, Exporter> visitorsToExp = new WeakHashMap<DrawerVisitor, Exporter>();
84 private static final Map<String, Integer> extToType = new HashMap<String, Integer>();
86 extToType.put("bmp", 1);
87 extToType.put("gif", 2);
88 extToType.put("jpeg", 3);
89 extToType.put("jpg", 3);
90 extToType.put("png", 4);
91 extToType.put("ppm", 5);
92 extToType.put("eps", 6);
93 extToType.put("pdf", 7);
94 extToType.put("svg", 8);
95 extToType.put("ps", 9);
96 extToType.put("pos", 9);
99 private static boolean svgLoaded;
100 private static boolean pdfLoaded;
102 public enum TYPE { PNG, JPEG, GIF, BMP, PPM, SVG, PS, EPS, PDF }
103 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};
106 * @param type the image type
107 * @return true if bitmap image format
109 public static boolean isBitmapFormat(TYPE type) {
110 return type == TYPE.PNG || type == TYPE.JPEG || type == TYPE.GIF || type == TYPE.BMP || type == TYPE.PPM;
113 public static int getType(String ext) {
114 Integer type = extToType.get(ext.toLowerCase());
123 * Export in drawing in a Graphics2D
124 * @param uid the figure uid
125 * @param type the export type
126 * @param fileName the file name
127 * @param params the export paramaters
128 * @return the export status
130 public static int export(String uid, int type, String fileName, ExportParams params, boolean headless) {
131 // Check that the fileName contains an extension
132 int dotPosition = fileName.lastIndexOf('.'); // position of the dot
133 boolean extensionFound = false;
134 if (dotPosition > 0 && dotPosition <= fileName.length() - 2) {
135 extensionFound = true;
138 String extendedFilename = fileName;
139 if (!extensionFound) { // Add default extension if no one found
140 String[] extensions = {"png", "bmp", "gif", "jpeg", "png", "ppm", "eps", "pdf", "svg", "ps"};
141 extendedFilename = fileName + "." + extensions[type];
144 DrawerVisitor visitor = DrawerVisitor.getVisitor(uid);
145 if (visitor != null) {
146 Canvas canvas = visitor.getCanvas();
147 if (canvas instanceof JoGLCanvas && isBitmapFormat(types[type])) {
149 return exportBitmap(uid, type, extendedFilename, true, params);
150 } catch (OutOfMemoryError e) {
152 } catch (Throwable e) {
153 return UNKNOWN_ERROR;
158 return exportVectorial(uid, type, extendedFilename, params, headless);
163 * Export in drawing in a Graphics2D
164 * @param uid the figure uid
165 * @param type the export type
166 * @param fileName the file name
167 * @param params the export paramaters
168 * @return the export status
170 public static int exportVectorial(String uid, int type, String fileName, ExportParams params, boolean headless) {
171 if (fileName == null) {
175 File f = new File(fileName);
176 int ret = Utils.checkWritePermission(f);
177 if (ret != SUCCESS) {
182 return exportVectorial(uid, types[type], f, params, headless);
183 } catch (IOException e) {
184 return IOEXCEPTION_ERROR;
189 * Export in drawing in a Graphics2D
190 * @param uid the figure uid
191 * @param type the export type
192 * @param file the file where to export
193 * @param params the export paramaters
195 public static int exportVectorial(String uid, TYPE type, File file, ExportParams params, boolean headless) throws IOException {
196 Figure figure = (Figure) GraphicController.getController().getObjectFromId(uid);
199 Exporter exporter = getExporter(type);
200 Integer[] dims = figure.getAxesSize();
202 int height = dims[1];
204 Graphics2D g2d = exporter.getGraphics2D(width, height, file, params);
205 params.setParamsOnGraphics(g2d);
207 Canvas canvas = G2DCanvasFactory.createCanvas(g2d, width, height);
208 DrawerVisitor oldVisitor = DrawerVisitor.getVisitor(uid);
209 DrawerVisitor visitor = new DrawerVisitor(null, canvas, figure) {
211 public void updateObject(String id, int property) {
212 // Don't update during the export
217 canvas.setMainDrawer(visitor);
220 } catch (OutOfMemoryError e) {
222 } catch (Throwable e) {
223 return UNKNOWN_ERROR;
225 GraphicController.getController().unregister(visitor);
226 DrawerVisitor.changeVisitor(figure, oldVisitor);
229 visitorsToExp.remove(visitor);
232 DrawerVisitor visitor = DrawerVisitor.getVisitor(uid);
233 G2DCanvas canvas = (G2DCanvas) visitor.getCanvas();
235 Exporter exporter = null;
238 exporter = visitorsToExp.get(visitor);
239 if (exporter != null) {
240 exporter.file = file;
243 } catch (OutOfMemoryError e) {
245 } catch (Throwable e) {
246 return UNKNOWN_ERROR;
248 if (exporter != null) {
251 visitorsToExp.remove(visitor);
253 DrawerVisitor.changeVisitor(figure, null);
254 GraphicController.getController().unregister(visitor);
262 * Export in getting a buffered image from JoGL
263 * @param uid the figure uid
264 * @param type the export type
265 * @param fileName the file name
266 * @param fromScreen if true, then use the screen view
267 * @param params the export paramaters
268 * @return the export status
270 public static int exportBitmap(String uid, int type, String fileName, boolean fromScreen, ExportParams params) {
271 if (fileName == null) {
275 File f = new File(fileName);
276 int ret = Utils.checkWritePermission(f);
277 if (ret != SUCCESS) {
282 exportBitmap(uid, types[type], f, fromScreen, params);
283 } catch (IOException e) {
284 return IOEXCEPTION_ERROR;
291 * Export in getting a buffered image from JoGL
292 * @param uid the figure uid
293 * @param type the export type
294 * @param file the file where to export
295 * @param fromScreen if true, then use the screen view
296 * @param params the export paramaters
298 public static void exportBitmap(String uid, TYPE type, File file, boolean fromScreen, ExportParams params) throws IOException {
299 if (isBitmapFormat(type)) {
300 JoGLCanvas joglCanvas = null;
302 DrawerVisitor visitor = DrawerVisitor.getVisitor(uid);
303 Canvas canvas = visitor.getCanvas();
304 if (canvas instanceof JoGLCanvas) {
305 joglCanvas = (JoGLCanvas) canvas;
308 Figure figure = (Figure) GraphicController.getController().getObjectFromId(uid);
309 Integer[] dims = figure.getAxesSize();
310 DrawerVisitor oldVisitor = DrawerVisitor.getVisitor(uid);
311 joglCanvas = (JoGLCanvas) JoGLCanvasFactory.createCanvas(dims[0], dims[1]);
312 DrawerVisitor visitor = new DrawerVisitor(null, joglCanvas, figure) {
314 public void updateObject(String id, int property) {
315 // Don't update during the export
319 public void deleteObject(String id) {
320 // Don't delete during the export
323 joglCanvas.setMainDrawer(visitor);
325 GraphicController.getController().unregister(visitor);
326 DrawerVisitor.changeVisitor(figure, oldVisitor);
329 if (joglCanvas != null) {
330 BufferedImage image = joglCanvas.getImage();
331 //joglCanvas.destroy();
332 PNGExporter exporter = (PNGExporter) getExporter(type);
333 exporter.setImage(file, image, params);
341 * Export in drawing in a Graphics2D
342 * @param uid the figure uid
343 * @param type the export type
344 * @param file the file where to export
345 * @param params the export paramaters
347 public static void setVisitor(String uid, int type, final ExportParams params) {
348 final Exporter exporter = getExporter(types[type]);
349 Figure figure = (Figure) GraphicController.getController().getObjectFromId(uid);
350 final Integer[] dims = figure.getAxesSize();
352 int height = dims[1];
354 final Graphics2D g2d = exporter.getGraphics2D(width, height, null, params);
355 params.setParamsOnGraphics(g2d);
357 final G2DCanvas canvas = G2DCanvasFactory.createCanvas(g2d, width, height);
358 canvas.disableDraw();
359 DrawerVisitor visitor = new DrawerVisitor(null, canvas, figure) {
361 public void deleteObject(String id) {
362 // Don't delete during the export
366 public void updateObject(String id, int property) {
367 if (needUpdate(id, property)) {
368 axesDrawer.update(id, property);
369 if (property == GraphicObjectProperties.__GO_AXES_SIZE__) {
370 Integer[] size = getFigure().getAxesSize();
371 if (size[0] != dims[0] || size[1] != dims[1]) {
372 Graphics2D newg2d = exporter.getGraphics2D(size[0], size[1], null, params);
373 params.setParamsOnGraphics(newg2d);
374 canvas.setGraphics(newg2d, size[0], size[1]);
380 } else if (property == GraphicObjectProperties.__GO_ANTIALIASING__) {
381 canvas.setAntiAliasingLevel(getFigure().getAntialiasing());
386 visitor.setDrawingTools(canvas.getDrawingTools());
387 canvas.setMainDrawer(visitor);
388 visitorsToExp.put(visitor, exporter);
392 * Get an exporter from a type
393 * @param type the exporter type.
394 * @return the corresponding exporter/
396 private static Exporter getExporter(TYPE type) {
399 return new PNGExporter();
401 return new GIFExporter();
403 return new JPEGExporter();
405 return new BMPExporter();
407 return new PPMExporter();
410 ScilabCommonsUtils.loadOnUse(CLASSPATH_SVG_EXPORT_NAME);
413 return new SVGExporter();
416 return new PDFExporter();
419 return new PSExporter();
422 return new EPSExporter();
431 * Load the PDF/PS/EPS dependencies
433 private static final void loadPDF() {
435 ScilabCommonsUtils.loadOnUse(CLASSPATH_PDF_PS_EPS_EXPORT_NAME);
441 * Interface to export
443 private static abstract class Exporter {
448 * @param width graphics width
449 * @param height graphisc height
450 * @param file the file
451 * @param params the export parameters
453 abstract Graphics2D getGraphics2D(int width, int height, File file, ExportParams params);
458 abstract void write() throws IOException;
460 abstract void dispose();
466 private static class PNGExporter extends Exporter {
468 protected BufferedImage image;
469 protected Graphics2D g2d;
470 protected ExportParams params;
472 public PNGExporter() { }
474 public void setImage(File file, BufferedImage image, ExportParams params) {
477 this.params = params;
481 public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
483 this.params = params;
484 image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
485 g2d = image.createGraphics();
491 public void write() throws IOException {
492 ExportBitmap.writeFile(image, "png", file);
496 public void dispose() {
506 private static class GIFExporter extends PNGExporter {
508 public GIFExporter() { }
511 public void write() throws IOException {
512 ExportBitmap.writeFile(image, "gif", file);
519 private static class BMPExporter extends PNGExporter {
521 public BMPExporter() { }
524 public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
526 this.params = params;
527 image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
528 g2d = image.createGraphics();
534 public void write() throws IOException {
535 ExportBitmap.writeFile(image, "bmp", file);
542 private static class JPEGExporter extends BMPExporter {
544 public JPEGExporter() { }
547 public void write() throws IOException {
548 if (params.compressionQuality == -1) {
549 ExportBitmap.writeJPEG(image, DEFAULT_JPEG_COMPRESSION, file);
551 ExportBitmap.writeJPEG(image, params.compressionQuality, file);
559 private static class PPMExporter extends BMPExporter {
561 public PPMExporter() { }
564 public void write() throws IOException {
565 OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
566 PPMEncoder encoder = new PPMEncoder(image, out);
567 int[] pixels = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
568 encoder.encodeStart(image.getWidth(), image.getHeight());
569 encoder.encodePixels(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
578 private static class SVGExporter extends Exporter {
580 private SVGGraphics2D g2d;
581 private ExportParams params;
583 public SVGExporter() { }
586 public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
588 this.params = params;
589 DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
590 Document document = domImpl.createDocument("http://www.w3.org/2000/svg", "svg", null);
591 final SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
592 ctx.setComment("Generated by Scilab with Batik SVG Generator");
593 // TODO: better handle of LaTeX fonts (should remove the 'true' below and include the font in the SVG)
594 // same thing for PDF & co...
595 ctx.setEmbeddedFontsOn(true);
596 g2d = new SVGGraphics2D(ctx, false) {
599 public void drawString(String s, float x, float y) {
600 textAsShapes = getFont().getFontName().startsWith("jlm");
601 super.drawString(s, x, y);
605 public void drawString(AttributedCharacterIterator ati, float x, float y) {
606 textAsShapes = getFont().getFontName().startsWith("jlm");
607 super.drawString(ati, x, y);
610 if (params.orientation == ExportParams.LANDSCAPE) {
611 g2d.setSVGCanvasSize(new Dimension(height, width));
612 AffineTransform transf = AffineTransform.getRotateInstance(Math.PI / 2);
613 transf.preConcatenate(AffineTransform.getTranslateInstance(height, 0));
614 g2d.setTransform(transf);
616 g2d.setSVGCanvasSize(new Dimension(width, height));
622 public void write() throws IOException {
623 boolean useCSS = true;
624 OutputStream svgs = new BufferedOutputStream(new FileOutputStream(file));
625 Writer out = new OutputStreamWriter(svgs, "UTF-8");
626 g2d.stream(out, useCSS);
632 public void dispose() {
642 private static class PDFExporter extends Exporter {
644 private OutputStream out;
645 private PDFDocumentGraphics2D g2d;
646 private ExportParams params;
647 private ByteArrayOutputStream buffer;
649 public PDFExporter() { }
652 public Graphics2D getGraphics2D(int width, int height, File file, ExportParams params) {
654 this.params = params;
657 buffer = new ByteArrayOutputStream();
658 out = new BufferedOutputStream(buffer);
660 out = new BufferedOutputStream(new FileOutputStream(file));
662 g2d = new PDFDocumentGraphics2D(true);
663 g2d.setupDefaultFontInfo();
664 g2d.getPDFDocument().getInfo().setProducer("Generated by Scilab with Apache FOP Version " + Version.getVersion());
665 g2d.setGraphicContext(new GraphicContext());
666 if (params.orientation == ExportParams.LANDSCAPE) {
667 g2d.setupDocument(out, height, width);
668 g2d.setSVGDimension(height, width);
669 double s = PDFDocumentGraphics2D.NORMAL_PDF_RESOLUTION / g2d.getDeviceDPI();
670 AffineTransform transf = AffineTransform.getRotateInstance(Math.PI / 2);
671 transf.preConcatenate(AffineTransform.getTranslateInstance(height / s, 0));
672 g2d.setTransform(transf);
674 g2d.setupDocument(out, width, height);
675 g2d.setSVGDimension(width, height);
677 } catch (IOException e) { }
683 public void write() throws IOException {
687 if (buffer != null && file != null) {
688 FileOutputStream fos = new FileOutputStream(file);
700 public void dispose() {
708 private static class PSExporter extends Exporter {
710 protected OutputStream out;
711 protected AbstractPSDocumentGraphics2D g2d;
712 protected ExportParams params;
713 protected ByteArrayOutputStream buffer;
715 public PSExporter() { }
718 public Graphics2D getGraphics2D(int width, int height, File file, final ExportParams params) {
720 this.params = params;
723 buffer = new ByteArrayOutputStream();
724 out = new BufferedOutputStream(buffer);
726 out = new BufferedOutputStream(new FileOutputStream(file));
728 g2d = new PSDocumentGraphics2D(true, out, width, height) {
730 protected void writePageHeader() throws IOException {
731 super.writePageHeader();
732 if (params.orientation == ExportParams.LANDSCAPE) {
733 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape");
735 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Portrait");
737 gen.writeln("/ReEncode { /MyEncoding exch def exch findfont dup length dict begin {def} forall /Encoding MyEncoding def currentdict end definefont } def");
738 gen.writeln("/Helvetica /HelveticaLatin1 ISOLatin1Encoding ReEncode");
739 gen.writeln("/Times /TimesLatin1 ISOLatin1Encoding ReEncode");
743 public void drawString(String s, float x, float y) {
744 if (s != null && !s.isEmpty()) {
745 CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder();
746 if (encoder.canEncode(s)) {
747 Font font = getFont();
748 boolean sserif = font.getName().equals("SansSerif");
749 boolean serif = font.getName().equals("Serif");
750 if (sserif || serif) {
753 establishColor(getColor());
754 gen.writeln((sserif ? "/HelveticaLatin1" : "/TimesLatin1") + " " + gen.formatDouble(getFont().getSize()) + " F");
756 gen.saveGraphicsState();
757 Shape imclip = getClip();
760 AffineTransform trans = getTransform();
761 boolean newTransform = gen.getCurrentState().checkTransform(trans) && !trans.isIdentity();
764 gen.concatMatrix(trans);
767 gen.writeln(gen.formatDouble(x)
768 + " " + gen.formatDouble(y)
771 StringBuffer buf = new StringBuffer("(");
772 for (int i = 0; i < s.length(); i++) {
773 PSGenerator.escapeChar(s.charAt(i), buf);
777 gen.writeln(buf.toString());
779 gen.restoreGraphicsState();
780 } catch (IOException e) {
781 System.err.println(e);
788 super.drawString(s, x, y);
793 public int processShape(Shape s) throws IOException {
794 if (s instanceof Ellipse2D.Double) {
795 Ellipse2D.Double ell = (Ellipse2D.Double) s;
796 if (ell.height == ell.width) {
797 gen.writeln(gen.formatDouble(ell.x + ell.width / 2)
798 + " " + gen.formatDouble(ell.y + ell.height / 2)
799 + " " + gen.formatDouble(ell.width / 2)
800 + " " + gen.formatDouble(0d)
801 + " " + gen.formatDouble(360d)
804 return PathIterator.WIND_NON_ZERO;
808 return super.processShape(s);
811 g2d.setGraphicContext(new GraphicContext());
812 } catch (IOException e) { }
818 public void write() throws IOException {
822 if (buffer != null && file != null) {
823 FileOutputStream fos = new FileOutputStream(file);
835 public void dispose() {
845 private static class EPSExporter extends PSExporter {
847 public EPSExporter() { }
850 public Graphics2D getGraphics2D(int width, int height, File file, final ExportParams params) {
852 this.params = params;
855 buffer = new ByteArrayOutputStream();
856 out = new BufferedOutputStream(buffer);
858 out = new BufferedOutputStream(new FileOutputStream(file));
860 g2d = new EPSDocumentGraphics2D(true) {
862 protected void writePageHeader() throws IOException {
863 super.writePageHeader();
864 if (params.orientation == ExportParams.LANDSCAPE) {
865 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Landscape");
867 gen.writeDSCComment(DSCConstants.PAGE_ORIENTATION, "Portrait");
869 gen.writeln("/ReEncode { /MyEncoding exch def exch findfont dup length dict begin {def} forall /Encoding MyEncoding def currentdict end definefont } def");
870 gen.writeln("/Helvetica /HelveticaLatin1 ISOLatin1Encoding ReEncode");
871 gen.writeln("/Times /TimesLatin1 ISOLatin1Encoding ReEncode");
875 public void drawString(String s, float x, float y) {
876 if (s != null && !s.isEmpty()) {
877 CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder();
878 if (encoder.canEncode(s)) {
879 Font font = getFont();
880 boolean sserif = font.getName().equals("SansSerif");
881 boolean serif = font.getName().equals("Serif");
882 if (sserif || serif) {
885 establishColor(getColor());
886 gen.writeln((sserif ? "/HelveticaLatin1" : "/TimesLatin1") + " " + gen.formatDouble(getFont().getSize()) + " F");
888 gen.saveGraphicsState();
889 Shape imclip = getClip();
892 AffineTransform trans = getTransform();
893 boolean newTransform = gen.getCurrentState().checkTransform(trans) && !trans.isIdentity();
896 gen.concatMatrix(trans);
899 gen.writeln(gen.formatDouble(x)
900 + " " + gen.formatDouble(y)
903 StringBuffer buf = new StringBuffer("(");
904 for (int i = 0; i < s.length(); i++) {
905 PSGenerator.escapeChar(s.charAt(i), buf);
909 gen.writeln(buf.toString());
911 gen.restoreGraphicsState();
912 } catch (IOException e) {
913 System.err.println(e);
920 super.drawString(s, x, y);
925 public int processShape(Shape s) throws IOException {
926 if (s instanceof Ellipse2D.Double) {
927 Ellipse2D.Double ell = (Ellipse2D.Double) s;
928 if (ell.height == ell.width) {
929 gen.writeln(gen.formatDouble(ell.x + ell.width / 2)
930 + " " + gen.formatDouble(ell.y + ell.height / 2)
931 + " " + gen.formatDouble(ell.width / 2)
932 + " " + gen.formatDouble(0d)
933 + " " + gen.formatDouble(360d)
936 return PathIterator.WIND_NON_ZERO;
940 return super.processShape(s);
944 g2d.setupDocument(out, width, height);
945 g2d.setGraphicContext(new GraphicContext());
946 } catch (IOException e) { }