Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package org.jibble.epsgraphics

File EpsGraphics2D.java

 

Coverage histogram

../../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

100
388
97
1
1,492
930
153
0.39
4
97
1.58

Classes

Class Line # Actions
EpsGraphics2D 121 388 153 585
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package org.jibble.epsgraphics;
22   
23    import jalview.util.MessageManager;
24   
25    import java.awt.AlphaComposite;
26    import java.awt.BasicStroke;
27    import java.awt.Color;
28    import java.awt.Composite;
29    import java.awt.Font;
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;
64    import java.io.File;
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;
73    import java.util.Map;
74   
75    /**
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.
78    * <p>
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.
82    * <p>
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.
88    * <p>
89    * Example usage:
90    * <p>
91    *
92    * <pre>
93    * Graphics2D g = new EpsGraphics2D();
94    * g.setColor(Color.black);
95    *
96    * // Line thickness 2.
97    * g.setStroke(new BasicStroke(2.0f));
98    *
99    * // Draw a line.
100    * g.drawLine(10, 10, 50, 10);
101    *
102    * // Fill a rectangle in blue
103    * g.setColor(Color.blue);
104    * g.fillRect(10, 0, 20, 20);
105    *
106    * // Get the EPS output.
107    * String output = g.toString();
108    * </pre>
109    *
110    * <p>
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.
114    * <p>
115    * Not all methods are implemented yet. Those that are not are clearly labelled.
116    * <p>
117    * Copyright Paul Mutton, <a
118    * href="http://www.jibble.org/">http://www.jibble.org/</a>
119    *
120    */
 
