2 Copyright Paul James Mutton, 2001-2004, http://www.jibble.org/
4 This file is part of EpsGraphics2D.
6 This software is dual-licensed, allowing you to choose between the GNU
7 General Public License (GPL) and the www.jibble.org Commercial License.
8 Since the GPL may be too restrictive for use in a proprietary application,
9 a commercial license is also provided. Full license information can be
10 found at http://www.jibble.org/licenses/
17 package org.jibble.epsgraphics;
24 import java.awt.font.*;
25 import java.awt.geom.*;
26 import java.awt.image.*;
27 import java.awt.image.renderable.*;
30 * EpsGraphics2D is suitable for creating high quality EPS graphics for use in
31 * documents and papers, and can be used just like a standard Graphics2D object.
33 * Many Java programs use Graphics2D to draw stuff on the screen, and while it
34 * is easy to save the output as a png or jpeg file, it is a little harder to
35 * export it as an EPS for including in a document or paper.
37 * This class makes the whole process extremely easy, because you can use it as
38 * if it's a Graphics2D object. The only difference is that all of the
39 * implemented methods create EPS output, which means the diagrams you draw can
40 * be resized without leading to any of the jagged edges you may see when
41 * resizing pixel-based images, such as jpeg and png files.
47 * Graphics2D g = new EpsGraphics2D();
48 * g.setColor(Color.black);
50 * // Line thickness 2.
51 * g.setStroke(new BasicStroke(2.0f));
54 * g.drawLine(10, 10, 50, 10);
56 * // Fill a rectangle in blue
57 * g.setColor(Color.blue);
58 * g.fillRect(10, 0, 20, 20);
60 * // Get the EPS output.
61 * String output = g.toString();
65 * You do not need to worry about the size of the canvas when drawing on a
66 * EpsGraphics2D object. The bounding box of the EPS document will automatically
67 * resize to accomodate new items that you draw.
69 * Not all methods are implemented yet. Those that are not are clearly labelled.
71 * Copyright Paul Mutton, <a
72 * href="http://www.jibble.org/">http://www.jibble.org/</a>
75 public class EpsGraphics2D extends java.awt.Graphics2D
78 public static final String VERSION = "0.8.8";
81 * Constructs a new EPS document that is initially empty and can be drawn on
82 * like a Graphics2D object. The EPS document is stored in memory.
84 public EpsGraphics2D()
90 * Constructs a new EPS document that is initially empty and can be drawn on
91 * like a Graphics2D object. The EPS document is stored in memory.
93 public EpsGraphics2D(String title)
95 _document = new EpsDocument(title);
96 _backgroundColor = Color.white;
98 _transform = new AffineTransform();
99 _clipTransform = new AffineTransform();
100 _accurateTextMode = true;
101 setColor(Color.black);
102 setPaint(Color.black);
103 setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
104 setFont(Font.decode(null));
105 setStroke(new BasicStroke());
109 * Constructs a new EPS document that is initially empty and can be drawn on
110 * like a Graphics2D object. The EPS document is written to the file as it
111 * goes, which reduces memory usage. The bounding box of the document is fixed
112 * and specified at construction time by minX,minY,maxX,maxY. The file is
113 * flushed and closed when the close() method is called.
115 public EpsGraphics2D(String title, File file, int minX, int minY,
116 int maxX, int maxY) throws IOException
118 this(title, new FileOutputStream(file), minX, minY, maxX, maxY);
122 * Constructs a new EPS document that is initially empty and can be drawn on
123 * like a Graphics2D object. The EPS document is written to the output stream
124 * as it goes, which reduces memory usage. The bounding box of the document is
125 * fixed and specified at construction time by minX,minY,maxX,maxY. The output
126 * stream is flushed and closed when the close() method is called.
128 public EpsGraphics2D(String title, OutputStream outputStream, int minX,
129 int minY, int maxX, int maxY) throws IOException
132 _document = new EpsDocument(title, outputStream, minX, minY, maxX, maxY);
136 * Constructs a new EpsGraphics2D instance that is a copy of the supplied
137 * argument and points at the same EpsDocument.
139 protected EpsGraphics2D(EpsGraphics2D g)
141 _document = g._document;
142 _backgroundColor = g._backgroundColor;
144 _clipTransform = (AffineTransform) g._clipTransform.clone();
145 _transform = (AffineTransform) g._transform.clone();
148 _composite = g._composite;
151 _accurateTextMode = g._accurateTextMode;
155 * This method is called to indicate that a particular method is not supported
156 * yet. The stack trace is printed to the standard output.
158 private void methodNotSupported()
160 EpsException e = new EpsException(
161 "Method not currently supported by EpsGraphics2D version "
163 e.printStackTrace(System.err);
166 // ///////////// Specialist methods ///////////////////////
169 * Sets whether to use accurate text mode when rendering text in EPS. This is
170 * enabled (true) by default. When accurate text mode is used, all text will
171 * be rendered in EPS to appear exactly the same as it would do when drawn
172 * with a Graphics2D context. With accurate text mode enabled, it is not
173 * necessary for the EPS viewer to have the required font installed.
175 * Turning off accurate text mode will require the EPS viewer to have the
176 * necessary fonts installed. If you are using a lot of text, you will find
177 * that this significantly reduces the file size of your EPS documents.
178 * AffineTransforms can only affect the starting point of text using this
179 * simpler text mode - all text will be horizontal.
181 public void setAccurateTextMode(boolean b)
183 _accurateTextMode = b;
187 * Returns whether accurate text mode is being used.
189 public boolean getAccurateTextMode()
191 return _accurateTextMode;
195 * Flushes the buffered contents of this EPS document to the underlying
196 * OutputStream it is being written to.
198 public void flush() throws IOException
204 * Closes the EPS file being output to the underlying OutputStream. The
205 * OutputStream is automatically flushed before being closed. If you forget to
206 * do this, the file may be incomplete.
208 public void close() throws IOException
215 * Appends a line to the EpsDocument.
217 private void append(String line)
219 _document.append(this, line);
223 * Returns the point after it has been transformed by the transformation.
225 private Point2D transform(float x, float y)
227 Point2D result = new Point2D.Float(x, y);
228 result = _transform.transform(result, result);
229 result.setLocation(result.getX(), -result.getY());
234 * Appends the commands required to draw a shape on the EPS document.
236 private void draw(Shape s, String action)
242 // Rectangle2D userBounds = s.getBounds2D();
243 if (!_transform.isIdentity())
245 s = _transform.createTransformedShape(s);
248 // Update the bounds.
249 if (!action.equals("clip"))
251 Rectangle2D shapeBounds = s.getBounds2D();
252 Rectangle2D visibleBounds = shapeBounds;
255 Rectangle2D clipBounds = _clip.getBounds2D();
256 visibleBounds = shapeBounds.createIntersection(clipBounds);
258 float lineRadius = _stroke.getLineWidth() / 2;
259 float minX = (float) visibleBounds.getMinX() - lineRadius;
260 float minY = (float) visibleBounds.getMinY() - lineRadius;
261 float maxX = (float) visibleBounds.getMaxX() + lineRadius;
262 float maxY = (float) visibleBounds.getMaxY() + lineRadius;
263 _document.updateBounds(minX, -minY);
264 _document.updateBounds(maxX, -maxY);
269 float[] coords = new float[6];
270 PathIterator it = s.getPathIterator(null);
276 type = it.currentSegment(coords);
277 float x1 = coords[0];
278 float y1 = -coords[1];
279 float x2 = coords[2];
280 float y2 = -coords[3];
281 float x3 = coords[4];
282 float y3 = -coords[5];
284 if (type == PathIterator.SEG_CLOSE)
289 else if (type == PathIterator.SEG_CUBICTO)
291 append(x1 + " " + y1 + " " + x2 + " " + y2 + " " + x3 + " " + y3
297 else if (type == PathIterator.SEG_LINETO)
299 append(x1 + " " + y1 + " lineto");
304 else if (type == PathIterator.SEG_MOVETO)
306 append(x1 + " " + y1 + " moveto");
311 else if (type == PathIterator.SEG_QUADTO)
313 // Convert the quad curve into a cubic.
314 float _x1 = x0 + 2 / 3f * (x1 - x0);
315 float _y1 = y0 + 2 / 3f * (y1 - y0);
316 float _x2 = x1 + 1 / 3f * (x2 - x1);
317 float _y2 = y1 + 1 / 3f * (y2 - y1);
320 append(_x1 + " " + _y1 + " " + _x2 + " " + _y2 + " " + _x3 + " "
326 else if (type == PathIterator.WIND_EVEN_ODD)
330 else if (type == PathIterator.WIND_NON_ZERO)
342 * Returns a hex string that always contains two characters.
344 private String toHexString(int n)
346 String result = Integer.toString(n, 16);
347 while (result.length() < 2)
349 result = "0" + result;
354 // ///////////// Graphics2D methods ///////////////////////
357 * Draws a 3D rectangle outline. If it is raised, light appears to come from
360 public void draw3DRect(int x, int y, int width, int height, boolean raised)
362 Color originalColor = getColor();
363 Stroke originalStroke = getStroke();
365 setStroke(new BasicStroke(1.0f));
369 setColor(originalColor.brighter());
373 setColor(originalColor.darker());
376 drawLine(x, y, x + width, y);
377 drawLine(x, y, x, y + height);
381 setColor(originalColor.darker());
385 setColor(originalColor.brighter());
388 drawLine(x + width, y + height, x, y + height);
389 drawLine(x + width, y + height, x + width, y);
391 setColor(originalColor);
392 setStroke(originalStroke);
396 * Fills a 3D rectangle. If raised, it has bright fill and light appears to
397 * come from the top left.
399 public void fill3DRect(int x, int y, int width, int height, boolean raised)
401 Color originalColor = getColor();
405 setColor(originalColor.brighter());
409 setColor(originalColor.darker());
411 draw(new Rectangle(x, y, width, height), "fill");
412 setColor(originalColor);
413 draw3DRect(x, y, width, height, raised);
417 * Draws a Shape on the EPS document.
419 public void draw(Shape s)
425 * Draws an Image on the EPS document.
427 public boolean drawImage(Image img, AffineTransform xform,
430 AffineTransform at = getTransform();
432 boolean st = drawImage(img, 0, 0, obs);
438 * Draws a BufferedImage on the EPS document.
440 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
442 BufferedImage img1 = op.filter(img, null);
443 drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null);
447 * Draws a RenderedImage on the EPS document.
449 public void drawRenderedImage(RenderedImage img, AffineTransform xform)
451 Hashtable properties = new Hashtable();
452 String[] names = img.getPropertyNames();
453 for (int i = 0; i < names.length; i++)
455 properties.put(names[i], img.getProperty(names[i]));
458 ColorModel cm = img.getColorModel();
459 WritableRaster wr = img.copyData(null);
460 BufferedImage img1 = new BufferedImage(cm, wr, cm
461 .isAlphaPremultiplied(), properties);
462 AffineTransform at = AffineTransform.getTranslateInstance(
463 img.getMinX(), img.getMinY());
464 at.preConcatenate(xform);
465 drawImage(img1, at, null);
469 * Draws a RenderableImage by invoking its createDefaultRendering method.
471 public void drawRenderableImage(RenderableImage img, AffineTransform xform)
473 drawRenderedImage(img.createDefaultRendering(), xform);
477 * Draws a string at (x,y)
479 public void drawString(String str, int x, int y)
481 drawString(str, (float) x, (float) y);
485 * Draws a string at (x,y)
487 public void drawString(String s, float x, float y)
489 if (s != null && s.length() > 0)
491 AttributedString as = new AttributedString(s);
492 as.addAttribute(TextAttribute.FONT, getFont());
493 drawString(as.getIterator(), x, y);
498 * Draws the characters of an AttributedCharacterIterator, starting from
501 public void drawString(AttributedCharacterIterator iterator, int x, int y)
503 drawString(iterator, (float) x, (float) y);
507 * Draws the characters of an AttributedCharacterIterator, starting from
510 public void drawString(AttributedCharacterIterator iterator, float x,
513 if (getAccurateTextMode())
515 TextLayout layout = new TextLayout(iterator, getFontRenderContext());
516 Shape shape = layout.getOutline(AffineTransform.getTranslateInstance(
523 Point2D location = transform(x, y);
524 append(location.getX() + " " + location.getY() + " moveto");
525 StringBuffer buffer = new StringBuffer();
526 for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator
529 if (ch == '(' || ch == ')')
535 append("(" + buffer.toString() + ") show");
540 * Draws a GlyphVector at (x,y)
542 public void drawGlyphVector(GlyphVector g, float x, float y)
544 Shape shape = g.getOutline(x, y);
549 * Fills a Shape on the EPS document.
551 public void fill(Shape s)
557 * Checks whether or not the specified Shape intersects the specified
558 * Rectangle, which is in device space.
560 public boolean hit(Rectangle rect, Shape s, boolean onStroke)
562 return s.intersects(rect);
566 * Returns the device configuration associated with this EpsGraphics2D object.
568 public GraphicsConfiguration getDeviceConfiguration()
570 GraphicsConfiguration gc = null;
571 GraphicsEnvironment ge = GraphicsEnvironment
572 .getLocalGraphicsEnvironment();
573 GraphicsDevice[] gds = ge.getScreenDevices();
574 for (int i = 0; i < gds.length; i++)
576 GraphicsDevice gd = gds[i];
577 GraphicsConfiguration[] gcs = gd.getConfigurations();
587 * Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does not
590 public void setComposite(Composite comp)
596 * Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
597 * of type Color are respected by EpsGraphics2D.
599 public void setPaint(Paint paint)
602 if (paint instanceof Color)
604 setColor((Color) paint);
609 * Sets the stroke. Only accepts BasicStroke objects (or subclasses of
612 public void setStroke(Stroke s)
614 if (s instanceof BasicStroke)
616 _stroke = (BasicStroke) s;
618 append(_stroke.getLineWidth() + " setlinewidth");
619 float miterLimit = _stroke.getMiterLimit();
620 if (miterLimit < 1.0f)
624 append(miterLimit + " setmiterlimit");
625 append(_stroke.getLineJoin() + " setlinejoin");
626 append(_stroke.getEndCap() + " setlinecap");
628 StringBuffer dashes = new StringBuffer();
630 float[] dashArray = _stroke.getDashArray();
631 if (dashArray != null)
633 for (int i = 0; i < dashArray.length; i++)
635 dashes.append((dashArray[i]) + " ");
639 append(dashes.toString() + " 0 setdash");
644 * Sets a rendering hint. These are not used by EpsGraphics2D.
646 public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
652 * Returns the value of a single preference for the rendering algorithms.
653 * Rendering hints are not used by EpsGraphics2D.
655 public Object getRenderingHint(RenderingHints.Key hintKey)
661 * Sets the rendering hints. These are ignored by EpsGraphics2D.
663 public void setRenderingHints(Map hints)
669 * Adds rendering hints. These are ignored by EpsGraphics2D.
671 public void addRenderingHints(Map hints)
677 * Returns the preferences for the rendering algorithms.
679 public RenderingHints getRenderingHints()
681 return new RenderingHints(null);
685 * Translates the origin of the EpsGraphics2D context to the point (x,y) in
686 * the current coordinate system.
688 public void translate(int x, int y)
690 translate((double) x, (double) y);
694 * Concatenates the current EpsGraphics2D Transformation with a translation
697 public void translate(double tx, double ty)
699 transform(AffineTransform.getTranslateInstance(tx, ty));
703 * Concatenates the current EpsGraphics2D Transform with a rotation transform.
705 public void rotate(double theta)
711 * Concatenates the current EpsGraphics2D Transform with a translated rotation
714 public void rotate(double theta, double x, double y)
716 transform(AffineTransform.getRotateInstance(theta, x, y));
720 * Concatenates the current EpsGraphics2D Transform with a scaling
723 public void scale(double sx, double sy)
725 transform(AffineTransform.getScaleInstance(sx, sy));
729 * Concatenates the current EpsGraphics2D Transform with a shearing transform.
731 public void shear(double shx, double shy)
733 transform(AffineTransform.getShearInstance(shx, shy));
737 * Composes an AffineTransform object with the Transform in this EpsGraphics2D
738 * according to the rule last-specified-first-applied.
740 public void transform(AffineTransform Tx)
742 _transform.concatenate(Tx);
743 setTransform(getTransform());
747 * Sets the AffineTransform to be used by this EpsGraphics2D.
749 public void setTransform(AffineTransform Tx)
753 _transform = new AffineTransform();
757 _transform = new AffineTransform(Tx);
759 // Need to update the stroke and font so they know the scale changed
760 setStroke(getStroke());
765 * Gets the AffineTransform used by this EpsGraphics2D.
767 public AffineTransform getTransform()
769 return new AffineTransform(_transform);
773 * Returns the current Paint of the EpsGraphics2D object.
775 public Paint getPaint()
781 * returns the current Composite of the EpsGraphics2D object.
783 public Composite getComposite()
789 * Sets the background color to be used by the clearRect method.
791 public void setBackground(Color color)
797 _backgroundColor = color;
801 * Gets the background color that is used by the clearRect method.
803 public Color getBackground()
805 return _backgroundColor;
809 * Returns the Stroke currently used. Guaranteed to be an instance of
812 public Stroke getStroke()
818 * Intersects the current clip with the interior of the specified Shape and
819 * sets the clip to the resulting intersection.
821 public void clip(Shape s)
829 Area area = new Area(_clip);
830 area.intersect(new Area(s));
836 * Returns the FontRenderContext.
838 public FontRenderContext getFontRenderContext()
840 return _fontRenderContext;
843 // ///////////// Graphics methods ///////////////////////
846 * Returns a new Graphics object that is identical to this EpsGraphics2D.
848 public Graphics create()
850 return new EpsGraphics2D(this);
854 * Returns an EpsGraphics2D object based on this Graphics object, but with a
855 * new translation and clip area.
857 public Graphics create(int x, int y, int width, int height)
859 Graphics g = create();
861 g.clipRect(0, 0, width, height);
866 * Returns the current Color. This will be a default value (black) until it is
867 * changed using the setColor method.
869 public Color getColor()
875 * Sets the Color to be used when drawing all future shapes, text, etc.
877 public void setColor(Color c)
884 append((c.getRed() / 255f) + " " + (c.getGreen() / 255f) + " "
885 + (c.getBlue() / 255f) + " setrgbcolor");
889 * Sets the paint mode of this EpsGraphics2D object to overwrite the
890 * destination EpsDocument with the current color.
892 public void setPaintMode()
894 // Do nothing - paint mode is the only method supported anyway.
898 * <b><i><font color="red">Not implemented</font></i></b> - performs no
901 public void setXORMode(Color c1)
903 methodNotSupported();
907 * Returns the Font currently being used.
909 public Font getFont()
915 * Sets the Font to be used in future text.
917 public void setFont(Font font)
921 font = Font.decode(null);
924 append("/" + _font.getPSName() + " findfont " + ((int) _font.getSize())
925 + " scalefont setfont");
929 * Gets the font metrics of the current font.
931 public FontMetrics getFontMetrics()
933 return getFontMetrics(getFont());
937 * Gets the font metrics for the specified font.
939 public FontMetrics getFontMetrics(Font f)
941 BufferedImage image = new BufferedImage(1, 1,
942 BufferedImage.TYPE_INT_RGB);
943 Graphics g = image.getGraphics();
944 return g.getFontMetrics(f);
948 * Returns the bounding rectangle of the current clipping area.
950 public Rectangle getClipBounds()
956 Rectangle rect = getClip().getBounds();
961 * Intersects the current clip with the specified rectangle.
963 public void clipRect(int x, int y, int width, int height)
965 clip(new Rectangle(x, y, width, height));
969 * Sets the current clip to the rectangle specified by the given coordinates.
971 public void setClip(int x, int y, int width, int height)
973 setClip(new Rectangle(x, y, width, height));
977 * Gets the current clipping area.
979 public Shape getClip()
989 AffineTransform t = _transform.createInverse();
990 t.concatenate(_clipTransform);
991 return t.createTransformedShape(_clip);
992 } catch (Exception e)
994 throw new EpsException("Unable to get inverse of matrix: "
1001 * Sets the current clipping area to an arbitrary clip shape.
1003 public void setClip(Shape clip)
1007 if (_document.isClipSet())
1014 _document.setClipSet(true);
1019 _clipTransform = (AffineTransform) _transform.clone();
1023 if (_document.isClipSet())
1026 _document.setClipSet(false);
1033 * <b><i><font color="red">Not implemented</font></i></b> - performs no
1036 public void copyArea(int x, int y, int width, int height, int dx, int dy)
1038 methodNotSupported();
1042 * Draws a straight line from (x1,y1) to (x2,y2).
1044 public void drawLine(int x1, int y1, int x2, int y2)
1046 Shape shape = new Line2D.Float(x1, y1, x2, y2);
1051 * Fills a rectangle with top-left corner placed at (x,y).
1053 public void fillRect(int x, int y, int width, int height)
1055 Shape shape = new Rectangle(x, y, width, height);
1056 draw(shape, "fill");
1060 * Draws a rectangle with top-left corner placed at (x,y).
1062 public void drawRect(int x, int y, int width, int height)
1064 Shape shape = new Rectangle(x, y, width, height);
1069 * Clears a rectangle with top-left corner placed at (x,y) using the current
1072 public void clearRect(int x, int y, int width, int height)
1074 Color originalColor = getColor();
1076 setColor(getBackground());
1077 Shape shape = new Rectangle(x, y, width, height);
1078 draw(shape, "fill");
1080 setColor(originalColor);
1084 * Draws a rounded rectangle.
1086 public void drawRoundRect(int x, int y, int width, int height,
1087 int arcWidth, int arcHeight)
1089 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1095 * Fills a rounded rectangle.
1097 public void fillRoundRect(int x, int y, int width, int height,
1098 int arcWidth, int arcHeight)
1100 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1102 draw(shape, "fill");
1108 public void drawOval(int x, int y, int width, int height)
1110 Shape shape = new Ellipse2D.Float(x, y, width, height);
1117 public void fillOval(int x, int y, int width, int height)
1119 Shape shape = new Ellipse2D.Float(x, y, width, height);
1120 draw(shape, "fill");
1126 public void drawArc(int x, int y, int width, int height, int startAngle,
1129 Shape shape = new Arc2D.Float(x, y, width, height, startAngle,
1130 arcAngle, Arc2D.OPEN);
1137 public void fillArc(int x, int y, int width, int height, int startAngle,
1140 Shape shape = new Arc2D.Float(x, y, width, height, startAngle,
1141 arcAngle, Arc2D.PIE);
1142 draw(shape, "fill");
1148 public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
1152 GeneralPath path = new GeneralPath();
1153 path.moveTo(xPoints[0], yPoints[0]);
1154 for (int i = 1; i < nPoints; i++)
1156 path.lineTo(xPoints[i], yPoints[i]);
1163 * Draws a polygon made with the specified points.
1165 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
1167 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1174 public void drawPolygon(Polygon p)
1180 * Fills a polygon made with the specified points.
1182 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
1184 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1185 draw(shape, "fill");
1191 public void fillPolygon(Polygon p)
1197 * Draws the specified characters, starting from (x,y)
1199 public void drawChars(char[] data, int offset, int length, int x, int y)
1201 String string = new String(data, offset, length);
1202 drawString(string, x, y);
1206 * Draws the specified bytes, starting from (x,y)
1208 public void drawBytes(byte[] data, int offset, int length, int x, int y)
1210 String string = new String(data, offset, length);
1211 drawString(string, x, y);
1217 public boolean drawImage(Image img, int x, int y, ImageObserver observer)
1219 return drawImage(img, x, y, Color.white, observer);
1225 public boolean drawImage(Image img, int x, int y, int width, int height,
1226 ImageObserver observer)
1228 return drawImage(img, x, y, width, height, Color.white, observer);
1234 public boolean drawImage(Image img, int x, int y, Color bgcolor,
1235 ImageObserver observer)
1237 int width = img.getWidth(null);
1238 int height = img.getHeight(null);
1239 return drawImage(img, x, y, width, height, bgcolor, observer);
1245 public boolean drawImage(Image img, int x, int y, int width, int height,
1246 Color bgcolor, ImageObserver observer)
1248 return drawImage(img, x, y, x + width, y + height, 0, 0, width, height,
1255 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1256 int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
1258 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
1259 Color.white, observer);
1265 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1266 int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1267 ImageObserver observer)
1271 throw new IllegalArgumentException("dx1 >= dx2");
1275 throw new IllegalArgumentException("sx1 >= sx2");
1279 throw new IllegalArgumentException("dy1 >= dy2");
1283 throw new IllegalArgumentException("sy1 >= sy2");
1288 int width = sx2 - sx1;
1289 int height = sy2 - sy1;
1290 int destWidth = dx2 - dx1;
1291 int destHeight = dy2 - dy1;
1293 int[] pixels = new int[width * height];
1294 PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sx2 - sx1, sy2 - sy1,
1299 } catch (InterruptedException e)
1304 AffineTransform matrix = new AffineTransform(_transform);
1305 matrix.translate(dx1, dy1);
1306 matrix.scale(destWidth / (double) width, destHeight / (double) height);
1307 double[] m = new double[6];
1310 matrix = matrix.createInverse();
1311 } catch (Exception e)
1313 throw new EpsException("Unable to get inverse of matrix: " + matrix);
1315 matrix.scale(1, -1);
1316 matrix.getMatrix(m);
1317 append(width + " " + height + " 8 [" + m[0] + " " + m[1] + " " + m[2]
1318 + " " + m[3] + " " + m[4] + " " + m[5] + "]");
1319 // Fill the background to update the bounding box.
1320 Color oldColor = getColor();
1321 setColor(getBackground());
1322 fillRect(dx1, dy1, destWidth, destHeight);
1324 append("{currentfile 3 " + width
1325 + " mul string readhexstring pop} bind");
1326 append("false 3 colorimage");
1327 StringBuffer line = new StringBuffer();
1328 for (int y = 0; y < height; y++)
1330 for (int x = 0; x < width; x++)
1332 Color color = new Color(pixels[x + width * y]);
1333 line.append(toHexString(color.getRed())
1334 + toHexString(color.getGreen())
1335 + toHexString(color.getBlue()));
1336 if (line.length() > 64)
1338 append(line.toString());
1339 line = new StringBuffer();
1343 if (line.length() > 0)
1345 append(line.toString());
1354 * Disposes of all resources used by this EpsGraphics2D object. If this is the
1355 * only remaining EpsGraphics2D instance pointing at a EpsDocument object,
1356 * then the EpsDocument object shall become eligible for garbage collection.
1358 public void dispose()
1364 * Finalizes the object.
1366 public void finalize()
1372 * Returns the entire contents of the EPS document, complete with headers and
1373 * bounding box. The returned String is suitable for being written directly to
1374 * disk as an EPS file.
1376 public String toString()
1378 StringWriter writer = new StringWriter();
1381 _document.write(writer);
1384 } catch (IOException e)
1386 throw new EpsException(e.toString());
1388 return writer.toString();
1392 * Returns true if the specified rectangular area might intersect the current
1395 public boolean hitClip(int x, int y, int width, int height)
1401 Rectangle rect = new Rectangle(x, y, width, height);
1402 return hit(rect, _clip, true);
1406 * Returns the bounding rectangle of the current clipping area.
1408 public Rectangle getClipBounds(Rectangle r)
1414 Rectangle rect = getClipBounds();
1415 r.setLocation((int) rect.getX(), (int) rect.getY());
1416 r.setSize((int) rect.getWidth(), (int) rect.getHeight());
1420 private Color _color;
1422 private Color _backgroundColor;
1424 private Paint _paint;
1426 private Composite _composite;
1428 private BasicStroke _stroke;
1432 private Shape _clip;
1434 private AffineTransform _clipTransform;
1436 private AffineTransform _transform;
1438 private boolean _accurateTextMode;
1440 private EpsDocument _document;
1442 private static FontRenderContext _fontRenderContext = new FontRenderContext(