1 /* PostScriptGraphics2D.java -- AWT printer rendering class.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu.java.awt.print;
40 import java.awt.BasicStroke;
41 import java.awt.Color;
42 import java.awt.Composite;
43 import java.awt.Paint;
45 import java.awt.FontMetrics;
46 import java.awt.GradientPaint;
47 import java.awt.Graphics;
48 import java.awt.GraphicsConfiguration;
49 import java.awt.Graphics2D;
50 import java.awt.Image;
51 import java.awt.Polygon;
52 import java.awt.Rectangle;
53 import java.awt.RenderingHints;
54 import java.awt.Shape;
55 import java.awt.Stroke;
56 import java.awt.geom.AffineTransform;
57 import java.awt.geom.Arc2D;
58 import java.awt.geom.Ellipse2D;
59 import java.awt.geom.RoundRectangle2D;
60 import java.awt.geom.PathIterator;
61 import java.awt.geom.Point2D;
62 import java.awt.geom.Rectangle2D;
63 import java.awt.font.FontRenderContext;
64 import java.awt.font.GlyphVector;
65 import java.awt.font.TextLayout;
66 import java.awt.image.BufferedImage;
67 import java.awt.image.BufferedImageOp;
68 import java.awt.image.renderable.RenderableImage;
69 import java.awt.image.RenderedImage;
70 import java.awt.image.ImageObserver;
71 import java.awt.image.PixelGrabber;
72 import java.awt.print.PageFormat;
73 import java.awt.print.Pageable;
74 import java.awt.print.Paper;
75 import java.awt.print.Printable;
76 import java.awt.print.PrinterException;
77 import java.awt.print.PrinterGraphics;
78 import java.awt.print.PrinterJob;
79 import java.io.BufferedWriter;
81 import java.io.FileOutputStream;
82 import java.io.IOException;
83 import java.io.OutputStreamWriter;
84 import java.io.PrintWriter;
85 import java.text.AttributedCharacterIterator;
89 * Class PostScriptGraphics2D - Class that implements the Graphics2D object,
90 * writing the output to a PostScript or EPS file
92 * @author Sven de Marothy
95 class PostScriptGraphics2D extends Graphics2D
98 * The associated printer job.
100 private PrinterJob printerJob;
105 private PrintWriter out;
108 private AffineTransform currentTransform = new AffineTransform();
109 private AffineTransform pageTransform;
110 private RenderingHints renderingHints;
111 private Paint currentPaint = null;
112 private Shape clipShape = null;
113 private Font currentFont = null;
114 private Color currentColor = Color.black;
115 private Color backgroundColor = Color.white;
116 private Stroke currentStroke = null;
117 private static Stroke ordinaryStroke = new BasicStroke(0.0f,
118 BasicStroke.CAP_BUTT,
119 BasicStroke.JOIN_MITER);
120 private float cx; // current drawing position
121 private float cy; // current drawing position
122 private boolean currentFontIsPS; // set if currentFont is one of the above
125 private double pageX = 595;
126 private double pageY = 842;
127 private double Y = pageY;
128 private boolean gradientOn = false;
134 public PostScriptGraphics2D( PrinterJob pg )
137 // create transform objects
138 pageTransform = new AffineTransform();
139 currentTransform = new AffineTransform();
142 Create Rendering hints
144 Quality color and rendering
145 Bicubic interpolation
146 Fractional metrics supported
148 renderingHints = new RenderingHints(null);
149 renderingHints.put(RenderingHints.KEY_RENDERING,
150 RenderingHints.VALUE_RENDER_QUALITY);
151 renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
152 RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
153 renderingHints.put(RenderingHints.KEY_INTERPOLATION,
154 RenderingHints.VALUE_INTERPOLATION_BICUBIC);
155 renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
156 RenderingHints.VALUE_FRACTIONALMETRICS_ON);
157 renderingHints.put(RenderingHints.KEY_COLOR_RENDERING,
158 RenderingHints.VALUE_COLOR_RENDER_QUALITY);
162 * Spool a document to PostScript.
163 * If Pageable is non-null, it will print that, otherwise it will use
164 * the supplied printable and pageFormat.
166 public SpooledDocument spoolPostScript(Printable printable,
167 PageFormat pageFormat,
169 throws PrinterException
173 // spool to a temporary file
174 File temp = File.createTempFile("cpspool", ".ps");
177 out = new PrintWriter(new BufferedWriter
178 (new OutputStreamWriter
179 (new FileOutputStream(temp),
180 "ISO8859_1"), 1000000));
186 for(int index = 0; index < pageable.getNumberOfPages(); index++)
187 spoolPage(out, pageable.getPrintable(index),
188 pageable.getPageFormat(index), index);
193 while(spoolPage(out, printable, pageFormat, index++) ==
194 Printable.PAGE_EXISTS);
196 out.println("%%Trailer");
197 out.println("%%EOF");
199 return new SpooledDocument( temp );
201 catch (IOException e)
203 PrinterException pe = new PrinterException();
209 //--------------------------------------------------------------------------
212 * Write the postscript file header,
213 * setup the page format and transforms.
215 private void writePSHeader()
217 out.println("%!PS-Adobe-3.0");
218 out.println("%%Title: "+printerJob.getJobName());
219 out.println("%%Creator: GNU Classpath ");
220 out.println("%%DocumentData: Clean8Bit");
222 out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier");
223 out.println("%%EndComments");
225 out.println("%%BeginProlog");
226 out.println("%%EndProlog");
227 out.println("%%BeginSetup");
229 out.println("%%EndFeature");
231 out.println("%%EndSetup");
233 // set default fonts and colors
234 setFont( new Font("Dialog", Font.PLAIN, 12) );
235 currentColor = Color.white;
236 currentStroke = new BasicStroke();
237 setPaint(currentColor);
238 setStroke(currentStroke);
242 * setupFonts - set up the font dictionaries for
243 * helvetica, times and courier
245 private void setupFonts()
247 out.println("/helveticaISO");
248 out.println("/Helvetica findfont dup length dict begin");
249 out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall");
250 out.println("/Encoding ISOLatin1Encoding def");
251 out.println("currentdict end definefont pop");
253 out.println("/timesISO");
254 out.println("/Times-Roman findfont dup length dict begin");
255 out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall");
256 out.println("/Encoding ISOLatin1Encoding def");
257 out.println("currentdict end definefont pop");
259 out.println("/courierISO");
260 out.println("/Courier findfont dup length dict begin");
261 out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall");
262 out.println("/Encoding ISOLatin1Encoding def");
263 out.println("currentdict end definefont pop");
267 * Spools a single page, returns NO_SUCH_PAGE unsuccessful,
268 * PAGE_EXISTS if it was.
270 public int spoolPage(PrintWriter out,
272 PageFormat pageFormat,
273 int index) throws IOException, PrinterException
275 out.println("%%BeginPageSetup");
277 Paper p = pageFormat.getPaper();
278 pageX = p.getWidth();
279 pageY = p.getHeight();
281 if( pageFormat.getOrientation() == PageFormat.PORTRAIT )
282 out.println( "%%Orientation: Portrait" );
285 out.println( "%%Orientation: Landscape" );
291 setClip(0, 0, (int)pageX, (int)pageY);
293 out.println("gsave % first save");
295 // 595x842; 612x792 respectively
296 out.println("<< /PageSize [" +pageX + " "+pageY+ "] >> setpagedevice");
298 if( pageFormat.getOrientation() != PageFormat.LANDSCAPE )
300 pageTransform.translate(pageX, 0);
301 pageTransform.scale(-1.0, 1.0);
304 // save the original CTM
306 concatCTM(pageTransform);
307 setTransform(new AffineTransform());
309 out.println("%%EndPageSetup");
311 out.println("gsave");
313 if( printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE )
314 return Printable.NO_SUCH_PAGE;
316 out.println("grestore");
317 out.println("showpage");
319 return Printable.PAGE_EXISTS;
322 /** push the Current Transformation Matrix onto the PS stack */
323 private void pushCTM()
325 out.println("matrix currentmatrix % pushCTM()");
328 /** pop the Current Transformation Matrix from the PS stack */
329 private void popCTM()
331 out.println("setmatrix % restore CTM");
334 ///////////////////////////////////////////////////////////////////////////
336 public Graphics create()
341 public void drawOval(int x, int y, int width, int height)
343 out.println("% drawOval()");
344 setStroke(ordinaryStroke);
345 draw(new Ellipse2D.Double(x, y, width, height));
346 setStroke(currentStroke);
349 public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
351 if (nPoints <= 0 || xPoints.length < nPoints || yPoints.length < nPoints)
353 out.println("newpath % drawPolyLine()");
354 out.println(xPoints[0] + " " + yPoints[0] + " moveto");
355 for (int i = 1; i < nPoints; i++)
356 out.println(xPoints[i] + " " + yPoints[i] + " lineto");
357 out.println("closepath");
358 out.println("stroke");
361 public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
364 out.println("% drawRoundRect()");
365 RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width,
368 setStroke(ordinaryStroke);
370 setStroke(currentStroke);
373 public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
376 out.println("% fillRoundRect()");
377 RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width,
383 public void drawArc(int x, int y, int width, int height, int startAngle,
386 setStroke(ordinaryStroke);
387 draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN));
388 setStroke(currentStroke);
391 public void fillArc(int x, int y, int width, int height, int startAngle,
394 fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE));
397 public void fillOval(int x, int y, int width, int height)
399 out.println("% fillOval()");
400 fill( new Ellipse2D.Double(x, y, width, height) );
403 public void fillPolygon(int[] x, int[] y, int nPoints)
405 out.println("% fillPolygon()");
406 fill( new Polygon(x, y, nPoints) );
409 public void drawLine(int x1, int y1, int x2, int y2)
411 out.println("% drawLine()");
412 setStroke(ordinaryStroke);
413 out.println("newpath");
414 out.println(x1 + " " + (y1) + " moveto");
415 out.println(x2 + " " + (y2) + " lineto");
416 out.println("stroke");
417 setStroke(currentStroke);
420 //--------------- Image drawing ------------------------------------------
421 public boolean drawImage(Image img, int x, int y, Color bgcolor,
422 ImageObserver observer)
424 int w = img.getWidth(null);
425 int h = img.getHeight(null);
427 return drawImage(img, x, y, x + w, y + h, 0, 0, w - 1, h - 1, bgcolor,
431 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
432 int sx1, int sy1, int sx2, int sy2, Color bgcolor,
433 ImageObserver observer)
436 boolean flipx = false;
437 boolean flipy = false;
469 int sw = sx2 - sx1; // source width
470 int sh = sy2 - sy1; // source height
471 int[] pixels = new int[sw * sh]; // pixel buffer
472 int dw = dx2 - dx1; // destination width
473 int dh = dy2 - dy1; // destination height
474 double x_scale = ((double) dw) / ((double) sw);
475 double y_scale = ((double) dh) / ((double) sh);
477 out.println("% drawImage() 2");
478 out.println("gsave");
479 out.println(dx1 + " " + dy1 + " translate");
480 out.println(dw + " " + dh + " scale");
481 out.println(sw + " " + sh + " 8 [" + (flipx ? -sw : sw) + " 0 0 "
482 + (flipy ? -sh : sh) + " " + (flipx ? sw : 0) + " "
483 + (flipy ? sh : 0) + " ]");
484 out.println("{currentfile 3 string readhexstring pop} bind");
485 out.println("false 3 colorimage");
487 PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sw, sh, pixels, 0, sw);
492 catch (InterruptedException e)
494 System.err.println("interrupted waiting for pixels!");
498 if ((pg.getStatus() & ImageObserver.ABORT) != 0)
500 System.err.println("image fetch aborted or errored");
504 for (int j = 0; j < sh; j++)
506 for (int i = 0; i < sw; i++)
508 out.print(colorTripleHex(new Color(pixels[j * sw + i])));
509 if (((++n) % 11) == 0)
515 out.println("%%EOF");
516 out.println("grestore");
520 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
521 int sx1, int sy1, int sx2, int sy2,
522 ImageObserver observer)
524 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
528 public boolean drawImage(Image img, int x, int y, ImageObserver observer)
530 return drawImage(img, x, y, null, observer);
533 public boolean drawImage(Image img, int x, int y, int width, int height,
534 Color bgcolor, ImageObserver observer)
536 int sw = img.getWidth(null);
537 int sh = img.getHeight(null);
538 return drawImage(img, x, y, x + width, y + height, /* destination */
539 0, 0, sw - 1, sh - 1, /* source */
544 public boolean drawImage(Image img, int x, int y, int width, int height,
545 ImageObserver observer)
547 return drawImage(img, x, y, width, height, null, observer);
550 /** Renders a BufferedImage that is filtered with a BufferedImageOp. */
551 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
553 BufferedImage result = op.filter(img, null);
554 drawImage(result, x, y, null);
557 /** Renders an image, applying a transform from image space
558 into user space before drawing. */
559 public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs)
561 AffineTransform oldTransform = new AffineTransform(currentTransform);
565 ret = drawImage(img, 0, 0, null, obs);
566 setTransform(oldTransform);
571 /** Renders a RenderableImage, applying a transform from image
572 space into user space before drawing. */
573 public void drawRenderableImage(RenderableImage img, AffineTransform xform)
578 /** Renders a RenderedImage, applying a transform from
579 image space into user space before drawing. */
580 public void drawRenderedImage(RenderedImage img, AffineTransform xform)
585 //-------------------------------------------------------------------------
586 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
588 setStroke(ordinaryStroke);
589 draw(new Polygon(xPoints, yPoints, nPoints));
590 setStroke(currentStroke);
593 public void drawString(String str, int x, int y)
595 drawString(str, (float) x, (float) y);
598 public void drawString(String str, float x, float y)
600 if( str.trim().equals("") )
601 return; // don't draw whitespace, silly!
603 if( currentFontIsPS )
605 drawStringPSFont(str, x, y);
609 TextLayout text = new TextLayout(str, currentFont, getFontRenderContext());
610 Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y));
614 private void drawStringPSFont(String str, float x, float y)
616 out.println("% drawString PS font");
617 out.println(x + " " + y + " moveto");
619 out.println("(" + str + ") show");
623 private void saveAndInvertAxis()
625 // Invert the Y axis of the CTM.
631 pageTransform.getScaleX(), pageTransform.getShearY(),
632 pageTransform.getShearX(), pageTransform.getScaleY(),
633 pageTransform.getTranslateX(),
634 -pageTransform.getTranslateY() + pageY
639 currentTransform.getScaleX(),
640 currentTransform.getShearY(),
641 -currentTransform.getShearX(),
642 -currentTransform.getScaleY(),
643 currentTransform.getTranslateX(),
644 currentTransform.getTranslateY()
647 AffineTransform total = new AffineTransform(test);
648 total.concatenate(new AffineTransform(test2));
652 private void restoreAxis()
657 AffineTransform total = new AffineTransform(pageTransform);
658 total.concatenate(currentTransform);
663 * special drawing routine for string shapes,
664 * which need to be drawn with the Y axis uninverted.
666 private void drawStringShape(Shape s)
670 // draw the shape s with an inverted Y axis.
671 PathIterator pi = s.getPathIterator(new AffineTransform());
672 float[] coords = new float[6];
674 while (! pi.isDone())
676 switch (pi.currentSegment(coords))
678 case PathIterator.SEG_MOVETO:
679 out.println((coords[0]) + " " + (Y - coords[1]) + " moveto");
683 case PathIterator.SEG_LINETO:
684 out.println((coords[0]) + " " + (Y - coords[1]) + " lineto");
688 case PathIterator.SEG_QUADTO:
689 // convert to cubic bezier points
690 float x1 = (cx + 2 * coords[0]) / 3;
691 float y1 = (cy + 2 * coords[1]) / 3;
692 float x2 = (2 * coords[2] + coords[0]) / 3;
693 float y2 = (2 * coords[3] + coords[1]) / 3;
695 out.print((x1) + " " + (Y - y1) + " ");
696 out.print((x2) + " " + (Y - y2) + " ");
697 out.println((coords[2]) + " " + (Y - coords[3]) + " curveto");
701 case PathIterator.SEG_CUBICTO:
702 out.print((coords[0]) + " " + (Y - coords[1]) + " ");
703 out.print((coords[2]) + " " + (Y - coords[3]) + " ");
704 out.println((coords[4]) + " " + (Y - coords[5]) + " curveto");
708 case PathIterator.SEG_CLOSE:
709 out.println("closepath");
719 public void setColor(Color c)
721 /* don't set the color if it's already set */
722 if (c.equals(currentColor))
726 currentPaint = c; // Graphics2D extends colors to paint
728 out.println(colorTriple(c) + " setrgbcolor");
731 public void clearRect(int x, int y, int width, int height)
733 out.println("% clearRect");
734 Color c = currentColor;
735 setColor(backgroundColor);
736 fill(new Rectangle2D.Double(x, y, width, height));
740 public void clipRect(int x, int y, int width, int height)
742 clip(new Rectangle2D.Double(x, y, width, height));
745 public void copyArea(int x, int y, int width, int height, int dx, int dy)
750 public void fillRect(int x, int y, int width, int height)
752 fill(new Rectangle2D.Double(x, y, width, height));
755 public void dispose()
759 public void setClip(int x, int y, int width, int height)
761 out.println("% setClip()");
762 setClip(new Rectangle2D.Double(x, y, width, height));
765 public void setClip(Shape s)
770 public Shape getClip()
775 public Rectangle getClipBounds()
777 return clipShape.getBounds();
780 public Color getColor()
785 public Font getFont()
790 public FontMetrics getFontMetrics()
792 return getFontMetrics(currentFont);
795 public FontMetrics getFontMetrics(Font f)
801 public void setFont(Font font)
803 out.println("% setfont()");
805 // use the default font
806 font = new Font("Dialog", Font.PLAIN, 12);
808 setPSFont(); // set up the PostScript fonts
812 * Setup the postscript font if the current font is one
814 private void setPSFont()
816 currentFontIsPS = false;
818 String s = currentFont.getName();
819 out.println("% setPSFont: Fontname: " + s);
820 if (s.equalsIgnoreCase("Helvetica") || s.equalsIgnoreCase("SansSerif"))
821 out.print("/helveticaISO findfont ");
822 else if (s.equalsIgnoreCase("Times New Roman"))
823 out.print("/timesISO findfont ");
824 else if (s.equalsIgnoreCase("Courier"))
825 out.print("/courierISO findfont ");
829 currentFontIsPS = true;
831 out.print(currentFont.getSize() + " scalefont ");
832 out.println("setfont");
835 /** XOR mode is not supported */
836 public void setPaintMode()
840 /** XOR mode is not supported */
841 public void setXORMode(Color c1)
847 out.println("showpage");
848 out.println("%%Trailer");
849 out.println("grestore % restore original stuff");
850 out.println("%%EOF");
862 //----------------------------------------------------------------
863 // Graphics2D stuff ----------------------------------------------
865 /** Sets the values of an arbitrary number of
866 preferences for the rendering algorithms. */
867 public void addRenderingHints(Map hints)
869 /* rendering hint changes are disallowed */
872 /** write a shape to the file */
873 private void writeShape(Shape s)
875 PathIterator pi = s.getPathIterator(new AffineTransform());
876 float[] coords = new float[6];
878 while (! pi.isDone())
880 switch (pi.currentSegment(coords))
882 case PathIterator.SEG_MOVETO:
883 out.println(coords[0] + " " + (coords[1]) + " moveto");
887 case PathIterator.SEG_LINETO:
888 out.println(coords[0] + " " + (coords[1]) + " lineto");
892 case PathIterator.SEG_QUADTO:
893 // convert to cubic bezier points
894 float x1 = (cx + 2 * coords[0]) / 3;
895 float y1 = (cy + 2 * coords[1]) / 3;
896 float x2 = (2 * coords[2] + coords[0]) / 3;
897 float y2 = (2 * coords[3] + coords[1]) / 3;
899 out.print(x1 + " " + (Y - y1) + " ");
900 out.print(x2 + " " + (Y - y2) + " ");
901 out.println(coords[2] + " " + (Y - coords[3]) + " curveto");
905 case PathIterator.SEG_CUBICTO:
906 out.print(coords[0] + " " + coords[1] + " ");
907 out.print(coords[2] + " " + coords[3] + " ");
908 out.println(coords[4] + " " + coords[5] + " curveto");
912 case PathIterator.SEG_CLOSE:
913 out.println("closepath");
920 /** Intersects the current Clip with the interior of
921 the specified Shape and sets the Clip to the resulting intersection. */
922 public void clip(Shape s)
925 out.println("% clip INACTIVE");
927 // out.println("clip");
930 /** Strokes the outline of a Shape using the
931 settings of the current Graphics2D context.*/
932 public void draw(Shape s)
934 if(!(currentStroke instanceof BasicStroke))
935 fill(currentStroke.createStrokedShape(s));
937 out.println("% draw");
939 out.println("stroke");
942 /** Renders the text of the specified GlyphVector using the
943 Graphics2D context's rendering attributes. */
944 public void drawGlyphVector(GlyphVector gv, float x, float y)
946 out.println("% drawGlyphVector");
947 Shape s = gv.getOutline();
948 drawStringShape(AffineTransform.getTranslateInstance(x, y)
949 .createTransformedShape(s));
952 /** Renders the text of the specified iterator,
953 using the Graphics2D context's current Paint.*/
954 public void drawString(AttributedCharacterIterator iterator, float x, float y)
956 TextLayout text = new TextLayout(iterator, getFontRenderContext());
957 Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y));
961 /** Renders the text of the specified iterator,
962 using the Graphics2D context's current Paint. */
963 public void drawString(AttributedCharacterIterator iterator, int x, int y)
965 drawString(iterator, (float) x, (float) y);
968 /** Fills the interior of a Shape using the settings of the Graphics2D context. */
969 public void fill(Shape s)
971 out.println("% fill");
979 out.println("gsave");
983 out.println("shfill");
984 out.println("grestore");
988 /** Returns the background color used for clearing a region. */
989 public Color getBackground()
991 return backgroundColor;
994 /** Returns the current Composite in the Graphics2D context. */
995 public Composite getComposite()
1001 /** Returns the device configuration associated with this Graphics2D. */
1002 public GraphicsConfiguration getDeviceConfiguration()
1005 out.println("% getDeviceConfiguration()");
1009 /** Get the rendering context of the Font within this Graphics2D context. */
1010 public FontRenderContext getFontRenderContext()
1012 out.println("% getFontRenderContext()");
1016 pageTransform.getScaleX(), 0, 0,
1017 -pageTransform.getScaleY(), 0, 0
1020 return (new FontRenderContext(new AffineTransform(scaling), false, true));
1023 /** Returns the current Paint of the Graphics2D context. */
1024 public Paint getPaint()
1026 return currentPaint;
1029 /** Returns the value of a single preference for the rendering algorithms. */
1030 public Object getRenderingHint(RenderingHints.Key hintKey)
1032 return renderingHints.get(hintKey);
1035 /** Gets the preferences for the rendering algorithms. */
1036 public RenderingHints getRenderingHints()
1038 return renderingHints;
1041 /** Returns the current Stroke in the Graphics2D context. */
1042 public Stroke getStroke()
1044 return currentStroke;
1047 /** Returns a copy of the current Transform in the Graphics2D context. */
1048 public AffineTransform getTransform()
1050 return currentTransform;
1054 * Checks whether or not the specified Shape intersects
1055 * the specified Rectangle, which is in device space.
1057 public boolean hit(Rectangle rect, Shape s, boolean onStroke)
1059 Rectangle2D.Double r = new Rectangle2D.Double(rect.getX(), rect.getY(),
1062 return s.intersects(r);
1065 /** Sets the background color for the Graphics2D context.*/
1066 public void setBackground(Color color)
1068 out.println("% setBackground(" + color + ")");
1069 backgroundColor = color;
1072 /** Sets the Composite for the Graphics2D context.
1074 public void setComposite(Composite comp)
1078 /** Sets the Paint attribute for the Graphics2D context.*/
1079 public void setPaint(Paint paint)
1081 currentPaint = paint;
1083 if (paint instanceof Color)
1085 setColor((Color) paint);
1088 if (paint instanceof GradientPaint)
1095 /* get a space seperated 0.0 - 1.0 color RGB triple */
1096 private String colorTriple(Color c)
1098 return (((double) c.getRed() / 255.0) + " "
1099 + ((double) c.getGreen() / 255.0) + " "
1100 + ((double) c.getBlue() / 255.0));
1104 * Get a nonsperated hex RGB triple, eg FFFFFF = white
1105 * used by writeGradient and drawImage
1107 private String colorTripleHex(Color c)
1109 String r = "00" + Integer.toHexString(c.getRed());
1110 r = r.substring(r.length() - 2);
1111 String g = "00" + Integer.toHexString(c.getGreen());
1112 g = g.substring(g.length() - 2);
1113 String b = "00" + Integer.toHexString(c.getBlue());
1114 b = b.substring(b.length() - 2);
1118 /* write the current gradient fill */
1119 private void writeGradient()
1121 GradientPaint paint = (GradientPaint) currentPaint;
1122 out.println("% writeGradient()");
1129 Point2D p1 = currentTransform.transform(paint.getPoint1(), null);
1130 Point2D p2 = currentTransform.transform(paint.getPoint2(), null);
1136 // get number of repetitions
1137 while (x + n * dx < pageY && y + n * dy < pageX && x + n * dx > 0
1141 out.println("<<"); // start
1142 out.println("/ShadingType 2"); // gradient fill
1143 out.println("/ColorSpace [ /DeviceRGB ]"); // RGB colors
1144 out.print("/Coords [");
1145 out.print(x + " " + y + " " + (x + n * dx) + " " + (y + n * dy) + " ");
1146 out.println("]"); // coordinates defining the axis
1147 out.println("/Function <<");
1148 out.println("/FunctionType 0");
1149 out.println("/Order 1");
1150 out.println("/Domain [ 0 1 ]");
1151 out.println("/Range [ 0 1 0 1 0 1 ]");
1152 out.println("/BitsPerSample 8");
1153 out.println("/Size [ " + (1 + n) + " ]");
1154 out.print("/DataSource < " + colorTripleHex(paint.getColor1()) + " "
1155 + colorTripleHex(paint.getColor2()) + " ");
1157 if (paint.isCyclic())
1160 out.print(colorTripleHex(paint.getColor1()) + " ");
1162 out.print(colorTripleHex(paint.getColor2()) + " ");
1165 out.print(colorTripleHex(paint.getColor2()) + " ");
1171 /** Sets the value of a single preference for the rendering algorithms. */
1172 public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
1174 /* we don't allow the changing of rendering hints. */
1177 /** Replaces the values of all preferences for the rendering algorithms
1178 with the specified hints. */
1179 public void setRenderingHints(Map hints)
1181 /* we don't allow the changing of rendering hints. */
1185 * Sets the Stroke for the Graphics2D context. BasicStroke fully implemented.
1187 public void setStroke(Stroke s)
1191 if (! (s instanceof BasicStroke))
1194 BasicStroke bs = (BasicStroke) s;
1195 out.println("% setStroke()");
1198 // set the line width
1199 out.println(bs.getLineWidth() + " setlinewidth");
1201 // set the line dash
1202 float[] dashArray = bs.getDashArray();
1203 if (dashArray != null)
1206 for (int i = 0; i < dashArray.length; i++)
1207 out.print(dashArray[i] + " ");
1208 out.println("] " + bs.getDashPhase() + " setdash");
1211 out.println("[] 0 setdash"); // set solid
1214 switch (bs.getEndCap())
1216 case BasicStroke.CAP_BUTT:
1217 out.println("0 setlinecap");
1219 case BasicStroke.CAP_ROUND:
1220 out.println("1 setlinecap");
1222 case BasicStroke.CAP_SQUARE:
1223 out.println("2 setlinecap");
1227 // set the line join
1228 switch (bs.getLineJoin())
1230 case BasicStroke.JOIN_BEVEL:
1231 out.println("2 setlinejoin");
1233 case BasicStroke.JOIN_MITER:
1234 out.println("0 setlinejoin");
1235 out.println(bs.getMiterLimit() + " setmiterlimit");
1237 case BasicStroke.JOIN_ROUND:
1238 out.println("1 setlinejoin");
1244 out.println("% Exception in setStroke()");
1248 //////////////////// TRANSFORM SETTING /////////////////////////////////////
1249 private void concatCTM(AffineTransform Tx)
1251 double[] matrixElements = new double[6];
1252 Tx.getMatrix(matrixElements);
1255 for (int i = 0; i < 6; i++)
1256 out.print(matrixElements[i] + " ");
1257 out.println("] concat");
1260 /** Sets the Transform in the Graphics2D context. */
1261 public void setTransform(AffineTransform Tx)
1263 // set the transformation matrix;
1264 currentTransform = Tx;
1266 // concatenate the current transform and the page transform
1267 AffineTransform totalTransform = new AffineTransform(pageTransform);
1268 totalTransform.concatenate(currentTransform);
1269 out.println("% setTransform()");
1270 out.println("% pageTransform:" + pageTransform);
1271 out.println("% currentTransform:" + currentTransform);
1272 out.println("% totalTransform:" + totalTransform);
1275 pushCTM(); // set the CTM to it's original state
1276 concatCTM(totalTransform); // apply our transforms
1279 /** Composes an AffineTransform object with the Transform
1280 in this Graphics2D according to the rule last-specified-first-applied. */
1281 public void transform(AffineTransform Tx)
1283 // concatenate the current transform
1284 currentTransform.concatenate(Tx);
1289 ////////////////////////// TRANSFORMS //////////////////////////////////////
1291 /** shear transform */
1292 public void shear(double shx, double shy)
1294 out.println("% shear()");
1295 AffineTransform Tx = new AffineTransform();
1300 /** Translates the origin of the Graphics2D context
1301 to the point (x, y) in the current coordinate system. */
1302 public void translate(int x, int y)
1304 out.println("% translate()");
1305 AffineTransform Tx = new AffineTransform();
1310 /** Translates the origin of the Graphics2D context
1311 to the point (x, y) in the current coordinate system. */
1312 public void translate(double x, double y)
1314 out.println("% translate(" + x + ", " + y + ")");
1315 AffineTransform Tx = new AffineTransform();
1320 /** Concatenates the current Graphics2D Transform with a rotation transform.*/
1321 public void rotate(double theta)
1323 out.println("% rotate(" + theta + ")");
1324 AffineTransform Tx = new AffineTransform();
1329 /** Concatenates the current Graphics2D Transform with
1330 a translated rotation transform.*/
1331 public void rotate(double theta, double x, double y)
1333 out.println("% rotate()");
1334 AffineTransform Tx = new AffineTransform();
1335 Tx.rotate(theta, x, y);
1339 /** Concatenates the current Graphics2D Transform with a scaling
1340 transformation Subsequent rendering is resized according to the
1341 specified scaling factors relative to the previous scaling.*/
1342 public void scale(double sx, double sy)
1344 out.println("% scale(" + sx + ", " + sy + ")");
1345 AffineTransform Tx = new AffineTransform();