121    public class EpsGraphics2D extends java.awt.Graphics2D
122    {
123   
124    public static final String VERSION = "0.8.8";
125   
126    /**
127    * Constructs a new EPS document that is initially empty and can be drawn on
128    * like a Graphics2D object. The EPS document is stored in memory.
129    */
 
130  0 toggle public EpsGraphics2D()
131    {
132  0 this("Untitled");
133    }
134   
135    /**
136    * Constructs a new EPS document that is initially empty and can be drawn on
137    * like a Graphics2D object. The EPS document is stored in memory.
138    */
 
139  0 toggle public EpsGraphics2D(String title)
140    {
141  0 _document = new EpsDocument(title);
142  0 _backgroundColor = Color.white;
143  0 _clip = null;
144  0 _transform = new AffineTransform();
145  0 _clipTransform = new AffineTransform();
146  0 _accurateTextMode = true;
147  0 setColor(Color.black);
148  0 setPaint(Color.black);
149  0 setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
150  0 setFont(Font.decode(null));
151  0 setStroke(new BasicStroke());
152    }
153   
154    /**
155    * Constructs a new EPS document that is initially empty and can be drawn on
156    * like a Graphics2D object. The EPS document is written to the file as it
157    * goes, which reduces memory usage. The bounding box of the document is fixed
158    * and specified at construction time by minX,minY,maxX,maxY. The file is
159    * flushed and closed when the close() method is called.
160    */
 
161  0 toggle public EpsGraphics2D(String title, File file, int minX, int minY,
162    int maxX, int maxY) throws IOException
163    {
164  0 this(title, new FileOutputStream(file), minX, minY, maxX, maxY);
165    }
166   
167    /**
168    * Constructs a new EPS document that is initially empty and can be drawn on
169    * like a Graphics2D object. The EPS document is written to the output stream
170    * as it goes, which reduces memory usage. The bounding box of the document is
171    * fixed and specified at construction time by minX,minY,maxX,maxY. The output
172    * stream is flushed and closed when the close() method is called.
173    */
 
174  0 toggle public EpsGraphics2D(String title, OutputStream outputStream, int minX,
175    int minY, int maxX, int maxY) throws IOException
176    {
177  0 this(title);
178  0 _document = new EpsDocument(title, outputStream, minX, minY, maxX, maxY);
179    }
180   
181    /**
182    * Constructs a new EpsGraphics2D instance that is a copy of the supplied
183    * argument and points at the same EpsDocument.
184    */
 
185  0 toggle protected EpsGraphics2D(EpsGraphics2D g)
186    {
187  0 _document = g._document;
188  0 _backgroundColor = g._backgroundColor;
189  0 _clip = g._clip;
190  0 _clipTransform = (AffineTransform) g._clipTransform.clone();
191  0 _transform = (AffineTransform) g._transform.clone();
192  0 _color = g._color;
193  0 _paint = g._paint;
194  0 _composite = g._composite;
195  0 _font = g._font;
196  0 _stroke = g._stroke;
197  0 _accurateTextMode = g._accurateTextMode;
198    }
199   
200    /**
201    * This method is called to indicate that a particular method is not supported
202    * yet. The stack trace is printed to the standard output.
203    */
 
204  0 toggle private void methodNotSupported()
205    {
206  0 EpsException e = new EpsException(MessageManager.formatMessage(
207    "exception.eps_method_not_supported", new String[] { VERSION }));
208  0 e.printStackTrace(System.err);
209    }
210   
211    // ///////////// Specialist methods ///////////////////////
212   
213    /**
214    * Sets whether to use accurate text mode when rendering text in EPS. This is
215    * enabled (true) by default. When accurate text mode is used, all text will
216    * be rendered in EPS to appear exactly the same as it would do when drawn
217    * with a Graphics2D context. With accurate text mode enabled, it is not
218    * necessary for the EPS viewer to have the required font installed.
219    * <p>
220    * Turning off accurate text mode will require the EPS viewer to have the
221    * necessary fonts installed. If you are using a lot of text, you will find
222    * that this significantly reduces the file size of your EPS documents.
223    * AffineTransforms can only affect the starting point of text using this
224    * simpler text mode - all text will be horizontal.
225    */
 
226  0 toggle public void setAccurateTextMode(boolean b)
227    {
228  0 _accurateTextMode = b;
229    }
230   
231    /**
232    * Returns whether accurate text mode is being used.
233    */
 
234  0 toggle public boolean getAccurateTextMode()
235    {
236  0 return _accurateTextMode;
237    }
238   
239    /**
240    * Flushes the buffered contents of this EPS document to the underlying
241    * OutputStream it is being written to.
242    */
 
243  0 toggle public void flush() throws IOException
244    {
245  0 _document.flush();
246    }
247   
248    /**
249    * Closes the EPS file being output to the underlying OutputStream. The
250    * OutputStream is automatically flushed before being closed. If you forget to
251    * do this, the file may be incomplete.
252    */
 
253  0 toggle public void close() throws IOException
254    {
255  0 flush();
256  0 _document.close();
257    }
258   
259    /**
260    * Appends a line to the EpsDocument.
261    */
 
262  0 toggle private void append(String line)
263    {
264  0 _document.append(this, line);
265    }
266   
267    /**
268    * Returns the point after it has been transformed by the transformation.
269    */
 
270  0 toggle private Point2D transform(float x, float y)
271    {
272  0 Point2D result = new Point2D.Float(x, y);
273  0 result = _transform.transform(result, result);
274  0 result.setLocation(result.getX(), -result.getY());
275  0 return result;
276    }
277   
278    /**
279    * Appends the commands required to draw a shape on the EPS document.
280    */
 
281  0 toggle private void draw(Shape s, String action)
282    {
283   
284  0 if (s != null)
285    {
286   
287    // Rectangle2D userBounds = s.getBounds2D();
288  0 if (!_transform.isIdentity())
289    {
290  0 s = _transform.createTransformedShape(s);
291    }
292   
293    // Update the bounds.
294  0 if (!action.equals("clip"))
295    {
296  0 Rectangle2D shapeBounds = s.getBounds2D();
297  0 Rectangle2D visibleBounds = shapeBounds;
298  0 if (_clip != null)
299    {
300  0 Rectangle2D clipBounds = _clip.getBounds2D();
301  0 visibleBounds = shapeBounds.createIntersection(clipBounds);
302    }
303  0 float lineRadius = _stroke.getLineWidth() / 2;
304  0 float minX = (float) visibleBounds.getMinX() - lineRadius;
305  0 float minY = (float) visibleBounds.getMinY() - lineRadius;
306  0 float maxX = (float) visibleBounds.getMaxX() + lineRadius;
307  0 float maxY = (float) visibleBounds.getMaxY() + lineRadius;
308  0 _document.updateBounds(minX, -minY);
309  0 _document.updateBounds(maxX, -maxY);
310    }
311   
312  0 append("newpath");
313  0 int type = 0;
314  0 float[] coords = new float[6];
315  0 PathIterator it = s.getPathIterator(null);
316  0 float x0 = 0;
317  0 float y0 = 0;
318  0 int count = 0;
319  0 while (!it.isDone())
320    {
321  0 type = it.currentSegment(coords);
322  0 float x1 = coords[0];
323  0 float y1 = -coords[1];
324  0 float x2 = coords[2];
325  0 float y2 = -coords[3];
326  0 float x3 = coords[4];
327  0 float y3 = -coords[5];
328   
329  0 if (type == PathIterator.SEG_CLOSE)
330    {
331  0 append("closepath");
332  0 count++;
333    }
334  0 else if (type == PathIterator.SEG_CUBICTO)
335    {
336  0 append(x1 + " " + y1 + " " + x2 + " " + y2 + " " + x3 + " " + y3
337    + " curveto");
338  0 count++;
339  0 x0 = x3;
340  0 y0 = y3;
341    }
342  0 else if (type == PathIterator.SEG_LINETO)
343    {
344  0 append(x1 + " " + y1 + " lineto");
345  0 count++;
346  0 x0 = x1;
347  0 y0 = y1;
348    }
349  0 else if (type == PathIterator.SEG_MOVETO)
350    {
351  0 append(x1 + " " + y1 + " moveto");
352  0 count++;
353  0 x0 = x1;
354  0 y0 = y1;
355    }
356  0 else if (type == PathIterator.SEG_QUADTO)
357    {
358    // Convert the quad curve into a cubic.
359  0 float _x1 = x0 + 2 / 3f * (x1 - x0);
360  0 float _y1 = y0 + 2 / 3f * (y1 - y0);
361  0 float _x2 = x1 + 1 / 3f * (x2 - x1);
362  0 float _y2 = y1 + 1 / 3f * (y2 - y1);
363  0 float _x3 = x2;
364  0 float _y3 = y2;
365  0 append(_x1 + " " + _y1 + " " + _x2 + " " + _y2 + " " + _x3 + " "
366    + _y3 + " curveto");
367  0 count++;
368  0 x0 = _x3;
369  0 y0 = _y3;
370    }
371  0 else if (type == PathIterator.WIND_EVEN_ODD)
372    {
373    // Ignore.
374    }
375  0 else if (type == PathIterator.WIND_NON_ZERO)
376    {
377    // Ignore.
378    }
379  0 it.next();
380    }
381  0 append(action);
382  0 append("newpath");
383    }
384    }
385   
386    /**
387    * Returns a hex string that always contains two characters.
388    */
 
389  0 toggle private String toHexString(int n)
390    {
391  0 String result = Integer.toString(n, 16);
392  0 while (result.length() < 2)
393    {
394  0 result = "0" + result;
395    }
396  0 return result;
397    }
398   
399    // ///////////// Graphics2D methods ///////////////////////
400   
401    /**
402    * Draws a 3D rectangle outline. If it is raised, light appears to come from
403    * the top left.
404    */
 
405  0 toggle public void draw3DRect(int x, int y, int width, int height, boolean raised)
406    {
407  0 Color originalColor = getColor();
408  0 Stroke originalStroke = getStroke();
409   
410  0 setStroke(new BasicStroke(1.0f));
411   
412  0 if (raised)
413    {
414  0 setColor(originalColor.brighter());
415    }
416    else
417    {
418  0 setColor(originalColor.darker());
419    }
420   
421  0 drawLine(x, y, x + width, y);
422  0 drawLine(x, y, x, y + height);
423   
424  0 if (raised)
425    {
426  0 setColor(originalColor.darker());
427    }
428    else
429    {
430  0 setColor(originalColor.brighter());
431    }
432   
433  0 drawLine(x + width, y + height, x, y + height);
434  0 drawLine(x + width, y + height, x + width, y);
435   
436  0 setColor(originalColor);
437  0 setStroke(originalStroke);
438    }
439   
440    /**
441    * Fills a 3D rectangle. If raised, it has bright fill and light appears to
442    * come from the top left.
443    */
 
444  0 toggle public void fill3DRect(int x, int y, int width, int height, boolean raised)
445    {
446  0 Color originalColor = getColor();
447   
448  0 if (raised)
449    {
450  0 setColor(originalColor.brighter());
451    }
452    else
453    {
454  0 setColor(originalColor.darker());
455    }
456  0 draw(new Rectangle(x, y, width, height), "fill");
457  0 setColor(originalColor);
458  0 draw3DRect(x, y, width, height, raised);
459    }
460   
461    /**
462    * Draws a Shape on the EPS document.
463    */
 
464  0 toggle public void draw(Shape s)
465    {
466  0 draw(s, "stroke");
467    }
468   
469    /**
470    * Draws an Image on the EPS document.
471    */
 
472  0 toggle public boolean drawImage(Image img, AffineTransform xform,
473    ImageObserver obs)
474    {
475  0 AffineTransform at = getTransform();
476  0 transform(xform);
477  0 boolean st = drawImage(img, 0, 0, obs);
478  0 setTransform(at);
479  0 return st;
480    }
481   
482    /**
483    * Draws a BufferedImage on the EPS document.
484    */
 
485  0 toggle public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y)
486    {
487  0 BufferedImage img1 = op.filter(img, null);
488  0 drawImage(img1, new AffineTransform(1f, 0f, 0f, 1f, x, y), null);
489    }
490   
491    /**
492    * Draws a RenderedImage on the EPS document.
493    */
 
