2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package org.jibble.epsgraphics;
23 import jalview.util.MessageManager;
25 import java.awt.AlphaComposite;
26 import java.awt.BasicStroke;
27 import java.awt.Color;
28 import java.awt.Composite;
30 import java.awt.FontMetrics;
31 import java.awt.Graphics;
32 import java.awt.GraphicsConfiguration;
33 import java.awt.GraphicsDevice;
34 import java.awt.GraphicsEnvironment;
35 import java.awt.Image;
36 import java.awt.Paint;
37 import java.awt.Polygon;
38 import java.awt.Rectangle;
39 import java.awt.RenderingHints;
40 import java.awt.Shape;
41 import java.awt.Stroke;
42 import java.awt.font.FontRenderContext;
43 import java.awt.font.GlyphVector;
44 import java.awt.font.TextAttribute;
45 import java.awt.font.TextLayout;
46 import java.awt.geom.AffineTransform;
47 import java.awt.geom.Arc2D;
48 import java.awt.geom.Area;
49 import java.awt.geom.Ellipse2D;
50 import java.awt.geom.GeneralPath;
51 import java.awt.geom.Line2D;
52 import java.awt.geom.PathIterator;
53 import java.awt.geom.Point2D;
54 import java.awt.geom.Rectangle2D;
55 import java.awt.geom.RoundRectangle2D;
56 import java.awt.image.BufferedImage;
57 import java.awt.image.BufferedImageOp;
58 import java.awt.image.ColorModel;
59 import java.awt.image.ImageObserver;
60 import java.awt.image.PixelGrabber;
61 import java.awt.image.RenderedImage;
62 import java.awt.image.WritableRaster;
63 import java.awt.image.renderable.RenderableImage;
65 import java.io.FileOutputStream;
66 import java.io.IOException;
67 import java.io.OutputStream;
68 import java.io.StringWriter;
69 import java.text.AttributedCharacterIterator;
70 import java.text.AttributedString;
71 import java.text.CharacterIterator;
72 import java.util.Hashtable;
76 * EpsGraphics2D is suitable for creating high quality EPS graphics for use in
77 * documents and papers, and can be used just like a standard Graphics2D object.
79 * Many Java programs use Graphics2D to draw stuff on the screen, and while it
80 * is easy to save the output as a png or jpeg file, it is a little harder to
81 * export it as an EPS for including in a document or paper.
83 * This class makes the whole process extremely easy, because you can use it as
84 * if it's a Graphics2D object. The only difference is that all of the
85 * implemented methods create EPS output, which means the diagrams you draw can
86 * be resized without leading to any of the jagged edges you may see when
87 * resizing pixel-based images, such as jpeg and png files.
93 * Graphics2D g = new EpsGraphics2D();
94 * g.setColor(Color.black);
96 * // Line thickness 2.
97 * g.setStroke(new BasicStroke(2.0f));
100 * g.drawLine(10, 10, 50, 10);
102 * // Fill a rectangle in blue
103 * g.setColor(Color.blue);
104 * g.fillRect(10, 0, 20, 20);
106 * // Get the EPS output.
107 * String output = g.toString();
111 * You do not need to worry about the size of the canvas when drawing on a
112 * EpsGraphics2D object. The bounding box of the EPS document will automatically
113 * resize to accomodate new items that you draw.
115 * Not all methods are implemented yet. Those that are not are clearly labelled.
117 * Copyright Paul Mutton,
118 * <a href="http://www.jibble.org/">http://www.jibble.org/</a>
121 public class EpsGraphics2D extends java.awt.Graphics2D
122 implements AutoCloseable
125 public static final String VERSION = "0.8.8";
128 * Constructs a new EPS document that is initially empty and can be drawn on
129 * like a Graphics2D object. The EPS document is stored in memory.
131 public EpsGraphics2D()
137 * Constructs a new EPS document that is initially empty and can be drawn on
138 * like a Graphics2D object. The EPS document is stored in memory.
140 public EpsGraphics2D(String title)
142 _document = new EpsDocument(title);
143 _backgroundColor = Color.white;
145 _transform = new AffineTransform();
146 _clipTransform = new AffineTransform();
147 _accurateTextMode = true;
148 setColor(Color.black);
149 setPaint(Color.black);
150 setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
151 setFont(Font.decode(null));
152 setStroke(new BasicStroke());
156 * Constructs a new EPS document that is initially empty and can be drawn on
157 * like a Graphics2D object. The EPS document is written to the file as it
158 * goes, which reduces memory usage. The bounding box of the document is fixed
159 * and specified at construction time by minX,minY,maxX,maxY. The file is
160 * flushed and closed when the close() method is called.
162 public EpsGraphics2D(String title, File file, int minX, int minY,
163 int maxX, int maxY) throws IOException
165 this(title, new FileOutputStream(file), minX, minY, maxX, maxY);
169 * Constructs a new EPS document that is initially empty and can be drawn on
170 * like a Graphics2D object. The EPS document is written to the output stream
171 * as it goes, which reduces memory usage. The bounding box of the document is
172 * fixed and specified at construction time by minX,minY,maxX,maxY. The output
173 * stream is flushed and closed when the close() method is called.
175 public EpsGraphics2D(String title, OutputStream outputStream, int minX,
176 int minY, int maxX, int maxY) throws IOException
179 _document = new EpsDocument(title, outputStream, minX, minY, maxX,
184 * Constructs a new EpsGraphics2D instance that is a copy of the supplied
185 * argument and points at the same EpsDocument.
187 protected EpsGraphics2D(EpsGraphics2D g)
189 _document = g._document;
190 _backgroundColor = g._backgroundColor;
192 _clipTransform = (AffineTransform) g._clipTransform.clone();
193 _transform = (AffineTransform) g._transform.clone();
196 _composite = g._composite;
199 _accurateTextMode = g._accurateTextMode;
203 * This method is called to indicate that a particular method is not supported
204 * yet. The stack trace is printed to the standard output.
206 private void methodNotSupported()
208 EpsException e = new EpsException(MessageManager.formatMessage(
209 "exception.eps_method_not_supported", new String[]
211 e.printStackTrace(System.err);
214 // ///////////// Specialist methods ///////////////////////
217 * Sets whether to use accurate text mode when rendering text in EPS. This is
218 * enabled (true) by default. When accurate text mode is used, all text will
219 * be rendered in EPS to appear exactly the same as it would do when drawn
220 * with a Graphics2D context. With accurate text mode enabled, it is not
221 * necessary for the EPS viewer to have the required font installed.
223 * Turning off accurate text mode will require the EPS viewer to have the
224 * necessary fonts installed. If you are using a lot of text, you will find
225 * that this significantly reduces the file size of your EPS documents.
226 * AffineTransforms can only affect the starting point of text using this
227 * simpler text mode - all text will be horizontal.
229 public void setAccurateTextMode(boolean b)
231 _accurateTextMode = b;
235 * Returns whether accurate text mode is being used.
237 public boolean getAccurateTextMode()
239 return _accurateTextMode;
243 * Flushes the buffered contents of this EPS document to the underlying
244 * OutputStream it is being written to.
246 public void flush() throws IOException
252 * Closes the EPS file being output to the underlying OutputStream. The
253 * OutputStream is automatically flushed before being closed. If you forget to
254 * do this, the file may be incomplete.
257 public void close() throws IOException
264 * Appends a line to the EpsDocument.
266 private void append(String line)
268 _document.append(this, line);
272 * Returns the point after it has been transformed by the transformation.
274 private Point2D transform(float x, float y)
276 Point2D result = new Point2D.Float(x, y);
277 result = _transform.transform(result, result);
278 result.setLocation(result.getX(), -result.getY());
283 * Appends the commands required to draw a shape on the EPS document.
285 private void draw(Shape s, String action)
291 // Rectangle2D userBounds = s.getBounds2D();
292 if (!_transform.isIdentity())
294 s = _transform.createTransformedShape(s);
297 // Update the bounds.
298 if (!action.equals("clip"))
300 Rectangle2D shapeBounds = s.getBounds2D();
301 Rectangle2D visibleBounds = shapeBounds;
304 Rectangle2D clipBounds = _clip.getBounds2D();
305 visibleBounds = shapeBounds.createIntersection(clipBounds);
307 float lineRadius = _stroke.getLineWidth() / 2;
308 float minX = (float) visibleBounds.getMinX() - lineRadius;
309 float minY = (float) visibleBounds.getMinY() - lineRadius;
310 float maxX = (float) visibleBounds.getMaxX() + lineRadius;
311 float maxY = (float) visibleBounds.getMaxY() + lineRadius;
312 _document.updateBounds(minX, -minY);
313 _document.updateBounds(maxX, -maxY);
318 float[] coords = new float[6];
319 PathIterator it = s.getPathIterator(null);
325 type = it.currentSegment(coords);
326 float x1 = coords[0];
327 float y1 = -coords[1];
328 float x2 = coords[2];
329 float y2 = -coords[3];
330 float x3 = coords[4];
331 float y3 = -coords[5];
333 if (type == PathIterator.SEG_CLOSE)
338 else if (type == PathIterator.SEG_CUBICTO)
340 append(x1 + " " + y1 + " " + x2 + " " + y2 + " " + x3 + " " + y3
346 else if (type == PathIterator.SEG_LINETO)
348 append(x1 + " " + y1 + " lineto");
353 else if (type == PathIterator.SEG_MOVETO)
355 append(x1 + " " + y1 + " moveto");
360 else if (type == PathIterator.SEG_QUADTO)
362 // Convert the quad curve into a cubic.
363 float _x1 = x0 + 2 / 3f * (x1 - x0);
364 float _y1 = y0 + 2 / 3f * (y1 - y0);
365 float _x2 = x1 + 1 / 3f * (x2 - x1);
366 float _y2 = y1 + 1 / 3f * (y2 - y1);
369 append(_x1 + " " + _y1 + " " + _x2 + " " + _y2 + " " + _x3 + " "
375 else if (type == PathIterator.WIND_EVEN_ODD)
379 else if (type == PathIterator.WIND_NON_ZERO)
391 * Returns a hex string that always contains two characters.
393 private String toHexString(int n)
395 String result = Integer.toString(n, 16);
396 while (result.length() < 2)
398 result = "0" + result;
403 // ///////////// Graphics2D methods ///////////////////////
406 * Draws a 3D rectangle outline. If it is raised, light appears to come from
410 public void draw3DRect(int x, int y, int width, int height,
413 Color originalColor = getColor();
414 Stroke originalStroke = getStroke();
416 setStroke(new BasicStroke(1.0f));
420 setColor(originalColor.brighter());
424 setColor(originalColor.darker());
427 drawLine(x, y, x + width, y);
428 drawLine(x, y, x, y + height);
432 setColor(originalColor.darker());
436 setColor(originalColor.brighter());
439 drawLine(x + width, y + height, x, y + height);
440 drawLine(x + width, y + height, x + width, y);
442 setColor(originalColor);
443 setStroke(originalStroke);
447 * Fills a 3D rectangle. If raised, it has bright fill and light appears to
448 * come from the top left.
451 public void fill3DRect(int x, int y, int width, int height,
454 Color originalColor = getColor();
458 setColor(originalColor.brighter());
462 setColor(originalColor.darker());
464 draw(new Rectangle(x, y, width, height), "fill");
465 setColor(originalColor);
466 draw3DRect(x, y, width, height, raised);
470 * Draws a Shape on the EPS document.
473 public void draw(Shape s)
479 * Draws an Image on the EPS document.
482 public boolean drawImage(Image img, AffineTransform xform,
485 AffineTransform at = getTransform();
487 boolean st = drawImage(img, 0, 0, obs);
493 * Draws a BufferedImage on the EPS document.
496 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
498 BufferedImage img1 = op.filter(img, null);
499 drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null);
503 * Draws a RenderedImage on the EPS document.
506 public void drawRenderedImage(RenderedImage img, AffineTransform xform)
508 Hashtable properties = new Hashtable();
509 String[] names = img.getPropertyNames();
510 for (int i = 0; i < names.length; i++)
512 properties.put(names[i], img.getProperty(names[i]));
515 ColorModel cm = img.getColorModel();
516 WritableRaster wr = img.copyData(null);
517 BufferedImage img1 = new BufferedImage(cm, wr,
518 cm.isAlphaPremultiplied(), properties);
519 AffineTransform at = AffineTransform.getTranslateInstance(img.getMinX(),
521 at.preConcatenate(xform);
522 drawImage(img1, at, null);
526 * Draws a RenderableImage by invoking its createDefaultRendering method.
529 public void drawRenderableImage(RenderableImage img,
530 AffineTransform xform)
532 drawRenderedImage(img.createDefaultRendering(), xform);
536 * Draws a string at (x,y)
539 public void drawString(String str, int x, int y)
541 drawString(str, (float) x, (float) y);
545 * Draws a string at (x,y)
548 public void drawString(String s, float x, float y)
550 if (s != null && s.length() > 0)
552 AttributedString as = new AttributedString(s);
553 as.addAttribute(TextAttribute.FONT, getFont());
554 drawString(as.getIterator(), x, y);
559 * Draws the characters of an AttributedCharacterIterator, starting from
563 public void drawString(AttributedCharacterIterator iterator, int x, int y)
565 drawString(iterator, (float) x, (float) y);
569 * Draws the characters of an AttributedCharacterIterator, starting from
573 public void drawString(AttributedCharacterIterator iterator, float x,
576 if (getAccurateTextMode())
578 TextLayout layout = new TextLayout(iterator, getFontRenderContext());
580 .getOutline(AffineTransform.getTranslateInstance(x, y));
586 Point2D location = transform(x, y);
587 append(location.getX() + " " + location.getY() + " moveto");
588 StringBuffer buffer = new StringBuffer();
589 for (char ch = iterator
590 .first(); ch != CharacterIterator.DONE; ch = iterator.next())
592 if (ch == '(' || ch == ')')
598 append("(" + buffer.toString() + ") show");
603 * Draws a GlyphVector at (x,y)
606 public void drawGlyphVector(GlyphVector g, float x, float y)
608 Shape shape = g.getOutline(x, y);
613 * Fills a Shape on the EPS document.
616 public void fill(Shape s)
622 * Checks whether or not the specified Shape intersects the specified
623 * Rectangle, which is in device space.
626 public boolean hit(Rectangle rect, Shape s, boolean onStroke)
628 return s.intersects(rect);
632 * Returns the device configuration associated with this EpsGraphics2D object.
635 public GraphicsConfiguration getDeviceConfiguration()
637 GraphicsConfiguration gc = null;
638 GraphicsEnvironment ge = GraphicsEnvironment
639 .getLocalGraphicsEnvironment();
640 GraphicsDevice[] gds = ge.getScreenDevices();
641 for (int i = 0; i < gds.length; i++)
643 GraphicsDevice gd = gds[i];
644 GraphicsConfiguration[] gcs = gd.getConfigurations();
654 * Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does not
658 public void setComposite(Composite comp)
664 * Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
665 * of type Color are respected by EpsGraphics2D.
668 public void setPaint(Paint paint)
671 if (paint instanceof Color)
673 setColor((Color) paint);
678 * Sets the stroke. Only accepts BasicStroke objects (or subclasses of
682 public void setStroke(Stroke s)
684 if (s instanceof BasicStroke)
686 _stroke = (BasicStroke) s;
688 append(_stroke.getLineWidth() + " setlinewidth");
689 float miterLimit = _stroke.getMiterLimit();
690 if (miterLimit < 1.0f)
694 append(miterLimit + " setmiterlimit");
695 append(_stroke.getLineJoin() + " setlinejoin");
696 append(_stroke.getEndCap() + " setlinecap");
698 StringBuffer dashes = new StringBuffer();
700 float[] dashArray = _stroke.getDashArray();
701 if (dashArray != null)
703 for (int i = 0; i < dashArray.length; i++)
705 dashes.append((dashArray[i]) + " ");
709 append(dashes.toString() + " 0 setdash");
714 * Sets a rendering hint. These are not used by EpsGraphics2D.
717 public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
723 * Returns the value of a single preference for the rendering algorithms.
724 * Rendering hints are not used by EpsGraphics2D.
727 public Object getRenderingHint(RenderingHints.Key hintKey)
733 * Sets the rendering hints. These are ignored by EpsGraphics2D.
736 public void setRenderingHints(Map hints)
742 * Adds rendering hints. These are ignored by EpsGraphics2D.
745 public void addRenderingHints(Map hints)
751 * Returns the preferences for the rendering algorithms.
754 public RenderingHints getRenderingHints()
756 return new RenderingHints(null);
760 * Translates the origin of the EpsGraphics2D context to the point (x,y) in
761 * the current coordinate system.
764 public void translate(int x, int y)
766 translate((double) x, (double) y);
770 * Concatenates the current EpsGraphics2D Transformation with a translation
774 public void translate(double tx, double ty)
776 transform(AffineTransform.getTranslateInstance(tx, ty));
780 * Concatenates the current EpsGraphics2D Transform with a rotation transform.
783 public void rotate(double theta)
789 * Concatenates the current EpsGraphics2D Transform with a translated rotation
793 public void rotate(double theta, double x, double y)
795 transform(AffineTransform.getRotateInstance(theta, x, y));
799 * Concatenates the current EpsGraphics2D Transform with a scaling
803 public void scale(double sx, double sy)
805 transform(AffineTransform.getScaleInstance(sx, sy));
809 * Concatenates the current EpsGraphics2D Transform with a shearing transform.
812 public void shear(double shx, double shy)
814 transform(AffineTransform.getShearInstance(shx, shy));
818 * Composes an AffineTransform object with the Transform in this EpsGraphics2D
819 * according to the rule last-specified-first-applied.
822 public void transform(AffineTransform Tx)
824 _transform.concatenate(Tx);
825 setTransform(getTransform());
829 * Sets the AffineTransform to be used by this EpsGraphics2D.
832 public void setTransform(AffineTransform Tx)
836 _transform = new AffineTransform();
840 _transform = new AffineTransform(Tx);
842 // Need to update the stroke and font so they know the scale changed
843 setStroke(getStroke());
848 * Gets the AffineTransform used by this EpsGraphics2D.
851 public AffineTransform getTransform()
853 return new AffineTransform(_transform);
857 * Returns the current Paint of the EpsGraphics2D object.
860 public Paint getPaint()
866 * returns the current Composite of the EpsGraphics2D object.
869 public Composite getComposite()
875 * Sets the background color to be used by the clearRect method.
878 public void setBackground(Color color)
884 _backgroundColor = color;
888 * Gets the background color that is used by the clearRect method.
891 public Color getBackground()
893 return _backgroundColor;
897 * Returns the Stroke currently used. Guaranteed to be an instance of
901 public Stroke getStroke()
907 * Intersects the current clip with the interior of the specified Shape and
908 * sets the clip to the resulting intersection.
911 public void clip(Shape s)
919 Area area = new Area(_clip);
920 area.intersect(new Area(s));
926 * Returns the FontRenderContext.
929 public FontRenderContext getFontRenderContext()
931 return _fontRenderContext;
934 // ///////////// Graphics methods ///////////////////////
937 * Returns a new Graphics object that is identical to this EpsGraphics2D.
940 public Graphics create()
942 return new EpsGraphics2D(this);
946 * Returns an EpsGraphics2D object based on this Graphics object, but with a
947 * new translation and clip area.
950 public Graphics create(int x, int y, int width, int height)
952 Graphics g = create();
954 g.clipRect(0, 0, width, height);
959 * Returns the current Color. This will be a default value (black) until it is
960 * changed using the setColor method.
963 public Color getColor()
969 * Sets the Color to be used when drawing all future shapes, text, etc.
972 public void setColor(Color c)
979 append((c.getRed() / 255f) + " " + (c.getGreen() / 255f) + " "
980 + (c.getBlue() / 255f) + " setrgbcolor");
984 * Sets the paint mode of this EpsGraphics2D object to overwrite the
985 * destination EpsDocument with the current color.
988 public void setPaintMode()
990 // Do nothing - paint mode is the only method supported anyway.
994 * <b><i><font color="red">Not implemented</font></i></b> - performs no
998 public void setXORMode(Color c1)
1000 methodNotSupported();
1004 * Returns the Font currently being used.
1007 public Font getFont()
1013 * Sets the Font to be used in future text.
1016 public void setFont(Font font)
1020 font = Font.decode(null);
1023 append("/" + _font.getPSName() + " findfont " + (_font.getSize())
1024 + " scalefont setfont");
1028 * Gets the font metrics of the current font.
1031 public FontMetrics getFontMetrics()
1033 return getFontMetrics(getFont());
1037 * Gets the font metrics for the specified font.
1040 public FontMetrics getFontMetrics(Font f)
1042 BufferedImage image = new BufferedImage(1, 1,
1043 BufferedImage.TYPE_INT_RGB);
1044 Graphics g = image.getGraphics();
1045 return g.getFontMetrics(f);
1049 * Returns the bounding rectangle of the current clipping area.
1052 public Rectangle getClipBounds()
1058 Rectangle rect = getClip().getBounds();
1063 * Intersects the current clip with the specified rectangle.
1066 public void clipRect(int x, int y, int width, int height)
1068 clip(new Rectangle(x, y, width, height));
1072 * Sets the current clip to the rectangle specified by the given coordinates.
1075 public void setClip(int x, int y, int width, int height)
1077 setClip(new Rectangle(x, y, width, height));
1081 * Gets the current clipping area.
1084 public Shape getClip()
1094 AffineTransform t = _transform.createInverse();
1095 t.concatenate(_clipTransform);
1096 return t.createTransformedShape(_clip);
1097 } catch (Exception e)
1099 throw new EpsException(MessageManager.formatMessage(
1100 "exception.eps_unable_to_get_inverse_matrix", new String[]
1101 { _transform.toString() }));
1107 * Sets the current clipping area to an arbitrary clip shape.
1110 public void setClip(Shape clip)
1114 if (_document.isClipSet())
1121 _document.setClipSet(true);
1126 _clipTransform = (AffineTransform) _transform.clone();
1130 if (_document.isClipSet())
1133 _document.setClipSet(false);
1140 * <b><i><font color="red">Not implemented</font></i></b> - performs no
1144 public void copyArea(int x, int y, int width, int height, int dx, int dy)
1146 methodNotSupported();
1150 * Draws a straight line from (x1,y1) to (x2,y2).
1153 public void drawLine(int x1, int y1, int x2, int y2)
1155 Shape shape = new Line2D.Float(x1, y1, x2, y2);
1160 * Fills a rectangle with top-left corner placed at (x,y).
1163 public void fillRect(int x, int y, int width, int height)
1165 Shape shape = new Rectangle(x, y, width, height);
1166 draw(shape, "fill");
1170 * Draws a rectangle with top-left corner placed at (x,y).
1173 public void drawRect(int x, int y, int width, int height)
1175 Shape shape = new Rectangle(x, y, width, height);
1180 * Clears a rectangle with top-left corner placed at (x,y) using the current
1184 public void clearRect(int x, int y, int width, int height)
1186 Color originalColor = getColor();
1188 setColor(getBackground());
1189 Shape shape = new Rectangle(x, y, width, height);
1190 draw(shape, "fill");
1192 setColor(originalColor);
1196 * Draws a rounded rectangle.
1199 public void drawRoundRect(int x, int y, int width, int height,
1200 int arcWidth, int arcHeight)
1202 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1208 * Fills a rounded rectangle.
1211 public void fillRoundRect(int x, int y, int width, int height,
1212 int arcWidth, int arcHeight)
1214 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1216 draw(shape, "fill");
1223 public void drawOval(int x, int y, int width, int height)
1225 Shape shape = new Ellipse2D.Float(x, y, width, height);
1233 public void fillOval(int x, int y, int width, int height)
1235 Shape shape = new Ellipse2D.Float(x, y, width, height);
1236 draw(shape, "fill");
1243 public void drawArc(int x, int y, int width, int height, int startAngle,
1246 Shape shape = new Arc2D.Float(x, y, width, height, startAngle, arcAngle,
1255 public void fillArc(int x, int y, int width, int height, int startAngle,
1258 Shape shape = new Arc2D.Float(x, y, width, height, startAngle, arcAngle,
1260 draw(shape, "fill");
1267 public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
1271 GeneralPath path = new GeneralPath();
1272 path.moveTo(xPoints[0], yPoints[0]);
1273 for (int i = 1; i < nPoints; i++)
1275 path.lineTo(xPoints[i], yPoints[i]);
1282 * Draws a polygon made with the specified points.
1285 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
1287 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1295 public void drawPolygon(Polygon p)
1301 * Fills a polygon made with the specified points.
1304 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
1306 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1307 draw(shape, "fill");
1314 public void fillPolygon(Polygon p)
1320 * Draws the specified characters, starting from (x,y)
1323 public void drawChars(char[] data, int offset, int length, int x, int y)
1325 String string = new String(data, offset, length);
1326 drawString(string, x, y);
1330 * Draws the specified bytes, starting from (x,y)
1333 public void drawBytes(byte[] data, int offset, int length, int x, int y)
1335 String string = new String(data, offset, length);
1336 drawString(string, x, y);
1343 public boolean drawImage(Image img, int x, int y, ImageObserver observer)
1345 return drawImage(img, x, y, Color.white, observer);
1352 public boolean drawImage(Image img, int x, int y, int width, int height,
1353 ImageObserver observer)
1355 return drawImage(img, x, y, width, height, Color.white, observer);
1362 public boolean drawImage(Image img, int x, int y, Color bgcolor,
1363 ImageObserver observer)
1365 int width = img.getWidth(null);
1366 int height = img.getHeight(null);
1367 return drawImage(img, x, y, width, height, bgcolor, observer);
1374 public boolean drawImage(Image img, int x, int y, int width, int height,
1375 Color bgcolor, ImageObserver observer)
1377 return drawImage(img, x, y, x + width, y + height, 0, 0, width, height,
1385 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1386 int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
1388 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
1389 Color.white, observer);
1396 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1397 int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1398 ImageObserver observer)
1402 throw new IllegalArgumentException("dx1 >= dx2");
1406 throw new IllegalArgumentException("sx1 >= sx2");
1410 throw new IllegalArgumentException("dy1 >= dy2");
1414 throw new IllegalArgumentException("sy1 >= sy2");
1419 int width = sx2 - sx1;
1420 int height = sy2 - sy1;
1421 int destWidth = dx2 - dx1;
1422 int destHeight = dy2 - dy1;
1424 int[] pixels = new int[width * height];
1425 PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sx2 - sx1, sy2 - sy1,
1430 } catch (InterruptedException e)
1435 AffineTransform matrix = new AffineTransform(_transform);
1436 matrix.translate(dx1, dy1);
1437 matrix.scale(destWidth / (double) width, destHeight / (double) height);
1438 double[] m = new double[6];
1441 matrix = matrix.createInverse();
1442 } catch (Exception e)
1444 throw new EpsException(MessageManager.formatMessage(
1445 "exception.eps_unable_to_get_inverse_matrix", new String[]
1446 { matrix.toString() }));
1448 matrix.scale(1, -1);
1449 matrix.getMatrix(m);
1450 append(width + " " + height + " 8 [" + m[0] + " " + m[1] + " " + m[2]
1451 + " " + m[3] + " " + m[4] + " " + m[5] + "]");
1452 // Fill the background to update the bounding box.
1453 Color oldColor = getColor();
1454 setColor(getBackground());
1455 fillRect(dx1, dy1, destWidth, destHeight);
1457 append("{currentfile 3 " + width
1458 + " mul string readhexstring pop} bind");
1459 append("false 3 colorimage");
1460 StringBuffer line = new StringBuffer();
1461 for (int y = 0; y < height; y++)
1463 for (int x = 0; x < width; x++)
1465 Color color = new Color(pixels[x + width * y]);
1467 toHexString(color.getRed()) + toHexString(color.getGreen())
1468 + toHexString(color.getBlue()));
1469 if (line.length() > 64)
1471 append(line.toString());
1472 line = new StringBuffer();
1476 if (line.length() > 0)
1478 append(line.toString());
1487 * Disposes of all resources used by this EpsGraphics2D object. If this is the
1488 * only remaining EpsGraphics2D instance pointing at a EpsDocument object,
1489 * then the EpsDocument object shall become eligible for garbage collection.
1492 public void dispose()
1497 /* bsoares 2019-03-20
1498 * finalize is now deprecated. Implementing AutoCloseable instead
1500 * Finalizes the object.
1502 public void finalize()
1509 * Returns the entire contents of the EPS document, complete with headers and
1510 * bounding box. The returned String is suitable for being written directly to
1511 * disk as an EPS file.
1514 public String toString()
1516 StringWriter writer = new StringWriter();
1519 _document.write(writer);
1522 } catch (IOException e)
1524 throw new EpsException(e.toString());
1526 return writer.toString();
1530 * Returns true if the specified rectangular area might intersect the current
1534 public boolean hitClip(int x, int y, int width, int height)
1540 Rectangle rect = new Rectangle(x, y, width, height);
1541 return hit(rect, _clip, true);
1545 * Returns the bounding rectangle of the current clipping area.
1548 public Rectangle getClipBounds(Rectangle r)
1554 Rectangle rect = getClipBounds();
1555 r.setLocation((int) rect.getX(), (int) rect.getY());
1556 r.setSize((int) rect.getWidth(), (int) rect.getHeight());
1560 private Color _color;
1562 private Color _backgroundColor;
1564 private Paint _paint;
1566 private Composite _composite;
1568 private BasicStroke _stroke;
1572 private Shape _clip;
1574 private AffineTransform _clipTransform;
1576 private AffineTransform _transform;
1578 private boolean _accurateTextMode;
1580 private EpsDocument _document;
1582 private static FontRenderContext _fontRenderContext = new FontRenderContext(