2 Copyright Paul James Mutton, 2001-2004, http://www.jibble.org/
\r
4 This file is part of EpsGraphics2D.
\r
6 This software is dual-licensed, allowing you to choose between the GNU
\r
7 General Public License (GPL) and the www.jibble.org Commercial License.
\r
8 Since the GPL may be too restrictive for use in a proprietary application,
\r
9 a commercial license is also provided. Full license information can be
\r
10 found at http://www.jibble.org/licenses/
\r
17 package org.jibble.epsgraphics;
\r
20 import java.awt.image.*;
\r
21 import java.awt.image.renderable.*;
\r
22 import java.awt.geom.*;
\r
25 import java.awt.font.*;
\r
30 * EpsGraphics2D is suitable for creating high quality EPS graphics for
\r
31 * use in documents and papers, and can be used just like a standard
\r
32 * Graphics2D object.
\r
34 * Many Java programs use Graphics2D to draw stuff on the screen, and while
\r
35 * it is easy to save the output as a png or jpeg file, it is a little
\r
36 * harder to export it as an EPS for including in a document or paper.
\r
38 * This class makes the whole process extremely easy, because you can use
\r
39 * it as if it's a Graphics2D object. The only difference is that all of
\r
40 * the implemented methods create EPS output, which means the diagrams you
\r
41 * draw can be resized without leading to any of the jagged edges you may
\r
42 * see when resizing pixel-based images, such as jpeg and png files.
\r
46 * <pre> Graphics2D g = new EpsGraphics2D();
\r
47 * g.setColor(Color.black);
\r
49 * // Line thickness 2.
\r
50 * g.setStroke(new BasicStroke(2.0f));
\r
53 * g.drawLine(10, 10, 50, 10);
\r
55 * // Fill a rectangle in blue
\r
56 * g.setColor(Color.blue);
\r
57 * g.fillRect(10, 0, 20, 20);
\r
59 * // Get the EPS output.
\r
60 * String output = g.toString();</pre>
\r
62 * You do not need to worry about the size of the canvas when drawing on a
\r
63 * EpsGraphics2D object. The bounding box of the EPS document will
\r
64 * automatically resize to accomodate new items that you draw.
\r
66 * Not all methods are implemented yet. Those that are not are clearly
\r
69 * Copyright Paul Mutton,
\r
70 * <a href="http://www.jibble.org/">http://www.jibble.org/</a>
\r
73 public class EpsGraphics2D extends java.awt.Graphics2D {
\r
76 public static final String VERSION = "0.8.8";
\r
80 * Constructs a new EPS document that is initially empty and can be
\r
81 * drawn on like a Graphics2D object. The EPS document is stored in
\r
84 public EpsGraphics2D() {
\r
90 * Constructs a new EPS document that is initially empty and can be
\r
91 * drawn on like a Graphics2D object. The EPS document is stored in
\r
94 public EpsGraphics2D(String title) {
\r
95 _document = new EpsDocument(title);
\r
96 _backgroundColor = Color.white;
\r
98 _transform = new AffineTransform();
\r
99 _clipTransform = new AffineTransform();
\r
100 _accurateTextMode = true;
\r
101 setColor(Color.black);
\r
102 setPaint(Color.black);
\r
103 setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
\r
104 setFont(Font.decode(null));
\r
105 setStroke(new BasicStroke());
\r
110 * Constructs a new EPS document that is initially empty and can be
\r
111 * drawn on like a Graphics2D object. The EPS document is written to
\r
112 * the file as it goes, which reduces memory usage. The bounding box of
\r
113 * the document is fixed and specified at construction time by
\r
114 * minX,minY,maxX,maxY. The file is flushed and closed when the close()
\r
115 * method is called.
\r
117 public EpsGraphics2D(String title, File file, int minX, int minY, int maxX, int maxY) throws IOException {
\r
118 this(title, new FileOutputStream(file), minX, minY, maxX, maxY);
\r
123 * Constructs a new EPS document that is initially empty and can be
\r
124 * drawn on like a Graphics2D object. The EPS document is written to
\r
125 * the output stream as it goes, which reduces memory usage. The
\r
126 * bounding box of the document is fixed and specified at construction
\r
127 * time by minX,minY,maxX,maxY. The output stream is flushed and closed
\r
128 * when the close() method is called.
\r
130 public EpsGraphics2D(String title, OutputStream outputStream, int minX, int minY, int maxX, int maxY) throws IOException {
\r
132 _document = new EpsDocument(title, outputStream, minX, minY, maxX, maxY);
\r
137 * Constructs a new EpsGraphics2D instance that is a copy of the
\r
138 * supplied argument and points at the same EpsDocument.
\r
140 protected EpsGraphics2D(EpsGraphics2D g) {
\r
141 _document = g._document;
\r
142 _backgroundColor = g._backgroundColor;
\r
144 _clipTransform = (AffineTransform) g._clipTransform.clone();
\r
145 _transform = (AffineTransform) g._transform.clone();
\r
148 _composite = g._composite;
\r
150 _stroke = g._stroke;
\r
151 _accurateTextMode = g._accurateTextMode;
\r
156 * This method is called to indicate that a particular method is not
\r
157 * supported yet. The stack trace is printed to the standard output.
\r
159 private void methodNotSupported() {
\r
160 EpsException e = new EpsException("Method not currently supported by EpsGraphics2D version " + VERSION);
\r
161 e.printStackTrace(System.err);
\r
165 /////////////// Specialist methods ///////////////////////
\r
169 * Sets whether to use accurate text mode when rendering text in EPS.
\r
170 * This is enabled (true) by default. When accurate text mode is used,
\r
171 * all text will be rendered in EPS to appear exactly the same as it
\r
172 * would do when drawn with a Graphics2D context. With accurate text
\r
173 * mode enabled, it is not necessary for the EPS viewer to have the
\r
174 * required font installed.
\r
176 * Turning off accurate text mode will require the EPS viewer to have
\r
177 * the necessary fonts installed. If you are using a lot of text, you
\r
178 * will find that this significantly reduces the file size of your EPS
\r
179 * documents. AffineTransforms can only affect the starting point of
\r
180 * text using this simpler text mode - all text will be horizontal.
\r
182 public void setAccurateTextMode(boolean b) {
\r
183 _accurateTextMode = b;
\r
188 * Returns whether accurate text mode is being used.
\r
190 public boolean getAccurateTextMode() {
\r
191 return _accurateTextMode;
\r
196 * Flushes the buffered contents of this EPS document to the underlying
\r
197 * OutputStream it is being written to.
\r
199 public void flush() throws IOException {
\r
205 * Closes the EPS file being output to the underlying OutputStream.
\r
206 * The OutputStream is automatically flushed before being closed.
\r
207 * If you forget to do this, the file may be incomplete.
\r
209 public void close() throws IOException {
\r
216 * Appends a line to the EpsDocument.
\r
218 private void append(String line) {
\r
219 _document.append(this, line);
\r
224 * Returns the point after it has been transformed by the transformation.
\r
226 private Point2D transform(float x, float y) {
\r
227 Point2D result = new Point2D.Float(x, y);
\r
228 result = _transform.transform(result, result);
\r
229 result.setLocation(result.getX(), -result.getY());
\r
235 * Appends the commands required to draw a shape on the EPS document.
\r
237 private void draw(Shape s, String action) {
\r
241 //Rectangle2D userBounds = s.getBounds2D();
\r
242 if (!_transform.isIdentity()) {
\r
243 s = _transform.createTransformedShape(s);
\r
246 // Update the bounds.
\r
247 if (!action.equals("clip")) {
\r
248 Rectangle2D shapeBounds = s.getBounds2D();
\r
249 Rectangle2D visibleBounds = shapeBounds;
\r
250 if (_clip != null) {
\r
251 Rectangle2D clipBounds = _clip.getBounds2D();
\r
252 visibleBounds = shapeBounds.createIntersection(clipBounds);
\r
254 float lineRadius = _stroke.getLineWidth() / 2;
\r
255 float minX = (float) visibleBounds.getMinX() - lineRadius;
\r
256 float minY = (float) visibleBounds.getMinY() - lineRadius;
\r
257 float maxX = (float) visibleBounds.getMaxX() + lineRadius;
\r
258 float maxY = (float) visibleBounds.getMaxY() + lineRadius;
\r
259 _document.updateBounds(minX, -minY);
\r
260 _document.updateBounds(maxX, -maxY);
\r
265 float[] coords = new float[6];
\r
266 PathIterator it = s.getPathIterator(null);
\r
270 while (!it.isDone()) {
\r
271 type = it.currentSegment(coords);
\r
272 float x1 = coords[0];
\r
273 float y1 = -coords[1];
\r
274 float x2 = coords[2];
\r
275 float y2 = -coords[3];
\r
276 float x3 = coords[4];
\r
277 float y3 = -coords[5];
\r
279 if (type == PathIterator.SEG_CLOSE) {
\r
280 append("closepath");
\r
283 else if (type == PathIterator.SEG_CUBICTO) {
\r
284 append(x1 + " " + y1 + " " + x2 + " " + y2 + " " + x3 + " " + y3 + " curveto");
\r
289 else if (type == PathIterator.SEG_LINETO) {
\r
290 append(x1 + " " + y1 + " lineto");
\r
295 else if (type == PathIterator.SEG_MOVETO) {
\r
296 append(x1 + " " + y1 + " moveto");
\r
301 else if (type == PathIterator.SEG_QUADTO) {
\r
302 // Convert the quad curve into a cubic.
\r
303 float _x1 = x0 + 2 / 3f * (x1 - x0);
\r
304 float _y1 = y0 + 2 / 3f * (y1 - y0);
\r
305 float _x2 = x1 + 1 / 3f * (x2 - x1);
\r
306 float _y2 = y1 + 1 / 3f * (y2 - y1);
\r
309 append(_x1 + " " + _y1 + " " + _x2 + " " + _y2 + " " + _x3 + " " + _y3 + " curveto");
\r
314 else if (type == PathIterator.WIND_EVEN_ODD) {
\r
317 else if (type == PathIterator.WIND_NON_ZERO) {
\r
329 * Returns a hex string that always contains two characters.
\r
331 private String toHexString(int n) {
\r
332 String result = Integer.toString(n, 16);
\r
333 while (result.length() < 2) {
\r
334 result = "0" + result;
\r
340 /////////////// Graphics2D methods ///////////////////////
\r
344 * Draws a 3D rectangle outline. If it is raised, light appears to come
\r
345 * from the top left.
\r
347 public void draw3DRect(int x, int y, int width, int height, boolean raised) {
\r
348 Color originalColor = getColor();
\r
349 Stroke originalStroke = getStroke();
\r
351 setStroke(new BasicStroke(1.0f));
\r
354 setColor(originalColor.brighter());
\r
357 setColor(originalColor.darker());
\r
360 drawLine(x, y, x + width, y);
\r
361 drawLine(x, y, x, y + height);
\r
364 setColor(originalColor.darker());
\r
367 setColor(originalColor.brighter());
\r
370 drawLine(x + width, y + height, x, y + height);
\r
371 drawLine(x + width, y + height, x + width, y);
\r
373 setColor(originalColor);
\r
374 setStroke(originalStroke);
\r
379 * Fills a 3D rectangle. If raised, it has bright fill and light appears
\r
380 * to come from the top left.
\r
382 public void fill3DRect(int x, int y, int width, int height, boolean raised) {
\r
383 Color originalColor = getColor();
\r
386 setColor(originalColor.brighter());
\r
389 setColor(originalColor.darker());
\r
391 draw(new Rectangle(x, y, width, height), "fill");
\r
392 setColor(originalColor);
\r
393 draw3DRect(x, y, width, height, raised);
\r
398 * Draws a Shape on the EPS document.
\r
400 public void draw(Shape s) {
\r
406 * Draws an Image on the EPS document.
\r
408 public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
\r
409 AffineTransform at = getTransform();
\r
411 boolean st = drawImage(img, 0, 0, obs);
\r
418 * Draws a BufferedImage on the EPS document.
\r
420 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
\r
421 BufferedImage img1 = op.filter(img, null);
\r
422 drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null);
\r
427 * Draws a RenderedImage on the EPS document.
\r
429 public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
\r
430 Hashtable properties = new Hashtable();
\r
431 String[] names = img.getPropertyNames();
\r
432 for (int i = 0; i < names.length; i++) {
\r
433 properties.put(names[i], img.getProperty(names[i]));
\r
436 ColorModel cm = img.getColorModel();
\r
437 WritableRaster wr = img.copyData(null);
\r
438 BufferedImage img1 = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties);
\r
439 AffineTransform at = AffineTransform.getTranslateInstance(img.getMinX(), img.getMinY());
\r
440 at.preConcatenate(xform);
\r
441 drawImage(img1, at, null);
\r
446 * Draws a RenderableImage by invoking its createDefaultRendering method.
\r
448 public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
\r
449 drawRenderedImage(img.createDefaultRendering(), xform);
\r
454 * Draws a string at (x,y)
\r
456 public void drawString(String str, int x, int y) {
\r
457 drawString(str, (float) x, (float) y);
\r
462 * Draws a string at (x,y)
\r
464 public void drawString(String s, float x, float y) {
\r
465 if (s != null && s.length() > 0) {
\r
466 AttributedString as = new AttributedString(s);
\r
467 as.addAttribute(TextAttribute.FONT, getFont());
\r
468 drawString(as.getIterator(), x, y);
\r
474 * Draws the characters of an AttributedCharacterIterator, starting from
\r
477 public void drawString(AttributedCharacterIterator iterator, int x, int y) {
\r
478 drawString(iterator, (float) x, (float) y);
\r
483 * Draws the characters of an AttributedCharacterIterator, starting from
\r
486 public void drawString(AttributedCharacterIterator iterator, float x, float y) {
\r
487 if (getAccurateTextMode()) {
\r
488 TextLayout layout = new TextLayout(iterator, getFontRenderContext());
\r
489 Shape shape = layout.getOutline(AffineTransform.getTranslateInstance(x, y));
\r
490 draw(shape, "fill");
\r
494 Point2D location = transform(x, y);
\r
495 append(location.getX() + " " + location.getY() + " moveto");
\r
496 StringBuffer buffer = new StringBuffer();
\r
497 for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator.next()) {
\r
498 if (ch == '(' || ch == ')') {
\r
499 buffer.append('\\');
\r
503 append("(" + buffer.toString() + ") show");
\r
509 * Draws a GlyphVector at (x,y)
\r
511 public void drawGlyphVector(GlyphVector g, float x, float y) {
\r
512 Shape shape = g.getOutline(x, y);
\r
513 draw(shape, "fill");
\r
518 * Fills a Shape on the EPS document.
\r
520 public void fill(Shape s) {
\r
526 * Checks whether or not the specified Shape intersects the specified
\r
527 * Rectangle, which is in device space.
\r
529 public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
\r
530 return s.intersects(rect);
\r
535 * Returns the device configuration associated with this EpsGraphics2D
\r
538 public GraphicsConfiguration getDeviceConfiguration() {
\r
539 GraphicsConfiguration gc = null;
\r
540 GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
\r
541 GraphicsDevice[] gds = ge.getScreenDevices();
\r
542 for (int i = 0; i < gds.length; i++) {
\r
543 GraphicsDevice gd = gds[i];
\r
544 GraphicsConfiguration[] gcs = gd.getConfigurations();
\r
545 if (gcs.length > 0) {
\r
554 * Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D
\r
555 * does not make use of these.
\r
557 public void setComposite(Composite comp) {
\r
563 * Sets the Paint attribute for the EpsGraphics2D object. Only Paint
\r
564 * objects of type Color are respected by EpsGraphics2D.
\r
566 public void setPaint(Paint paint) {
\r
568 if (paint instanceof Color) {
\r
569 setColor((Color) paint);
\r
575 * Sets the stroke. Only accepts BasicStroke objects (or subclasses of
\r
578 public void setStroke(Stroke s) {
\r
579 if (s instanceof BasicStroke) {
\r
580 _stroke = (BasicStroke) s;
\r
582 append(_stroke.getLineWidth() + " setlinewidth");
\r
583 float miterLimit = _stroke.getMiterLimit();
\r
584 if (miterLimit < 1.0f) {
\r
587 append(miterLimit + " setmiterlimit");
\r
588 append(_stroke.getLineJoin() + " setlinejoin");
\r
589 append(_stroke.getEndCap() + " setlinecap");
\r
591 StringBuffer dashes = new StringBuffer();
\r
592 dashes.append("[ ");
\r
593 float[] dashArray = _stroke.getDashArray();
\r
594 if (dashArray != null) {
\r
595 for (int i = 0; i < dashArray.length; i++) {
\r
596 dashes.append((dashArray[i]) + " ");
\r
599 dashes.append("]");
\r
600 append(dashes.toString() + " 0 setdash");
\r
606 * Sets a rendering hint. These are not used by EpsGraphics2D.
\r
608 public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
\r
614 * Returns the value of a single preference for the rendering
\r
615 * algorithms. Rendering hints are not used by EpsGraphics2D.
\r
617 public Object getRenderingHint(RenderingHints.Key hintKey) {
\r
623 * Sets the rendering hints. These are ignored by EpsGraphics2D.
\r
625 public void setRenderingHints(Map hints) {
\r
631 * Adds rendering hints. These are ignored by EpsGraphics2D.
\r
633 public void addRenderingHints(Map hints) {
\r
639 * Returns the preferences for the rendering algorithms.
\r
641 public RenderingHints getRenderingHints() {
\r
642 return new RenderingHints(null);
\r
647 * Translates the origin of the EpsGraphics2D context to the point (x,y)
\r
648 * in the current coordinate system.
\r
650 public void translate(int x, int y) {
\r
651 translate((double) x, (double) y);
\r
656 * Concatenates the current EpsGraphics2D Transformation with a
\r
657 * translation transform.
\r
659 public void translate(double tx, double ty) {
\r
660 transform(AffineTransform.getTranslateInstance(tx, ty));
\r
665 * Concatenates the current EpsGraphics2D Transform with a rotation
\r
668 public void rotate(double theta) {
\r
669 rotate(theta, 0, 0);
\r
674 * Concatenates the current EpsGraphics2D Transform with a translated
\r
675 * rotation transform.
\r
677 public void rotate(double theta, double x, double y) {
\r
678 transform(AffineTransform.getRotateInstance(theta, x, y));
\r
683 * Concatenates the current EpsGraphics2D Transform with a scaling
\r
686 public void scale(double sx, double sy) {
\r
687 transform(AffineTransform.getScaleInstance(sx, sy));
\r
692 * Concatenates the current EpsGraphics2D Transform with a shearing
\r
695 public void shear(double shx, double shy) {
\r
696 transform(AffineTransform.getShearInstance(shx, shy));
\r
701 * Composes an AffineTransform object with the Transform in this
\r
702 * EpsGraphics2D according to the rule last-specified-first-applied.
\r
704 public void transform(AffineTransform Tx) {
\r
705 _transform.concatenate(Tx);
\r
706 setTransform(getTransform());
\r
711 * Sets the AffineTransform to be used by this EpsGraphics2D.
\r
713 public void setTransform(AffineTransform Tx) {
\r
715 _transform = new AffineTransform();
\r
718 _transform = new AffineTransform(Tx);
\r
720 // Need to update the stroke and font so they know the scale changed
\r
721 setStroke(getStroke());
\r
722 setFont(getFont());
\r
727 * Gets the AffineTransform used by this EpsGraphics2D.
\r
729 public AffineTransform getTransform() {
\r
730 return new AffineTransform(_transform);
\r
735 * Returns the current Paint of the EpsGraphics2D object.
\r
737 public Paint getPaint() {
\r
743 * returns the current Composite of the EpsGraphics2D object.
\r
745 public Composite getComposite() {
\r
751 * Sets the background color to be used by the clearRect method.
\r
753 public void setBackground(Color color) {
\r
754 if (color == null) {
\r
755 color = Color.black;
\r
757 _backgroundColor = color;
\r
762 * Gets the background color that is used by the clearRect method.
\r
764 public Color getBackground() {
\r
765 return _backgroundColor;
\r
770 * Returns the Stroke currently used. Guaranteed to be an instance of
\r
773 public Stroke getStroke() {
\r
779 * Intersects the current clip with the interior of the specified Shape
\r
780 * and sets the clip to the resulting intersection.
\r
782 public void clip(Shape s) {
\r
783 if (_clip == null) {
\r
787 Area area = new Area(_clip);
\r
788 area.intersect(new Area(s));
\r
795 * Returns the FontRenderContext.
\r
797 public FontRenderContext getFontRenderContext() {
\r
798 return _fontRenderContext;
\r
802 /////////////// Graphics methods ///////////////////////
\r
806 * Returns a new Graphics object that is identical to this EpsGraphics2D.
\r
808 public Graphics create() {
\r
809 return new EpsGraphics2D(this);
\r
814 * Returns an EpsGraphics2D object based on this
\r
815 * Graphics object, but with a new translation and clip
\r
818 public Graphics create(int x, int y, int width, int height) {
\r
819 Graphics g = create();
\r
821 g.clipRect(0, 0, width, height);
\r
827 * Returns the current Color. This will be a default value (black)
\r
828 * until it is changed using the setColor method.
\r
830 public Color getColor() {
\r
836 * Sets the Color to be used when drawing all future shapes, text, etc.
\r
838 public void setColor(Color c) {
\r
843 append((c.getRed() / 255f) + " " + (c.getGreen() / 255f) + " " + (c.getBlue() / 255f) + " setrgbcolor");
\r
848 * Sets the paint mode of this EpsGraphics2D object to overwrite the
\r
849 * destination EpsDocument with the current color.
\r
851 public void setPaintMode() {
\r
852 // Do nothing - paint mode is the only method supported anyway.
\r
857 * <b><i><font color="red">Not implemented</font></i></b> - performs no action.
\r
859 public void setXORMode(Color c1) {
\r
860 methodNotSupported();
\r
865 * Returns the Font currently being used.
\r
867 public Font getFont() {
\r
873 * Sets the Font to be used in future text.
\r
875 public void setFont(Font font) {
\r
876 if (font == null) {
\r
877 font = Font.decode(null);
\r
880 append("/" + _font.getPSName() + " findfont " + ((int) _font.getSize()) + " scalefont setfont");
\r
885 * Gets the font metrics of the current font.
\r
887 public FontMetrics getFontMetrics() {
\r
888 return getFontMetrics(getFont());
\r
893 * Gets the font metrics for the specified font.
\r
895 public FontMetrics getFontMetrics(Font f) {
\r
896 BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
\r
897 Graphics g = image.getGraphics();
\r
898 return g.getFontMetrics(f);
\r
903 * Returns the bounding rectangle of the current clipping area.
\r
905 public Rectangle getClipBounds() {
\r
906 if (_clip == null) {
\r
909 Rectangle rect = getClip().getBounds();
\r
915 * Intersects the current clip with the specified rectangle.
\r
917 public void clipRect(int x, int y, int width, int height) {
\r
918 clip(new Rectangle(x, y, width, height));
\r
923 * Sets the current clip to the rectangle specified by the given
\r
926 public void setClip(int x, int y, int width, int height) {
\r
927 setClip(new Rectangle(x, y, width, height));
\r
932 * Gets the current clipping area.
\r
934 public Shape getClip() {
\r
935 if (_clip == null) {
\r
940 AffineTransform t = _transform.createInverse();
\r
941 t.concatenate(_clipTransform);
\r
942 return t.createTransformedShape(_clip);
\r
944 catch (Exception e) {
\r
945 throw new EpsException("Unable to get inverse of matrix: " + _transform);
\r
952 * Sets the current clipping area to an arbitrary clip shape.
\r
954 public void setClip(Shape clip) {
\r
955 if (clip != null) {
\r
956 if (_document.isClipSet()) {
\r
957 append("grestore");
\r
961 _document.setClipSet(true);
\r
964 draw(clip, "clip");
\r
966 _clipTransform = (AffineTransform) _transform.clone();
\r
969 if (_document.isClipSet()) {
\r
970 append("grestore");
\r
971 _document.setClipSet(false);
\r
979 * <b><i><font color="red">Not implemented</font></i></b> - performs no action.
\r
981 public void copyArea(int x, int y, int width, int height, int dx, int dy) {
\r
982 methodNotSupported();
\r
987 * Draws a straight line from (x1,y1) to (x2,y2).
\r
989 public void drawLine(int x1, int y1, int x2, int y2) {
\r
990 Shape shape = new Line2D.Float(x1, y1, x2, y2);
\r
996 * Fills a rectangle with top-left corner placed at (x,y).
\r
998 public void fillRect(int x, int y, int width, int height) {
\r
999 Shape shape = new Rectangle(x, y, width, height);
\r
1000 draw(shape, "fill");
\r
1005 * Draws a rectangle with top-left corner placed at (x,y).
\r
1007 public void drawRect(int x, int y, int width, int height) {
\r
1008 Shape shape = new Rectangle(x, y, width, height);
\r
1014 * Clears a rectangle with top-left corner placed at (x,y) using the
\r
1015 * current background color.
\r
1017 public void clearRect(int x, int y, int width, int height) {
\r
1018 Color originalColor = getColor();
\r
1020 setColor(getBackground());
\r
1021 Shape shape = new Rectangle(x, y, width, height);
\r
1022 draw(shape, "fill");
\r
1024 setColor(originalColor);
\r
1029 * Draws a rounded rectangle.
\r
1031 public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
\r
1032 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight);
\r
1038 * Fills a rounded rectangle.
\r
1040 public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
\r
1041 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight);
\r
1042 draw(shape, "fill");
\r
1049 public void drawOval(int x, int y, int width, int height) {
\r
1050 Shape shape = new Ellipse2D.Float(x, y, width, height);
\r
1058 public void fillOval(int x, int y, int width, int height) {
\r
1059 Shape shape = new Ellipse2D.Float(x, y, width, height);
\r
1060 draw(shape, "fill");
\r
1067 public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
\r
1068 Shape shape = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
\r
1076 public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
\r
1077 Shape shape = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
\r
1078 draw(shape, "fill");
\r
1083 * Draws a polyline.
\r
1085 public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
\r
1086 if (nPoints > 0) {
\r
1087 GeneralPath path = new GeneralPath();
\r
1088 path.moveTo(xPoints[0], yPoints[0]);
\r
1089 for (int i = 1; i < nPoints; i++) {
\r
1090 path.lineTo(xPoints[i], yPoints[i]);
\r
1098 * Draws a polygon made with the specified points.
\r
1100 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
\r
1101 Shape shape = new Polygon(xPoints, yPoints, nPoints);
\r
1107 * Draws a polygon.
\r
1109 public void drawPolygon(Polygon p) {
\r
1115 * Fills a polygon made with the specified points.
\r
1117 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
\r
1118 Shape shape = new Polygon(xPoints, yPoints, nPoints);
\r
1119 draw(shape, "fill");
\r
1124 * Fills a polygon.
\r
1126 public void fillPolygon(Polygon p) {
\r
1132 * Draws the specified characters, starting from (x,y)
\r
1134 public void drawChars(char[] data, int offset, int length, int x, int y) {
\r
1135 String string = new String(data, offset, length);
\r
1136 drawString(string, x, y);
\r
1141 * Draws the specified bytes, starting from (x,y)
\r
1143 public void drawBytes(byte[] data, int offset, int length, int x, int y) {
\r
1144 String string = new String(data, offset, length);
\r
1145 drawString(string, x, y);
\r
1152 public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
\r
1153 return drawImage(img, x, y, Color.white, observer);
\r
1160 public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
\r
1161 return drawImage(img, x, y, width, height, Color.white, observer);
\r
1168 public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
\r
1169 int width = img.getWidth(null);
\r
1170 int height = img.getHeight(null);
\r
1171 return drawImage(img, x, y, width, height, bgcolor, observer);
\r
1178 public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
\r
1179 return drawImage(img, x, y, x + width, y + height, 0, 0, width, height, bgcolor, observer);
\r
1186 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) {
\r
1187 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, Color.white, observer);
\r
1194 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) {
\r
1196 throw new IllegalArgumentException("dx1 >= dx2");
\r
1199 throw new IllegalArgumentException("sx1 >= sx2");
\r
1202 throw new IllegalArgumentException("dy1 >= dy2");
\r
1205 throw new IllegalArgumentException("sy1 >= sy2");
\r
1210 int width = sx2 - sx1;
\r
1211 int height = sy2 - sy1;
\r
1212 int destWidth = dx2 - dx1;
\r
1213 int destHeight = dy2 - dy1;
\r
1215 int[] pixels = new int[width * height];
\r
1216 PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sx2 - sx1, sy2 - sy1, pixels, 0, width);
\r
1220 catch(InterruptedException e) {
\r
1224 AffineTransform matrix = new AffineTransform(_transform);
\r
1225 matrix.translate(dx1, dy1);
\r
1226 matrix.scale(destWidth / (double) width, destHeight / (double) height);
\r
1227 double[] m = new double[6];
\r
1229 matrix = matrix.createInverse();
\r
1231 catch (Exception e) {
\r
1232 throw new EpsException("Unable to get inverse of matrix: " + matrix);
\r
1234 matrix.scale(1, -1);
\r
1235 matrix.getMatrix(m);
\r
1236 append(width + " " + height + " 8 [" + m[0] + " " + m[1] + " " + m[2] + " " + m[3] + " " + m[4] + " " + m[5] + "]");
\r
1237 // Fill the background to update the bounding box.
\r
1238 Color oldColor = getColor();
\r
1239 setColor(getBackground());
\r
1240 fillRect(dx1, dy1, destWidth, destHeight);
\r
1241 setColor(oldColor);
\r
1242 append("{currentfile 3 " + width + " mul string readhexstring pop} bind");
\r
1243 append("false 3 colorimage");
\r
1244 StringBuffer line = new StringBuffer();
\r
1245 for (int y = 0; y < height; y++) {
\r
1246 for (int x = 0; x < width; x++) {
\r
1247 Color color = new Color(pixels[x + width * y]);
\r
1248 line.append(toHexString(color.getRed()) + toHexString(color.getGreen()) + toHexString(color.getBlue()));
\r
1249 if (line.length() > 64) {
\r
1250 append(line.toString());
\r
1251 line = new StringBuffer();
\r
1255 if (line.length() > 0) {
\r
1256 append(line.toString());
\r
1259 append("grestore");
\r
1266 * Disposes of all resources used by this EpsGraphics2D object.
\r
1267 * If this is the only remaining EpsGraphics2D instance pointing at
\r
1268 * a EpsDocument object, then the EpsDocument object shall become
\r
1269 * eligible for garbage collection.
\r
1271 public void dispose() {
\r
1277 * Finalizes the object.
\r
1279 public void finalize() {
\r
1285 * Returns the entire contents of the EPS document, complete with
\r
1286 * headers and bounding box. The returned String is suitable for
\r
1287 * being written directly to disk as an EPS file.
\r
1289 public String toString() {
\r
1290 StringWriter writer = new StringWriter();
\r
1292 _document.write(writer);
\r
1293 _document.flush();
\r
1294 _document.close();
\r
1296 catch (IOException e) {
\r
1297 throw new EpsException(e.toString());
\r
1299 return writer.toString();
\r
1304 * Returns true if the specified rectangular area might intersect the
\r
1305 * current clipping area.
\r
1307 public boolean hitClip(int x, int y, int width, int height) {
\r
1308 if (_clip == null) {
\r
1311 Rectangle rect = new Rectangle(x, y, width, height);
\r
1312 return hit(rect, _clip, true);
\r
1317 * Returns the bounding rectangle of the current clipping area.
\r
1319 public Rectangle getClipBounds(Rectangle r) {
\r
1320 if (_clip == null) {
\r
1323 Rectangle rect = getClipBounds();
\r
1324 r.setLocation((int) rect.getX(), (int) rect.getY());
\r
1325 r.setSize((int) rect.getWidth(), (int) rect.getHeight());
\r
1330 private Color _color;
\r
1331 private Color _backgroundColor;
\r
1332 private Paint _paint;
\r
1333 private Composite _composite;
\r
1334 private BasicStroke _stroke;
\r
1335 private Font _font;
\r
1336 private Shape _clip;
\r
1337 private AffineTransform _clipTransform;
\r
1338 private AffineTransform _transform;
\r
1339 private boolean _accurateTextMode;
\r
1341 private EpsDocument _document;
\r
1343 private static FontRenderContext _fontRenderContext = new FontRenderContext(null, false, true);
\r