494  0 toggle public void drawRenderedImage(RenderedImage img, AffineTransform xform)
495    {
496  0 Hashtable properties = new Hashtable();
497  0 String[] names = img.getPropertyNames();
498  0 for (int i = 0; i < names.length; i++)
499    {
500  0 properties.put(names[i], img.getProperty(names[i]));
501    }
502   
503  0 ColorModel cm = img.getColorModel();
504  0 WritableRaster wr = img.copyData(null);
505  0 BufferedImage img1 = new BufferedImage(cm, wr,
506    cm.isAlphaPremultiplied(), properties);
507  0 AffineTransform at = AffineTransform.getTranslateInstance(
508    img.getMinX(), img.getMinY());
509  0 at.preConcatenate(xform);
510  0 drawImage(img1, at, null);
511    }
512   
513    /**
514    * Draws a RenderableImage by invoking its createDefaultRendering method.
515    */
 
516  0 toggle public void drawRenderableImage(RenderableImage img, AffineTransform xform)
517    {
518  0 drawRenderedImage(img.createDefaultRendering(), xform);
519    }
520   
521    /**
522    * Draws a string at (x,y)
523    */
 
524  0 toggle public void drawString(String str, int x, int y)
525    {
526  0 drawString(str, (float) x, (float) y);
527    }
528   
529    /**
530    * Draws a string at (x,y)
531    */
 
532  0 toggle public void drawString(String s, float x, float y)
533    {
534  0 if (s != null && s.length() > 0)
535    {
536  0 AttributedString as = new AttributedString(s);
537  0 as.addAttribute(TextAttribute.FONT, getFont());
538  0 drawString(as.getIterator(), x, y);
539    }
540    }
541   
542    /**
543    * Draws the characters of an AttributedCharacterIterator, starting from
544    * (x,y).
545    */
 
546  0 toggle public void drawString(AttributedCharacterIterator iterator, int x, int y)
547    {
548  0 drawString(iterator, (float) x, (float) y);
549    }
550   
551    /**
552    * Draws the characters of an AttributedCharacterIterator, starting from
553    * (x,y).
554    */
 
