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, <a
118 * 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, maxY);
183 * Constructs a new EpsGraphics2D instance that is a copy of the supplied
184 * argument and points at the same EpsDocument.
186 protected EpsGraphics2D(EpsGraphics2D g)
188 _document = g._document;
189 _backgroundColor = g._backgroundColor;
191 _clipTransform = (AffineTransform) g._clipTransform.clone();
192 _transform = (AffineTransform) g._transform.clone();
195 _composite = g._composite;
198 _accurateTextMode = g._accurateTextMode;
202 * This method is called to indicate that a particular method is not supported
203 * yet. The stack trace is printed to the standard output.
205 private void methodNotSupported()
207 EpsException e = new EpsException(MessageManager.formatMessage(
208 "exception.eps_method_not_supported", new String[] { VERSION }));
209 e.printStackTrace(System.err);
212 // ///////////// Specialist methods ///////////////////////
215 * Sets whether to use accurate text mode when rendering text in EPS. This is
216 * enabled (true) by default. When accurate text mode is used, all text will
217 * be rendered in EPS to appear exactly the same as it would do when drawn
218 * with a Graphics2D context. With accurate text mode enabled, it is not
219 * necessary for the EPS viewer to have the required font installed.
221 * Turning off accurate text mode will require the EPS viewer to have the
222 * necessary fonts installed. If you are using a lot of text, you will find
223 * that this significantly reduces the file size of your EPS documents.
224 * AffineTransforms can only affect the starting point of text using this
225 * simpler text mode - all text will be horizontal.
227 public void setAccurateTextMode(boolean b)
229 _accurateTextMode = b;
233 * Returns whether accurate text mode is being used.
235 public boolean getAccurateTextMode()
237 return _accurateTextMode;
241 * Flushes the buffered contents of this EPS document to the underlying
242 * OutputStream it is being written to.
244 public void flush() throws IOException
250 * Closes the EPS file being output to the underlying OutputStream. The
251 * OutputStream is automatically flushed before being closed. If you forget to
252 * do this, the file may be incomplete.
255 public void close() throws IOException
262 * Appends a line to the EpsDocument.
264 private void append(String line)
266 _document.append(this, line);
270 * Returns the point after it has been transformed by the transformation.
272 private Point2D transform(float x, float y)
274 Point2D result = new Point2D.Float(x, y);
275 result = _transform.transform(result, result);
276 result.setLocation(result.getX(), -result.getY());
281 * Appends the commands required to draw a shape on the EPS document.
283 private void draw(Shape s, String action)
289 // Rectangle2D userBounds = s.getBounds2D();
290 if (!_transform.isIdentity())
292 s = _transform.createTransformedShape(s);
295 // Update the bounds.
296 if (!action.equals("clip"))
298 Rectangle2D shapeBounds = s.getBounds2D();
299 Rectangle2D visibleBounds = shapeBounds;
302 Rectangle2D clipBounds = _clip.getBounds2D();
303 visibleBounds = shapeBounds.createIntersection(clipBounds);
305 float lineRadius = _stroke.getLineWidth() / 2;
306 float minX = (float) visibleBounds.getMinX() - lineRadius;
307 float minY = (float) visibleBounds.getMinY() - lineRadius;
308 float maxX = (float) visibleBounds.getMaxX() + lineRadius;
309 float maxY = (float) visibleBounds.getMaxY() + lineRadius;
310 _document.updateBounds(minX, -minY);
311 _document.updateBounds(maxX, -maxY);
316 float[] coords = new float[6];
317 PathIterator it = s.getPathIterator(null);
323 type = it.currentSegment(coords);
324 float x1 = coords[0];
325 float y1 = -coords[1];
326 float x2 = coords[2];
327 float y2 = -coords[3];
328 float x3 = coords[4];
329 float y3 = -coords[5];
331 if (type == PathIterator.SEG_CLOSE)
336 else if (type == PathIterator.SEG_CUBICTO)
338 append(x1 + " " + y1 + " " + x2 + " " + y2 + " " + x3 + " " + y3
344 else if (type == PathIterator.SEG_LINETO)
346 append(x1 + " " + y1 + " lineto");
351 else if (type == PathIterator.SEG_MOVETO)
353 append(x1 + " " + y1 + " moveto");
358 else if (type == PathIterator.SEG_QUADTO)
360 // Convert the quad curve into a cubic.
361 float _x1 = x0 + 2 / 3f * (x1 - x0);
362 float _y1 = y0 + 2 / 3f * (y1 - y0);
363 float _x2 = x1 + 1 / 3f * (x2 - x1);
364 float _y2 = y1 + 1 / 3f * (y2 - y1);
367 append(_x1 + " " + _y1 + " " + _x2 + " " + _y2 + " " + _x3 + " "
373 else if (type == PathIterator.WIND_EVEN_ODD)
377 else if (type == PathIterator.WIND_NON_ZERO)
389 * Returns a hex string that always contains two characters.
391 private String toHexString(int n)
393 String result = Integer.toString(n, 16);
394 while (result.length() < 2)
396 result = "0" + result;
401 // ///////////// Graphics2D methods ///////////////////////
404 * Draws a 3D rectangle outline. If it is raised, light appears to come from
408 public void draw3DRect(int x, int y, int width, int height, boolean raised)
410 Color originalColor = getColor();
411 Stroke originalStroke = getStroke();
413 setStroke(new BasicStroke(1.0f));
417 setColor(originalColor.brighter());
421 setColor(originalColor.darker());
424 drawLine(x, y, x + width, y);
425 drawLine(x, y, x, y + height);
429 setColor(originalColor.darker());
433 setColor(originalColor.brighter());
436 drawLine(x + width, y + height, x, y + height);
437 drawLine(x + width, y + height, x + width, y);
439 setColor(originalColor);
440 setStroke(originalStroke);
444 * Fills a 3D rectangle. If raised, it has bright fill and light appears to
445 * come from the top left.
448 public void fill3DRect(int x, int y, int width, int height, boolean raised)
450 Color originalColor = getColor();
454 setColor(originalColor.brighter());
458 setColor(originalColor.darker());
460 draw(new Rectangle(x, y, width, height), "fill");
461 setColor(originalColor);
462 draw3DRect(x, y, width, height, raised);
466 * Draws a Shape on the EPS document.
469 public void draw(Shape s)
475 * Draws an Image on the EPS document.
478 public boolean drawImage(Image img, AffineTransform xform,
481 AffineTransform at = getTransform();
483 boolean st = drawImage(img, 0, 0, obs);
489 * Draws a BufferedImage on the EPS document.
492 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
494 BufferedImage img1 = op.filter(img, null);
495 drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null);
499 * Draws a RenderedImage on the EPS document.
502 public void drawRenderedImage(RenderedImage img, AffineTransform xform)
504 Hashtable properties = new Hashtable();
505 String[] names = img.getPropertyNames();
506 for (int i = 0; i < names.length; i++)
508 properties.put(names[i], img.getProperty(names[i]));
511 ColorModel cm = img.getColorModel();
512 WritableRaster wr = img.copyData(null);
513 BufferedImage img1 = new BufferedImage(cm, wr,
514 cm.isAlphaPremultiplied(), properties);
515 AffineTransform at = AffineTransform.getTranslateInstance(
516 img.getMinX(), img.getMinY());
517 at.preConcatenate(xform);
518 drawImage(img1, at, null);
522 * Draws a RenderableImage by invoking its createDefaultRendering method.
525 public void drawRenderableImage(RenderableImage img, AffineTransform xform)
527 drawRenderedImage(img.createDefaultRendering(), xform);
531 * Draws a string at (x,y)
534 public void drawString(String str, int x, int y)
536 drawString(str, (float) x, (float) y);
540 * Draws a string at (x,y)
543 public void drawString(String s, float x, float y)
545 if (s != null && s.length() > 0)
547 AttributedString as = new AttributedString(s);
548 as.addAttribute(TextAttribute.FONT, getFont());
549 drawString(as.getIterator(), x, y);
554 * Draws the characters of an AttributedCharacterIterator, starting from
558 public void drawString(AttributedCharacterIterator iterator, int x, int y)
560 drawString(iterator, (float) x, (float) y);
564 * Draws the characters of an AttributedCharacterIterator, starting from
568 public void drawString(AttributedCharacterIterator iterator, float x,
571 if (getAccurateTextMode())
573 TextLayout layout = new TextLayout(iterator, getFontRenderContext());
574 Shape shape = layout.getOutline(AffineTransform.getTranslateInstance(
581 Point2D location = transform(x, y);
582 append(location.getX() + " " + location.getY() + " moveto");
583 StringBuffer buffer = new StringBuffer();
584 for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator
587 if (ch == '(' || ch == ')')
593 append("(" + buffer.toString() + ") show");
598 * Draws a GlyphVector at (x,y)
601 public void drawGlyphVector(GlyphVector g, float x, float y)
603 Shape shape = g.getOutline(x, y);
608 * Fills a Shape on the EPS document.
611 public void fill(Shape s)
617 * Checks whether or not the specified Shape intersects the specified
618 * Rectangle, which is in device space.
621 public boolean hit(Rectangle rect, Shape s, boolean onStroke)
623 return s.intersects(rect);
627 * Returns the device configuration associated with this EpsGraphics2D object.
630 public GraphicsConfiguration getDeviceConfiguration()
632 GraphicsConfiguration gc = null;
633 GraphicsEnvironment ge = GraphicsEnvironment
634 .getLocalGraphicsEnvironment();
635 GraphicsDevice[] gds = ge.getScreenDevices();
636 for (int i = 0; i < gds.length; i++)
638 GraphicsDevice gd = gds[i];
639 GraphicsConfiguration[] gcs = gd.getConfigurations();
649 * Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does not
653 public void setComposite(Composite comp)
659 * Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
660 * of type Color are respected by EpsGraphics2D.
663 public void setPaint(Paint paint)
666 if (paint instanceof Color)
668 setColor((Color) paint);
673 * Sets the stroke. Only accepts BasicStroke objects (or subclasses of
677 public void setStroke(Stroke s)
679 if (s instanceof BasicStroke)
681 _stroke = (BasicStroke) s;
683 append(_stroke.getLineWidth() + " setlinewidth");
684 float miterLimit = _stroke.getMiterLimit();
685 if (miterLimit < 1.0f)
689 append(miterLimit + " setmiterlimit");
690 append(_stroke.getLineJoin() + " setlinejoin");
691 append(_stroke.getEndCap() + " setlinecap");
693 StringBuffer dashes = new StringBuffer();
695 float[] dashArray = _stroke.getDashArray();
696 if (dashArray != null)
698 for (int i = 0; i < dashArray.length; i++)
700 dashes.append((dashArray[i]) + " ");
704 append(dashes.toString() + " 0 setdash");
709 * Sets a rendering hint. These are not used by EpsGraphics2D.
712 public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
718 * Returns the value of a single preference for the rendering algorithms.
719 * Rendering hints are not used by EpsGraphics2D.
722 public Object getRenderingHint(RenderingHints.Key hintKey)
728 * Sets the rendering hints. These are ignored by EpsGraphics2D.
731 public void setRenderingHints(Map hints)
737 * Adds rendering hints. These are ignored by EpsGraphics2D.
740 public void addRenderingHints(Map hints)
746 * Returns the preferences for the rendering algorithms.
749 public RenderingHints getRenderingHints()
751 return new RenderingHints(null);
755 * Translates the origin of the EpsGraphics2D context to the point (x,y) in
756 * the current coordinate system.
759 public void translate(int x, int y)
761 translate((double) x, (double) y);
765 * Concatenates the current EpsGraphics2D Transformation with a translation
769 public void translate(double tx, double ty)
771 transform(AffineTransform.getTranslateInstance(tx, ty));
775 * Concatenates the current EpsGraphics2D Transform with a rotation transform.
778 public void rotate(double theta)
784 * Concatenates the current EpsGraphics2D Transform with a translated rotation
788 public void rotate(double theta, double x, double y)
790 transform(AffineTransform.getRotateInstance(theta, x, y));
794 * Concatenates the current EpsGraphics2D Transform with a scaling
798 public void scale(double sx, double sy)
800 transform(AffineTransform.getScaleInstance(sx, sy));
804 * Concatenates the current EpsGraphics2D Transform with a shearing transform.
807 public void shear(double shx, double shy)
809 transform(AffineTransform.getShearInstance(shx, shy));
813 * Composes an AffineTransform object with the Transform in this EpsGraphics2D
814 * according to the rule last-specified-first-applied.
817 public void transform(AffineTransform Tx)
819 _transform.concatenate(Tx);
820 setTransform(getTransform());
824 * Sets the AffineTransform to be used by this EpsGraphics2D.
827 public void setTransform(AffineTransform Tx)
831 _transform = new AffineTransform();
835 _transform = new AffineTransform(Tx);
837 // Need to update the stroke and font so they know the scale changed
838 setStroke(getStroke());
843 * Gets the AffineTransform used by this EpsGraphics2D.
846 public AffineTransform getTransform()
848 return new AffineTransform(_transform);
852 * Returns the current Paint of the EpsGraphics2D object.
855 public Paint getPaint()
861 * returns the current Composite of the EpsGraphics2D object.
864 public Composite getComposite()
870 * Sets the background color to be used by the clearRect method.
873 public void setBackground(Color color)
879 _backgroundColor = color;
883 * Gets the background color that is used by the clearRect method.
886 public Color getBackground()
888 return _backgroundColor;
892 * Returns the Stroke currently used. Guaranteed to be an instance of
896 public Stroke getStroke()
902 * Intersects the current clip with the interior of the specified Shape and
903 * sets the clip to the resulting intersection.
906 public void clip(Shape s)
914 Area area = new Area(_clip);
915 area.intersect(new Area(s));
921 * Returns the FontRenderContext.
924 public FontRenderContext getFontRenderContext()
926 return _fontRenderContext;
929 // ///////////// Graphics methods ///////////////////////
932 * Returns a new Graphics object that is identical to this EpsGraphics2D.
935 public Graphics create()
937 return new EpsGraphics2D(this);
941 * Returns an EpsGraphics2D object based on this Graphics object, but with a
942 * new translation and clip area.
945 public Graphics create(int x, int y, int width, int height)
947 Graphics g = create();
949 g.clipRect(0, 0, width, height);
954 * Returns the current Color. This will be a default value (black) until it is
955 * changed using the setColor method.
958 public Color getColor()
964 * Sets the Color to be used when drawing all future shapes, text, etc.
967 public void setColor(Color c)
974 append((c.getRed() / 255f) + " " + (c.getGreen() / 255f) + " "
975 + (c.getBlue() / 255f) + " setrgbcolor");
979 * Sets the paint mode of this EpsGraphics2D object to overwrite the
980 * destination EpsDocument with the current color.
983 public void setPaintMode()
985 // Do nothing - paint mode is the only method supported anyway.
989 * <b><i><font color="red">Not implemented</font></i></b> - performs no
993 public void setXORMode(Color c1)
995 methodNotSupported();
999 * Returns the Font currently being used.
1002 public Font getFont()
1008 * Sets the Font to be used in future text.
1011 public void setFont(Font font)
1015 font = Font.decode(null);
1018 append("/" + _font.getPSName() + " findfont " + (_font.getSize())
1019 + " scalefont setfont");
1023 * Gets the font metrics of the current font.
1026 public FontMetrics getFontMetrics()
1028 return getFontMetrics(getFont());
1032 * Gets the font metrics for the specified font.
1035 public FontMetrics getFontMetrics(Font f)
1037 BufferedImage image = new BufferedImage(1, 1,
1038 BufferedImage.TYPE_INT_RGB);
1039 Graphics g = image.getGraphics();
1040 return g.getFontMetrics(f);
1044 * Returns the bounding rectangle of the current clipping area.
1047 public Rectangle getClipBounds()
1053 Rectangle rect = getClip().getBounds();
1058 * Intersects the current clip with the specified rectangle.
1061 public void clipRect(int x, int y, int width, int height)
1063 clip(new Rectangle(x, y, width, height));
1067 * Sets the current clip to the rectangle specified by the given coordinates.
1070 public void setClip(int x, int y, int width, int height)
1072 setClip(new Rectangle(x, y, width, height));
1076 * Gets the current clipping area.
1079 public Shape getClip()
1089 AffineTransform t = _transform.createInverse();
1090 t.concatenate(_clipTransform);
1091 return t.createTransformedShape(_clip);
1092 } catch (Exception e)
1094 throw new EpsException(MessageManager.formatMessage(
1095 "exception.eps_unable_to_get_inverse_matrix",
1096 new String[] { _transform.toString() }));
1102 * Sets the current clipping area to an arbitrary clip shape.
1105 public void setClip(Shape clip)
1109 if (_document.isClipSet())
1116 _document.setClipSet(true);
1121 _clipTransform = (AffineTransform) _transform.clone();
1125 if (_document.isClipSet())
1128 _document.setClipSet(false);
1135 * <b><i><font color="red">Not implemented</font></i></b> - performs no
1139 public void copyArea(int x, int y, int width, int height, int dx, int dy)
1141 methodNotSupported();
1145 * Draws a straight line from (x1,y1) to (x2,y2).
1148 public void drawLine(int x1, int y1, int x2, int y2)
1150 Shape shape = new Line2D.Float(x1, y1, x2, y2);
1155 * Fills a rectangle with top-left corner placed at (x,y).
1158 public void fillRect(int x, int y, int width, int height)
1160 Shape shape = new Rectangle(x, y, width, height);
1161 draw(shape, "fill");
1165 * Draws a rectangle with top-left corner placed at (x,y).
1168 public void drawRect(int x, int y, int width, int height)
1170 Shape shape = new Rectangle(x, y, width, height);
1175 * Clears a rectangle with top-left corner placed at (x,y) using the current
1179 public void clearRect(int x, int y, int width, int height)
1181 Color originalColor = getColor();
1183 setColor(getBackground());
1184 Shape shape = new Rectangle(x, y, width, height);
1185 draw(shape, "fill");
1187 setColor(originalColor);
1191 * Draws a rounded rectangle.
1194 public void drawRoundRect(int x, int y, int width, int height,
1195 int arcWidth, int arcHeight)
1197 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1203 * Fills a rounded rectangle.
1206 public void fillRoundRect(int x, int y, int width, int height,
1207 int arcWidth, int arcHeight)
1209 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1211 draw(shape, "fill");
1218 public void drawOval(int x, int y, int width, int height)
1220 Shape shape = new Ellipse2D.Float(x, y, width, height);
1228 public void fillOval(int x, int y, int width, int height)
1230 Shape shape = new Ellipse2D.Float(x, y, width, height);
1231 draw(shape, "fill");
1238 public void drawArc(int x, int y, int width, int height, int startAngle,
1241 Shape shape = new Arc2D.Float(x, y, width, height, startAngle,
1242 arcAngle, Arc2D.OPEN);
1250 public void fillArc(int x, int y, int width, int height, int startAngle,
1253 Shape shape = new Arc2D.Float(x, y, width, height, startAngle,
1254 arcAngle, Arc2D.PIE);
1255 draw(shape, "fill");
1262 public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
1266 GeneralPath path = new GeneralPath();
1267 path.moveTo(xPoints[0], yPoints[0]);
1268 for (int i = 1; i < nPoints; i++)
1270 path.lineTo(xPoints[i], yPoints[i]);
1277 * Draws a polygon made with the specified points.
1280 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
1282 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1290 public void drawPolygon(Polygon p)
1296 * Fills a polygon made with the specified points.
1299 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
1301 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1302 draw(shape, "fill");
1309 public void fillPolygon(Polygon p)
1315 * Draws the specified characters, starting from (x,y)
1318 public void drawChars(char[] data, int offset, int length, int x, int y)
1320 String string = new String(data, offset, length);
1321 drawString(string, x, y);
1325 * Draws the specified bytes, starting from (x,y)
1328 public void drawBytes(byte[] data, int offset, int length, int x, int y)
1330 String string = new String(data, offset, length);
1331 drawString(string, x, y);
1338 public boolean drawImage(Image img, int x, int y, ImageObserver observer)
1340 return drawImage(img, x, y, Color.white, observer);
1347 public boolean drawImage(Image img, int x, int y, int width, int height,
1348 ImageObserver observer)
1350 return drawImage(img, x, y, width, height, Color.white, observer);
1357 public boolean drawImage(Image img, int x, int y, Color bgcolor,
1358 ImageObserver observer)
1360 int width = img.getWidth(null);
1361 int height = img.getHeight(null);
1362 return drawImage(img, x, y, width, height, bgcolor, observer);
1369 public boolean drawImage(Image img, int x, int y, int width, int height,
1370 Color bgcolor, ImageObserver observer)
1372 return drawImage(img, x, y, x + width, y + height, 0, 0, width, height,
1380 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1381 int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
1383 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
1384 Color.white, observer);
1391 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1392 int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1393 ImageObserver observer)
1397 throw new IllegalArgumentException("dx1 >= dx2");
1401 throw new IllegalArgumentException("sx1 >= sx2");
1405 throw new IllegalArgumentException("dy1 >= dy2");
1409 throw new IllegalArgumentException("sy1 >= sy2");
1414 int width = sx2 - sx1;
1415 int height = sy2 - sy1;
1416 int destWidth = dx2 - dx1;
1417 int destHeight = dy2 - dy1;
1419 int[] pixels = new int[width * height];
1420 PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sx2 - sx1, sy2 - sy1,
1425 } catch (InterruptedException e)
1430 AffineTransform matrix = new AffineTransform(_transform);
1431 matrix.translate(dx1, dy1);
1432 matrix.scale(destWidth / (double) width, destHeight / (double) height);
1433 double[] m = new double[6];
1436 matrix = matrix.createInverse();
1437 } catch (Exception e)
1439 throw new EpsException(MessageManager.formatMessage(
1440 "exception.eps_unable_to_get_inverse_matrix",
1441 new String[] { matrix.toString() }));
1443 matrix.scale(1, -1);
1444 matrix.getMatrix(m);
1445 append(width + " " + height + " 8 [" + m[0] + " " + m[1] + " " + m[2]
1446 + " " + m[3] + " " + m[4] + " " + m[5] + "]");
1447 // Fill the background to update the bounding box.
1448 Color oldColor = getColor();
1449 setColor(getBackground());
1450 fillRect(dx1, dy1, destWidth, destHeight);
1452 append("{currentfile 3 " + width
1453 + " mul string readhexstring pop} bind");
1454 append("false 3 colorimage");
1455 StringBuffer line = new StringBuffer();
1456 for (int y = 0; y < height; y++)
1458 for (int x = 0; x < width; x++)
1460 Color color = new Color(pixels[x + width * y]);
1461 line.append(toHexString(color.getRed())
1462 + toHexString(color.getGreen())
1463 + toHexString(color.getBlue()));
1464 if (line.length() > 64)
1466 append(line.toString());
1467 line = new StringBuffer();
1471 if (line.length() > 0)
1473 append(line.toString());
1482 * Disposes of all resources used by this EpsGraphics2D object. If this is the
1483 * only remaining EpsGraphics2D instance pointing at a EpsDocument object,
1484 * then the EpsDocument object shall become eligible for garbage collection.
1487 public void dispose()
1492 /* bsoares 2019-03-20
1493 * finalize is now deprecated. Implementing AutoCloseable instead
1495 * Finalizes the object.
1497 public void finalize()
1504 * Returns the entire contents of the EPS document, complete with headers and
1505 * bounding box. The returned String is suitable for being written directly to
1506 * disk as an EPS file.
1509 public String toString()
1511 StringWriter writer = new StringWriter();
1514 _document.write(writer);
1517 } catch (IOException e)
1519 throw new EpsException(e.toString());
1521 return writer.toString();
1525 * Returns true if the specified rectangular area might intersect the current
1529 public boolean hitClip(int x, int y, int width, int height)
1535 Rectangle rect = new Rectangle(x, y, width, height);
1536 return hit(rect, _clip, true);
1540 * Returns the bounding rectangle of the current clipping area.
1543 public Rectangle getClipBounds(Rectangle r)
1549 Rectangle rect = getClipBounds();
1550 r.setLocation((int) rect.getX(), (int) rect.getY());
1551 r.setSize((int) rect.getWidth(), (int) rect.getHeight());
1555 private Color _color;
1557 private Color _backgroundColor;
1559 private Paint _paint;
1561 private Composite _composite;
1563 private BasicStroke _stroke;
1567 private Shape _clip;
1569 private AffineTransform _clipTransform;
1571 private AffineTransform _transform;
1573 private boolean _accurateTextMode;
1575 private EpsDocument _document;
1577 private static FontRenderContext _fontRenderContext = new FontRenderContext(