555  0 toggle public void drawString(AttributedCharacterIterator iterator, float x,
556    float y)
557    {
558  0 if (getAccurateTextMode())
559    {
560  0 TextLayout layout = new TextLayout(iterator, getFontRenderContext());
561  0 Shape shape = layout.getOutline(AffineTransform.getTranslateInstance(
562    x, y));
563  0 draw(shape, "fill");
564    }
565    else
566    {
567  0 append("newpath");
568  0 Point2D location = transform(x, y);
569  0 append(location.getX() + " " + location.getY() + " moveto");
570  0 StringBuffer buffer = new StringBuffer();
571  0 for (char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator
572    .next())
573    {
574  0 if (ch == '(' || ch == ')')
575    {
576  0 buffer.append('\\');
577    }
578  0 buffer.append(ch);
579    }
580  0 append("(" + buffer.toString() + ") show");
581    }
582    }
583   
584    /**
585    * Draws a GlyphVector at (x,y)
586    */
 
587  0 toggle public void drawGlyphVector(GlyphVector g, float x, float y)
588    {
589  0 Shape shape = g.getOutline(x, y);
590  0 draw(shape, "fill");
591    }
592   
593    /**
594    * Fills a Shape on the EPS document.
595    */
 
596  0 toggle public void fill(Shape s)
597    {
598  0 draw(s, "fill");
599    }
600   
601    /**
602    * Checks whether or not the specified Shape intersects the specified
603    * Rectangle, which is in device space.
604    */
 
605  0 toggle public boolean hit(Rectangle rect, Shape s, boolean onStroke)
606    {
607  0 return s.intersects(rect);
608    }
609   
610    /**
611    * Returns the device configuration associated with this EpsGraphics2D object.
612    */
 
613  0 toggle public GraphicsConfiguration getDeviceConfiguration()
614    {
615  0 GraphicsConfiguration gc = null;
616  0 GraphicsEnvironment ge = GraphicsEnvironment
617    .getLocalGraphicsEnvironment();
618  0 GraphicsDevice[] gds = ge.getScreenDevices();
619  0 for (int i = 0; i < gds.length; i++)
620    {
621  0 GraphicsDevice gd = gds[i];
622  0 GraphicsConfiguration[] gcs = gd.getConfigurations();
623  0 if (gcs.length > 0)
624    {
625  0 return gcs[0];
626    }
627    }
628  0 return gc;
629    }
630   
631    /**
632    * Sets the Composite to be used by this EpsGraphics2D. EpsGraphics2D does not
633    * make use of these.
634    */
 
635  0 toggle public void setComposite(Composite comp)
636    {
637  0 _composite = comp;
638    }
639   
640    /**
641    * Sets the Paint attribute for the EpsGraphics2D object. Only Paint objects
642    * of type Color are respected by EpsGraphics2D.
643    */
 
644  0 toggle public void setPaint(Paint paint)
645    {
646  0 _paint = paint;
647  0 if (paint instanceof Color)
648    {
649  0 setColor((Color) paint);
650    }
651    }
652   
653    /**
654    * Sets the stroke. Only accepts BasicStroke objects (or subclasses of
655    * BasicStroke).
656    */
 
657  0 toggle public void setStroke(Stroke s)
658    {
659  0 if (s instanceof BasicStroke)
660    {
661  0 _stroke = (BasicStroke) s;
662   
663  0 append(_stroke.getLineWidth() + " setlinewidth");
664  0 float miterLimit = _stroke.getMiterLimit();
665  0 if (miterLimit < 1.0f)
666    {
667  0 miterLimit = 1;
668    }
669  0 append(miterLimit + " setmiterlimit");
670  0 append(_stroke.getLineJoin() + " setlinejoin");
671  0 append(_stroke.getEndCap() + " setlinecap");
672   
673  0 StringBuffer dashes = new StringBuffer();
674  0 dashes.append("[ ");
675  0 float[] dashArray = _stroke.getDashArray();
676  0 if (dashArray != null)
677    {
678  0 for (int i = 0; i < dashArray.length; i++)
679    {
680  0 dashes.append((dashArray[i]) + " ");
681    }
682    }
683  0 dashes.append("]");
684  0 append(dashes.toString() + " 0 setdash");
685    }
686    }
687   
688    /**
689    * Sets a rendering hint. These are not used by EpsGraphics2D.
690    */
 
691  0 toggle public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
692    {
693    // Do nothing.
694    }
695   
696    /**
697    * Returns the value of a single preference for the rendering algorithms.
698    * Rendering hints are not used by EpsGraphics2D.
699    */
 
700  0 toggle public Object getRenderingHint(RenderingHints.Key hintKey)
701    {
702  0 return null;
703    }
704   
705    /**
706    * Sets the rendering hints. These are ignored by EpsGraphics2D.
707    */
 
708  0 toggle public void setRenderingHints(Map hints)
709    {
710    // Do nothing.
711    }
712   
713    /**
714    * Adds rendering hints. These are ignored by EpsGraphics2D.
715    */
 
716  0 toggle public void addRenderingHints(Map hints)
717    {
718    // Do nothing.
719    }
720   
721    /**
722    * Returns the preferences for the rendering algorithms.
723    */
 
724  0 toggle public RenderingHints getRenderingHints()
725    {
726  0 return new RenderingHints(null);
727    }
728   
729    /**
730    * Translates the origin of the EpsGraphics2D context to the point (x,y) in
731    * the current coordinate system.
732    */
 
733  0 toggle public void translate(int x, int y)
734    {
735  0 translate((double) x, (double) y);
736    }
737   
738    /**
739    * Concatenates the current EpsGraphics2D Transformation with a translation
740    * transform.
741    */
 
742  0 toggle public void translate(double tx, double ty)
743    {
744  0 transform(AffineTransform.getTranslateInstance(tx, ty));
745    }
746   
747    /**
748    * Concatenates the current EpsGraphics2D Transform with a rotation transform.
749    */
 
750  0 toggle public void rotate(double theta)
751    {
752  0 rotate(theta, 0, 0);
753    }
754   
755    /**
756    * Concatenates the current EpsGraphics2D Transform with a translated rotation
757    * transform.
758    */
 
759  0 toggle public void rotate(double theta, double x, double y)
760    {
761  0 transform(AffineTransform.getRotateInstance(theta, x, y));
762    }
763   
764    /**
765    * Concatenates the current EpsGraphics2D Transform with a scaling
766    * transformation.
767    */
 
768  0 toggle public void scale(double sx, double sy)
769    {
770  0 transform(AffineTransform.getScaleInstance(sx, sy));
771    }
772   
773    /**
774    * Concatenates the current EpsGraphics2D Transform with a shearing transform.
775    */
 
776  0 toggle public void shear(double shx, double shy)
777    {
778  0 transform(AffineTransform.getShearInstance(shx, shy));
779    }
780   
781    /**
782    * Composes an AffineTransform object with the Transform in this EpsGraphics2D
783    * according to the rule last-specified-first-applied.
784    */
 
785  0 toggle public void transform(AffineTransform Tx)
786    {
787  0 _transform.concatenate(Tx);
788  0 setTransform(getTransform());
789    }
790   
791    /**
792    * Sets the AffineTransform to be used by this EpsGraphics2D.
793    */
 
794  0 toggle public void setTransform(AffineTransform Tx)
795    {
796  0 if (Tx == null)
797    {
798  0 _transform = new AffineTransform();
799    }
800    else
801    {
802  0 _transform = new AffineTransform(Tx);
803    }
804    // Need to update the stroke and font so they know the scale changed
805  0 setStroke(getStroke());
806  0 setFont(getFont());
807    }
808   
809    /**
810    * Gets the AffineTransform used by this EpsGraphics2D.
811    */
 
812  0 toggle public AffineTransform getTransform()
813    {
814  0 return new AffineTransform(_transform);
815    }
816   
817    /**
818    * Returns the current Paint of the EpsGraphics2D object.
819    */
 
820  0 toggle public Paint getPaint()
821    {
822  0 return _paint;
823    }
824   
825    /**
826    * returns the current Composite of the EpsGraphics2D object.
827    */
 
828  0 toggle public Composite getComposite()
829    {
830  0 return _composite;
831    }
832   
833    /**
834    * Sets the background color to be used by the clearRect method.
835    */
 
836  0 toggle public void setBackground(Color color)
837    {
838  0 if (color == null)
839    {
840  0 color = Color.black;
841    }
842  0 _backgroundColor = color;
843    }
844   
845    /**
846    * Gets the background color that is used by the clearRect method.
847    */
 
848  0 toggle public Color getBackground()
849    {
850  0 return _backgroundColor;
851    }
852   
853    /**
854    * Returns the Stroke currently used. Guaranteed to be an instance of
855    * BasicStroke.
856    */
 
857  0 toggle public Stroke getStroke()
858    {
859  0 return _stroke;
860    }
861   
862    /**
863    * Intersects the current clip with the interior of the specified Shape and
864    * sets the clip to the resulting intersection.
865    */
 
866  0 toggle public void clip(Shape s)
867    {
868  0 if (_clip == null)
869    {
870  0 setClip(s);
871    }
872    else
873    {
874  0 Area area = new Area(_clip);
875  0 area.intersect(new Area(s));
876  0 setClip(area);
877    }
878    }
879   
880    /**
881    * Returns the FontRenderContext.
882    */
 
883  0 toggle public FontRenderContext getFontRenderContext()
884    {
885  0 return _fontRenderContext;
886    }
887   
888    // ///////////// Graphics methods ///////////////////////
889   
890    /**
891    * Returns a new Graphics object that is identical to this EpsGraphics2D.
892    */
 
893  0 toggle public Graphics create()
894    {
895  0 return new EpsGraphics2D(this);
896    }
897   
898    /**
899    * Returns an EpsGraphics2D object based on this Graphics object, but with a
900    * new translation and clip area.
901    */
 
902  0 toggle public Graphics create(int x, int y, int width, int height)
903    {
904  0 Graphics g = create();
905  0 g.translate(x, y);
906  0 g.clipRect(0, 0, width, height);
907  0 return g;
908    }
909   
910    /**
911    * Returns the current Color. This will be a default value (black) until it is
912    * changed using the setColor method.
913    */
 
914  0 toggle public Color getColor()
915    {
916  0 return _color;
917    }
918   
919    /**
920    * Sets the Color to be used when drawing all future shapes, text, etc.
921    */
 
922  0 toggle public void setColor(Color c)
923    {
924  0 if (c == null)
925    {
926  0 c = Color.black;
927    }
928  0 _color = c;
929  0 append((c.getRed() / 255f) + " " + (c.getGreen() / 255f) + " "
930    + (c.getBlue() / 255f) + " setrgbcolor");
931    }
932   
933    /**
934    * Sets the paint mode of this EpsGraphics2D object to overwrite the
935    * destination EpsDocument with the current color.
936    */
 
937  0 toggle public void setPaintMode()
938    {
939    // Do nothing - paint mode is the only method supported anyway.
940    }
941   
942    /**
943    * <b><i><font color="red">Not implemented</font></i></b> - performs no
944    * action.
945    */
 
946  0 toggle public void setXORMode(Color c1)
947    {
948  0 methodNotSupported();
949    }
950   
951    /**
952    * Returns the Font currently being used.
953    */
 
954  0 toggle public Font getFont()
955    {
956  0 return _font;
957    }
958   
959    /**
960    * Sets the Font to be used in future text.
961    */
 
962  0 toggle public void setFont(Font font)
963    {
964  0 if (font == null)
965    {
966  0 font = Font.decode(null);
967    }
968  0 _font = font;
969  0 append("/" + _font.getPSName() + " findfont " + ((int) _font.getSize())
970    + " scalefont setfont");
971    }
972   
973    /**
974    * Gets the font metrics of the current font.
975    */
 
976  0 toggle public FontMetrics getFontMetrics()
977    {
978  0 return getFontMetrics(getFont());
979    }
980   
981    /**
982    * Gets the font metrics for the specified font.
983    */
 
984  0 toggle public FontMetrics getFontMetrics(Font f)
985    {
986  0 BufferedImage image = new BufferedImage(1, 1,
987    BufferedImage.TYPE_INT_RGB);
988  0 Graphics g = image.getGraphics();
989  0 return g.getFontMetrics(f);
990    }
991   
992    /**
993    * Returns the bounding rectangle of the current clipping area.
994    */
 
995  0 toggle public Rectangle getClipBounds()
996    {
997  0 if (_clip == null)
998    {
999  0 return null;
1000    }
1001  0 Rectangle rect = getClip().getBounds();
1002  0 return rect;
1003    }
1004   
1005    /**
1006    * Intersects the current clip with the specified rectangle.
1007    */
 
1008  0 toggle public void clipRect(int x, int y, int width, int height)
1009    {
1010  0 clip(new Rectangle(x, y, width, height));
1011    }
1012   
1013    /**
1014    * Sets the current clip to the rectangle specified by the given coordinates.
1015    */
 
1016  0 toggle public void setClip(int x, int y, int width, int height)
1017    {
1018  0 setClip(new Rectangle(x, y, width, height));
1019    }
1020   
1021    /**
1022    * Gets the current clipping area.
1023    */
 
1024  0 toggle public Shape getClip()
1025    {
1026  0 if (_clip == null)
1027    {
1028  0 return null;
1029    }
1030    else
1031    {
1032  0 try
1033    {
1034  0 AffineTransform t = _transform.createInverse();
1035  0 t.concatenate(_clipTransform);
1036  0 return t.createTransformedShape(_clip);
1037    } catch (Exception e)
1038    {
1039  0 throw new EpsException(MessageManager.formatMessage(
1040    "exception.eps_unable_to_get_inverse_matrix",
1041    new String[] { _transform.toString() }));
1042    }
1043    }
1044    }
1045   
1046    /**
1047    * Sets the current clipping area to an arbitrary clip shape.
1048    */
 
1049  0 toggle public void setClip(Shape clip)
1050    {
1051  0 if (clip != null)
1052    {
1053  0 if (_document.isClipSet())
1054    {
1055  0 append("grestore");
1056  0 append("gsave");
1057    }
1058    else
1059    {
1060  0 _document.setClipSet(true);
1061  0 append("gsave");
1062    }
1063  0 draw(clip, "clip");
1064  0 _clip = clip;
1065  0 _clipTransform = (AffineTransform) _transform.clone();
1066    }
1067    else
1068    {
1069  0 if (_document.isClipSet())
1070    {
1071  0 append("grestore");
1072  0 _document.setClipSet(false);
1073    }
1074  0 _clip = null;
1075    }
1076    }
1077   
1078    /**
1079    * <b><i><font color="red">Not implemented</font></i></b> - performs no
1080    * action.
1081    */
 
1082  0 toggle public void copyArea(int x, int y, int width, int height, int dx, int dy)
1083    {
1084  0 methodNotSupported();
1085    }
1086   
1087    /**
1088    * Draws a straight line from (x1,y1) to (x2,y2).
1089    */
 
1090  0 toggle public void drawLine(int x1, int y1, int x2, int y2)
1091    {
1092  0 Shape shape = new Line2D.Float(x1, y1, x2, y2);
1093  0 draw(shape);
1094    }
1095   
1096    /**
1097    * Fills a rectangle with top-left corner placed at (x,y).
1098    */
 
1099  0 toggle public void fillRect(int x, int y, int width, int height)
1100    {
1101  0 Shape shape = new Rectangle(x, y, width, height);
1102  0 draw(shape, "fill");
1103    }
1104   
1105    /**
1106    * Draws a rectangle with top-left corner placed at (x,y).
1107    */
 
1108  0 toggle public void drawRect(int x, int y, int width, int height)
1109    {
1110  0 Shape shape = new Rectangle(x, y, width, height);
1111  0 draw(shape);
1112    }
1113   
1114    /**
1115    * Clears a rectangle with top-left corner placed at (x,y) using the current
1116    * background color.
1117    */
 
1118  0 toggle public void clearRect(int x, int y, int width, int height)
1119    {
1120  0 Color originalColor = getColor();
1121   
1122  0 setColor(getBackground());
1123  0 Shape shape = new Rectangle(x, y, width, height);
1124  0 draw(shape, "fill");
1125   
1126  0 setColor(originalColor);
1127    }
1128   
1129    /**
1130    * Draws a rounded rectangle.
1131    */
 
1132  0 toggle public void drawRoundRect(int x, int y, int width, int height,
1133    int arcWidth, int arcHeight)
1134    {
1135  0 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1136    arcHeight);
1137  0 draw(shape);
1138    }
1139   
1140    /**
1141    * Fills a rounded rectangle.
1142    */
 
1143  0 toggle public void fillRoundRect(int x, int y, int width, int height,
1144    int arcWidth, int arcHeight)
1145    {
1146  0 Shape shape = new RoundRectangle2D.Float(x, y, width, height, arcWidth,
1147    arcHeight);
1148  0 draw(shape, "fill");
1149    }
1150   
1151    /**
1152    * Draws an oval.
1153    */
 
1154  0 toggle public void drawOval(int x, int y, int width, int height)
1155    {
1156  0 Shape shape = new Ellipse2D.Float(x, y, width, height);
1157  0 draw(shape);
1158    }
1159   
1160    /**
1161    * Fills an oval.
1162    */
 
1163  0 toggle public void fillOval(int x, int y, int width, int height)
1164    {
1165  0 Shape shape = new Ellipse2D.Float(x, y, width, height);
1166  0 draw(shape, "fill");
1167    }
1168   
1169    /**
1170    * Draws an arc.
1171    */
 
1172  0 toggle public void drawArc(int x, int y, int width, int height, int startAngle,
1173    int arcAngle)
1174    {
1175  0 Shape shape = new Arc2D.Float(x, y, width, height, startAngle,
1176    arcAngle, Arc2D.OPEN);
1177  0 draw(shape);
1178    }
1179   
1180    /**
1181    * Fills an arc.
1182    */
 
1183  0 toggle public void fillArc(int x, int y, int width, int height, int startAngle,
1184    int arcAngle)
1185    {
1186  0 Shape shape = new Arc2D.Float(x, y, width, height, startAngle,
1187    arcAngle, Arc2D.PIE);
1188  0 draw(shape, "fill");
1189    }
1190   
1191    /**
1192    * Draws a polyline.
1193    */
 
1194  0 toggle public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
1195    {
1196  0 if (nPoints > 0)
1197    {
1198  0 GeneralPath path = new GeneralPath();
1199  0 path.moveTo(xPoints[0], yPoints[0]);
1200  0 for (int i = 1; i < nPoints; i++)
1201    {
1202  0 path.lineTo(xPoints[i], yPoints[i]);
1203    }
1204  0 draw(path);
1205    }
1206    }
1207   
1208    /**
1209    * Draws a polygon made with the specified points.
1210    */
 
1211  0 toggle public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
1212    {
1213  0 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1214  0 draw(shape);
1215    }
1216   
1217    /**
1218    * Draws a polygon.
1219    */
 
1220  0 toggle public void drawPolygon(Polygon p)
1221    {
1222  0 draw(p);
1223    }
1224   
1225    /**
1226    * Fills a polygon made with the specified points.
1227    */
 
1228  0 toggle public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
1229    {
1230  0 Shape shape = new Polygon(xPoints, yPoints, nPoints);
1231  0 draw(shape, "fill");
1232    }
1233   
1234    /**
1235    * Fills a polygon.
1236    */
 
1237  0 toggle public void fillPolygon(Polygon p)
1238    {
1239  0 draw(p, "fill");
1240    }
1241   
1242    /**
1243    * Draws the specified characters, starting from (x,y)
1244    */
 
1245  0 toggle public void drawChars(char[] data, int offset, int length, int x, int y)
1246    {
1247  0 String string = new String(data, offset, length);
1248  0 drawString(string, x, y);
1249    }
1250   
1251    /**
1252    * Draws the specified bytes, starting from (x,y)
1253    */
 
1254  0 toggle public void drawBytes(byte[] data, int offset, int length, int x, int y)
1255    {
1256  0 String string = new String(data, offset, length);
1257  0 drawString(string, x, y);
1258    }
1259   
1260    /**
1261    * Draws an image.
1262    */
 
1263  0 toggle public boolean drawImage(Image img, int x, int y, ImageObserver observer)
1264    {
1265  0 return drawImage(img, x, y, Color.white, observer);
1266    }
1267   
1268    /**
1269    * Draws an image.
1270    */
 
1271  0 toggle public boolean drawImage(Image img, int x, int y, int width, int height,
1272    ImageObserver observer)
1273    {
1274  0 return drawImage(img, x, y, width, height, Color.white, observer);
1275    }
1276   
1277    /**
1278    * Draws an image.
1279    */
 
1280  0 toggle public boolean drawImage(Image img, int x, int y, Color bgcolor,
1281    ImageObserver observer)
1282    {
1283  0 int width = img.getWidth(null);
1284  0 int height = img.getHeight(null);
1285  0 return drawImage(img, x, y, width, height, bgcolor, observer);
1286    }
1287   
1288    /**
1289    * Draws an image.
1290    */
 
1291  0 toggle public boolean drawImage(Image img, int x, int y, int width, int height,
1292    Color bgcolor, ImageObserver observer)
1293    {
1294  0 return drawImage(img, x, y, x + width, y + height, 0, 0, width, height,
1295    bgcolor, observer);
1296    }
1297   
1298    /**
1299    * Draws an image.
1300    */
 
1301  0 toggle public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1302    int sx1, int sy1, int sx2, int sy2, ImageObserver observer)
1303    {
1304  0 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
1305    Color.white, observer);
1306    }
1307   
1308    /**
1309    * Draws an image.
1310    */
 
1311  0 toggle public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1312    int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1313    ImageObserver observer)
1314    {
1315  0 if (dx1 >= dx2)
1316    {
1317  0 throw new IllegalArgumentException("dx1 >= dx2");
1318    }
1319  0 if (sx1 >= sx2)
1320    {
1321  0 throw new IllegalArgumentException("sx1 >= sx2");
1322    }
1323  0 if (dy1 >= dy2)
1324    {
1325  0 throw new IllegalArgumentException("dy1 >= dy2");
1326    }
1327  0 if (sy1 >= sy2)
1328    {
1329  0 throw new IllegalArgumentException("sy1 >= sy2");
1330    }
1331   
1332  0 append("gsave");
1333   
1334  0 int width = sx2 - sx1;
1335  0 int height = sy2 - sy1;
1336  0 int destWidth = dx2 - dx1;
1337  0 int destHeight = dy2 - dy1;
1338   
1339  0 int[] pixels = new int[width * height];
1340  0 PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sx2 - sx1, sy2 - sy1,
1341    pixels, 0, width);
1342  0 try
1343    {
1344  0 pg.grabPixels();
1345    } catch (InterruptedException e)
1346    {
1347  0 return false;
1348    }
1349   
1350  0 AffineTransform matrix = new AffineTransform(_transform);
1351  0 matrix.translate(dx1, dy1);
1352  0 matrix.scale(destWidth / (double) width, destHeight / (double) height);
1353  0 double[] m = new double[6];
1354  0 try
1355    {
1356  0 matrix = matrix.createInverse();
1357    } catch (Exception e)
1358    {
1359  0 throw new EpsException(MessageManager.formatMessage(
1360    "exception.eps_unable_to_get_inverse_matrix",
1361    new String[] { matrix.toString() }));
1362    }
1363  0 matrix.scale(1, -1);
1364  0 matrix.getMatrix(m);
1365  0 append(width + " " + height + " 8 [" + m[0] + " " + m[1] + " " + m[2]
1366    + " " + m[3] + " " + m[4] + " " + m[5] + "]");
1367    // Fill the background to update the bounding box.
1368  0 Color oldColor = getColor();
1369  0 setColor(getBackground());
1370  0 fillRect(dx1, dy1, destWidth, destHeight);
1371  0 setColor(oldColor);
1372  0 append("{currentfile 3 " + width
1373    + " mul string readhexstring pop} bind");
1374  0 append("false 3 colorimage");
1375  0 StringBuffer line = new StringBuffer();
1376  0 for (int y = 0; y < height; y++)
1377    {
1378  0 for (int x = 0; x < width; x++)
1379    {
1380  0 Color color = new Color(pixels[x + width * y]);
1381  0 line.append(toHexString(color.getRed())
1382    + toHexString(color.getGreen())
1383    + toHexString(color.getBlue()));
1384  0 if (line.length() > 64)
1385    {
1386  0 append(line.toString());
1387  0 line = new StringBuffer();
1388    }
1389    }
1390    }
1391  0 if (line.length() > 0)
1392    {
1393  0 append(line.toString());
1394    }
1395   
1396  0 append("grestore");
1397   
1398  0 return true;
1399    }
1400   
1401    /**
1402    * Disposes of all resources used by this EpsGraphics2D object. If this is the
1403    * only remaining EpsGraphics2D instance pointing at a EpsDocument object,
1404    * then the EpsDocument object shall become eligible for garbage collection.
1405    */
 
1406  0 toggle public void dispose()
1407    {
1408  0 _document = null;
1409    }
1410   
1411    /**
1412    * Finalizes the object.
1413    */
 
1414  0 toggle public void finalize()
1415    {
1416  0 super.finalize();
1417    }
1418   
1419    /**
1420    * Returns the entire contents of the EPS document, complete with headers and
1421    * bounding box. The returned String is suitable for being written directly to
1422    * disk as an EPS file.
1423    */
 
1424  0 toggle public String toString()
1425    {
1426  0 StringWriter writer = new StringWriter();
1427  0 try
1428    {
1429  0 _document.write(writer);
1430  0 _document.flush();
1431  0 _document.close();
1432    } catch (IOException e)
1433    {
1434  0 throw new EpsException(e.toString());
1435    }
1436  0 return writer.toString();
1437    }
1438   
1439    /**
1440    * Returns true if the specified rectangular area might intersect the current
1441    * clipping area.
1442    */
 
1443  0 toggle public boolean hitClip(int x, int y, int width, int height)
1444    {
1445  0 if (_clip == null)
1446    {
1447  0 return true;
1448    }
1449  0 Rectangle rect = new Rectangle(x, y, width, height);
1450  0 return hit(rect, _clip, true);
1451    }
1452   
1453    /**
1454    * Returns the bounding rectangle of the current clipping area.
1455    */
 
1456  0 toggle public Rectangle getClipBounds(Rectangle r)
1457    {
1458  0 if (_clip == null)
1459    {
1460  0 return r;
1461    }
1462  0 Rectangle rect = getClipBounds();
1463  0 r.setLocation((int) rect.getX(), (int) rect.getY());
1464  0 r.setSize((int) rect.getWidth(), (int) rect.getHeight());
1465  0 return r;
1466    }
1467   
1468    private Color _color;
1469   
1470    private Color _backgroundColor;
1471   
1472    private Paint _paint;
1473   
1474    private Composite _composite;
1475   
1476    private BasicStroke _stroke;
1477   
1478    private Font _font;
1479   
1480    private Shape _clip;
1481   
1482    private AffineTransform _clipTransform;
1483   
1484    private AffineTransform _transform;
1485   
1486    private boolean _accurateTextMode;
1487   
1488    private EpsDocument _document;
1489   
1490    private static FontRenderContext _fontRenderContext = new FontRenderContext(
1491    null, false, true);
1492    }