View Javadoc

1   // Copyright 2000-2006, FreeHEP.
2   package org.freehep.graphics2d;
3   
4   import java.awt.AlphaComposite;
5   import java.awt.BasicStroke;
6   import java.awt.Color;
7   import java.awt.Composite;
8   import java.awt.Font;
9   import java.awt.FontMetrics;
10  import java.awt.Graphics;
11  import java.awt.Graphics2D;
12  import java.awt.GraphicsConfiguration;
13  import java.awt.Image;
14  import java.awt.Paint;
15  import java.awt.Polygon;
16  import java.awt.Rectangle;
17  import java.awt.RenderingHints;
18  import java.awt.Shape;
19  import java.awt.Stroke;
20  import java.awt.Transparency;
21  import java.awt.font.FontRenderContext;
22  import java.awt.font.GlyphVector;
23  import java.awt.geom.AffineTransform;
24  import java.awt.geom.Rectangle2D;
25  import java.awt.image.BufferedImage;
26  import java.awt.image.BufferedImageOp;
27  import java.awt.image.ImageObserver;
28  import java.awt.image.RenderedImage;
29  import java.awt.image.renderable.RenderableImage;
30  import java.awt.print.PrinterGraphics;
31  import java.lang.reflect.InvocationTargetException;
32  import java.lang.reflect.Method;
33  import java.text.AttributedCharacterIterator;
34  import java.util.HashMap;
35  import java.util.Map;
36  
37  import org.freehep.graphics2d.font.FontEncoder;
38  
39  /**
40   * @author Charles Loomis
41   * @author Mark Donszelmann
42   * @version $Id: PixelGraphics2D.java 10115 2006-12-04 22:27:37Z duns $
43   */
44  public class PixelGraphics2D extends AbstractVectorGraphics {
45  
46      public final static RenderingHints.Key KEY_SYMBOL_BLIT = new SymbolBlitKey();
47  
48      public final static Object VALUE_SYMBOL_BLIT_ON = Boolean.TRUE;
49  
50      public final static Object VALUE_SYMBOL_BLIT_OFF = Boolean.FALSE;
51  
52      static class SymbolBlitKey extends RenderingHints.Key {
53          public SymbolBlitKey() {
54              super(94025);
55          }
56  
57          public boolean isCompatibleValue(Object o) {
58              if (o.equals(VALUE_SYMBOL_BLIT_ON))
59                  return true;
60              if (o.equals(VALUE_SYMBOL_BLIT_OFF))
61                  return true;
62              return false;
63          }
64  
65          public String toString() {
66              return "Symbol Blitting enable key";
67          }
68      }
69  
70      // The host graphics context.
71      protected Graphics2D hostGraphics;
72  
73      protected double lineWidth;
74  
75      protected int resolution;
76  
77      // tag handler
78      protected GenericTagHandler tagHandler;
79  
80      // fast symbol handling, FIXME: does not work for fillAndDraw
81      private static final int MAX_BLIT_SIZE = 32;
82  
83      private static Map /* <color, Image[fill][symbol][size]> */symbols;
84  
85      private WebColor webColor;
86  
87      // graphics environment stuff
88      private static boolean displayX11;
89  
90      private static boolean displayLocal;
91  
92      static {
93          symbols = new HashMap();
94  
95          displayX11 = false;
96          displayLocal = false;
97          try {
98              Class clazz = Class.forName("sun.awt.X11GraphicsEnvironment");
99              displayX11 = true;
100             Method method = clazz.getMethod("isDisplayLocal", null);
101             Boolean result = (Boolean) method.invoke(null, null);
102             displayLocal = result.booleanValue();
103         } catch (ClassNotFoundException e) {
104             // Windows case...
105             displayLocal = true;
106         } catch (IllegalAccessException e) {
107             // ignored
108         } catch (NoSuchMethodException e) {
109             // ignored
110         } catch (InvocationTargetException e) {
111             // ignored
112         } catch (ClassCastException e) {
113             // ignored
114         } catch (SecurityException e) {
115             // ignored
116         }
117     }
118 
119     public PixelGraphics2D(Graphics graphics) {
120         this();
121         setHostGraphics(graphics);
122     }
123 
124     /**
125      */
126     protected PixelGraphics2D(PixelGraphics2D graphics) {
127         super(graphics);
128         setHostGraphics(graphics.hostGraphics.create());
129     }
130 
131     /**
132      * Constructor for the case that you only know the hostgraphics later on.
133      * NOTE: make sure you call setHostGraphics afterwards.
134      */
135     protected PixelGraphics2D() {
136         super();
137     }
138 
139     protected void setHostGraphics(Graphics graphics) {
140         hostGraphics = (Graphics2D) graphics;
141         resolution = (graphics instanceof PrinterGraphics) ? 0 : 1;
142         tagHandler = new GenericTagHandler(hostGraphics);
143 
144         super.setBackground(hostGraphics.getBackground());
145         super.setColor(hostGraphics.getColor());
146         super.setPaint(hostGraphics.getPaint());
147         super.setFont(hostGraphics.getFont());
148 
149         Stroke s = hostGraphics.getStroke();
150         if (s instanceof BasicStroke) {
151             lineWidth = ((BasicStroke) s).getLineWidth();
152         }
153         webColor = WebColor.create(getColor());
154         setRenderingHint(KEY_SYMBOL_BLIT, VALUE_SYMBOL_BLIT_ON);
155     }
156 
157     public void startExport() {
158     }
159 
160     public void endExport() {
161     }
162 
163     public void printComment(String comment) {
164     }
165 
166     public Graphics create(double x, double y, double width, double height) {
167         PixelGraphics2D graphics = new PixelGraphics2D(this);
168         graphics.translate(x, y);
169         graphics.clipRect(0, 0, width, height);
170         return graphics;
171     }
172 
173     // //
174     // The methods which follow are those necessary for the Graphics
175     // and Graphics2D contexts. These simply call the appropriate
176     // method on the underlying graphics context.
177     // //
178 
179     public void clearRect(int x, int y, int width, int height) {
180         hostGraphics.clearRect(x, y, width, height);
181     }
182 
183     public void clipRect(int x, int y, int width, int height) {
184         hostGraphics.clipRect(x, y, width, height);
185     }
186 
187     public void copyArea(int x, int y, int width, int height, int dx, int dy) {
188         hostGraphics.copyArea(x, y, width, height, dx, dy);
189     }
190 
191     public Graphics create() {
192         return new PixelGraphics2D(this);
193     }
194 
195     public void dispose() {
196         hostGraphics.dispose();
197     }
198 
199     public void drawArc(int x, int y, int width, int height, int startAngle,
200             int arcAngle) {
201         hostGraphics.drawArc(x, y, width, height, startAngle, arcAngle);
202     }
203 
204     public boolean drawImage(Image img, int x, int y, Color bgcolor,
205             ImageObserver observer) {
206         return hostGraphics.drawImage(img, x, y, getPrintColor(bgcolor),
207                 observer);
208     }
209 
210     public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
211         return hostGraphics.drawImage(img, x, y, observer);
212     }
213 
214     public boolean drawImage(Image img, int x, int y, int width, int height,
215             Color bgcolor, ImageObserver observer) {
216         return hostGraphics.drawImage(img, x, y, width, height,
217                 getPrintColor(bgcolor), observer);
218     }
219 
220     public boolean drawImage(Image img, int x, int y, int width, int height,
221             ImageObserver observer) {
222         return hostGraphics.drawImage(img, x, y, width, height, observer);
223     }
224 
225     public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
226             int sx1, int sy1, int sx2, int sy2, Color bgcolor,
227             ImageObserver observer) {
228         return hostGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2,
229                 sy2, getPrintColor(bgcolor), observer);
230     }
231 
232     public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
233             int sx1, int sy1, int sx2, int sy2, ImageObserver observer) {
234         return hostGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2,
235                 sy2, observer);
236     }
237 
238     public void drawLine(int x1, int y1, int x2, int y2) {
239         hostGraphics.drawLine(x1, y1, x2, y2);
240     }
241 
242     public void drawOval(int x, int y, int width, int height) {
243         hostGraphics.drawOval(x, y, width, height);
244     }
245 
246     public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
247         hostGraphics.drawPolygon(xPoints, yPoints, nPoints);
248     }
249 
250     public void drawPolygon(Polygon p) {
251         hostGraphics.drawPolygon(p);
252     }
253 
254     public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
255         hostGraphics.drawPolyline(xPoints, yPoints, nPoints);
256     }
257 
258     public void drawRect(int x, int y, int width, int height) {
259         hostGraphics.drawRect(x, y, width, height);
260     }
261 
262     public void drawString(String str, int x, int y) {
263         str = FontEncoder.getEncodedString(str, getFont().getName());
264         hostGraphics.drawString(str, x, y);
265     }
266 
267     public void fillArc(int x, int y, int width, int height, int startAngle,
268             int arcAngle) {
269         hostGraphics.fillArc(x, y, width, height, startAngle, arcAngle);
270     }
271 
272     public void fillOval(int x, int y, int width, int height) {
273         hostGraphics.fillOval(x, y, width, height);
274     }
275 
276     public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
277         hostGraphics.fillPolygon(xPoints, yPoints, nPoints);
278     }
279 
280     public void fillPolygon(Polygon p) {
281         hostGraphics.fillPolygon(p);
282     }
283 
284     public void fillRect(int x, int y, int width, int height) {
285         hostGraphics.fillRect(x, y, width, height);
286     }
287 
288     public void drawSymbol(double x, double y, double size, int symbol) {
289         if (size <= 0)
290             return;
291 
292         int intSize = (int) Math.ceil(size);
293         if ((intSize > MAX_BLIT_SIZE)
294                 || (lineWidth != 1.0)
295                 || !isDisplayLocal()
296                 || (getRenderingHint(RenderingHints.KEY_ANTIALIASING) == RenderingHints.VALUE_ANTIALIAS_ON)
297                 || (getRenderingHint(KEY_SYMBOL_BLIT) == VALUE_SYMBOL_BLIT_OFF)) {
298             super.drawSymbol(x, y, size, symbol);
299             return;
300         }
301 
302         blitSymbol(x, y, intSize, symbol, false);
303     }
304 
305     public void fillSymbol(double x, double y, double size, int symbol) {
306         if (size <= 0)
307             return;
308 
309         int intSize = (int) Math.ceil(size);
310         if ((intSize > MAX_BLIT_SIZE)
311                 || (lineWidth != 1.0)
312                 || !isDisplayLocal()
313                 || (getRenderingHint(RenderingHints.KEY_ANTIALIASING) == RenderingHints.VALUE_ANTIALIAS_ON)
314                 || (getRenderingHint(KEY_SYMBOL_BLIT) == VALUE_SYMBOL_BLIT_OFF)) {
315             super.fillSymbol(x, y, size, symbol);
316             return;
317         }
318 
319         blitSymbol(x, y, intSize, symbol, true);
320     }
321 
322     // FIXME: overridden to avoid blitting
323     public void fillAndDrawSymbol(double x, double y, double size, int symbol,
324             Color fillColor) {
325         Color color = getColor();
326         setColor(fillColor);
327         super.fillSymbol(x, y, size, symbol);
328         setColor(color);
329         super.drawSymbol(x, y, size, symbol);
330     }
331 
332     private void blitSymbol(double x, double y, int size, int symbol,
333             boolean fill) {
334         Image[][][] images = (Image[][][]) symbols.get(webColor);
335         if (images == null) {
336             images = new Image[2][NUMBER_OF_SYMBOLS][MAX_BLIT_SIZE];
337             symbols.put(webColor, images);
338         }
339 
340         Image image = images[fill ? 1 : 0][symbol][size - 1];
341         int imageSize = size + 1;
342         double imageSize2 = imageSize / 2.0;
343         if (image == null) {
344             image = getDeviceConfiguration().createCompatibleImage(
345                     imageSize + 1, imageSize + 1, Transparency.BITMASK);
346             VectorGraphics imageGraphics = VectorGraphics.create(image
347                     .getGraphics());
348             Composite composite = imageGraphics.getComposite();
349             imageGraphics.setComposite(AlphaComposite.Clear);
350             imageGraphics.fillRect(0, 0, size, size);
351             imageGraphics.setComposite(composite);
352             imageGraphics.setColor(getColor());
353             if (fill) {
354                 fillSymbol(imageGraphics, imageSize2, imageSize2, size, symbol);
355             } else {
356                 drawSymbol(imageGraphics, imageSize2, imageSize2, size, symbol);
357             }
358             images[fill ? 1 : 0][symbol][size - 1] = image;
359         }
360         drawImage(image, (int) (x - imageSize2), (int) (y - imageSize2), null);
361     }
362 
363     public void setLineWidth(double width) {
364         super.setLineWidth(width);
365         lineWidth = width;
366     }
367 
368     public Shape getClip() {
369         return hostGraphics.getClip();
370     }
371 
372     public Rectangle getClipBounds() {
373         return hostGraphics.getClipBounds();
374     }
375 
376     public Rectangle getClipBounds(Rectangle r) {
377         return hostGraphics.getClipBounds(r);
378     }
379 
380     public FontMetrics getFontMetrics(Font f) {
381         return hostGraphics.getFontMetrics(f);
382     }
383 
384     public void setClip(int x, int y, int width, int height) {
385         hostGraphics.setClip(x, y, width, height);
386     }
387 
388     public void setClip(Shape clip) {
389         hostGraphics.setClip(clip);
390     }
391 
392     public void setFont(Font font) {
393     	if (font == null) return;
394     	
395         super.setFont(font);
396         if (font.getName().equals("Symbol")
397                 || font.getName().equals("ZapfDingbats")) {
398             Font newFont = new Font("Serif", font.getSize(), font.getStyle());
399             font = newFont.deriveFont(font.getSize2D());
400         }
401         hostGraphics.setFont(font);
402     }
403 
404     public void setColor(Color color) {
405     	if (color == null) return;
406     	
407         if (color.equals(getColor()))
408             return;
409 
410         super.setColor(color);
411         hostGraphics.setColor(getPrintColor(color));
412         webColor = WebColor.create(color);
413     }
414 
415     public void setPaint(Paint paint) {
416     	if (paint == null) return; 
417     	
418         if (paint.equals(getPaint()))
419             return;
420 
421         if (paint instanceof Color) {
422             setColor((Color) paint);
423         } else {
424             super.setPaint(paint);
425             hostGraphics.setPaint(paint);
426         }
427     }
428 
429     public void setPaintMode() {
430         hostGraphics.setPaintMode();
431     }
432 
433     public void setXORMode(Color c1) {
434         hostGraphics.setXORMode(getPrintColor(c1));
435     }
436 
437     public void translate(int x, int y) {
438         hostGraphics.translate(x, y);
439     }
440 
441     // //
442     // The ones from the Graphic2D context. This overrides some
443     // methods defined in VectorGraphics2D by simply calling the
444     // underlying host graphics context.
445     // //
446 
447     public void addRenderingHints(Map hints) {
448         hostGraphics.addRenderingHints(hints);
449     }
450 
451     public void clip(Shape clip) {
452         hostGraphics.clip(clip);
453     }
454 
455     public void draw(Shape s) {
456         hostGraphics.draw(s);
457     }
458 
459     public void drawGlyphVector(GlyphVector g, float x, float y) {
460         hostGraphics.drawGlyphVector(g, x, y);
461     }
462 
463     public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
464         hostGraphics.drawImage(img, op, x, y);
465     }
466 
467     public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
468         return hostGraphics.drawImage(img, xform, obs);
469     }
470 
471     public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
472         hostGraphics.drawRenderableImage(img, xform);
473     }
474 
475     public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
476         hostGraphics.drawRenderedImage(img, xform);
477     }
478 
479     public void drawString(AttributedCharacterIterator iterator, float x,
480             float y) {
481         hostGraphics.drawString(iterator, x, y);
482     }
483 
484     public void drawString(AttributedCharacterIterator iterator, int x, int y) {
485         hostGraphics.drawString(iterator, x, y);
486     }
487 
488     public void drawString(String str, float x, float y) {
489         str = FontEncoder.getEncodedString(str, getFont().getName());
490         hostGraphics.drawString(str, x, y);
491     }
492 
493     public void fill(Shape s) {
494         hostGraphics.fill(s);
495     }
496 
497     public Composite getComposite() {
498         return hostGraphics.getComposite();
499     }
500 
501     public GraphicsConfiguration getDeviceConfiguration() {
502         return hostGraphics.getDeviceConfiguration();
503     }
504 
505     public FontRenderContext getFontRenderContext() {
506         return hostGraphics.getFontRenderContext();
507     }
508 
509     public Object getRenderingHint(RenderingHints.Key hintKey) {
510         return hostGraphics.getRenderingHint(hintKey);
511     }
512 
513     public RenderingHints getRenderingHints() {
514         return hostGraphics.getRenderingHints();
515     }
516 
517     public Stroke getStroke() {
518         return hostGraphics.getStroke();
519     }
520 
521     public AffineTransform getTransform() {
522         return hostGraphics.getTransform();
523     }
524 
525     public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
526         return hostGraphics.hit(rect, s, onStroke);
527     }
528 
529     public void rotate(double theta) {
530         hostGraphics.rotate(theta);
531     }
532 
533     public void rotate(double theta, double x, double y) {
534         hostGraphics.rotate(theta, x, y);
535     }
536 
537     public void scale(double sx, double sy) {
538         hostGraphics.scale(sx, sy);
539     }
540 
541     public void setBackground(Color color) {
542         super.setBackground(color);
543         hostGraphics.setBackground(getPrintColor(color));
544     }
545 
546     public void setComposite(Composite comp) {
547         hostGraphics.setComposite(comp);
548     }
549 
550     public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
551         hostGraphics.setRenderingHint(hintKey, hintValue);
552     }
553 
554     public void setRenderingHints(Map hints) {
555         hostGraphics.setRenderingHints(hints);
556     }
557 
558     public void setStroke(Stroke s) {
559         hostGraphics.setStroke(s);
560     }
561 
562     public void setTransform(AffineTransform Tx) {
563         hostGraphics.setTransform(Tx);
564     }
565 
566     public void shear(double shx, double shy) {
567         hostGraphics.shear(shx, shy);
568     }
569 
570     public void transform(AffineTransform Tx) {
571         hostGraphics.transform(Tx);
572     }
573 
574     public void translate(double tx, double ty) {
575         hostGraphics.translate(tx, ty);
576     }
577 
578     // //
579     // The following methods are those specific to the VectorGraphics
580     // interfaces, but which are simple extensions of integer method
581     // calls to doubles.
582     // //
583 
584     public void clearRect(double x, double y, double width, double height) {
585         clearRect((int) x, (int) y, (int) width, (int) height);
586     }
587 
588     public void clipRect(double x, double y, double width, double height) {
589         clipRect((int) x, (int) y, (int) width, (int) height);
590     }
591 
592     public void drawString(String str, double x, double y) {
593         drawString(str, (int) Math.round(x), (int) Math.round(y));
594     }
595 
596     public void setClip(double x, double y, double width, double height) {
597         setClip(new Rectangle2D.Double(x, y, width, height));
598     }
599 
600     public String toString() {
601         return "PixelGraphics2D[" + hostGraphics.toString() + "]";
602     }
603 
604     public static boolean isDisplayX11() {
605         return displayX11;
606     }
607 
608     public static boolean isDisplayLocal() {
609         return displayLocal;
610     }
611 
612     /**
613      * Implementation of createShape makes sure that the points are different by
614      * at least one pixel.
615      */
616     protected Shape createShape(double[] xPoints, double[] yPoints,
617             int nPoints, boolean close) {
618         return new ArrayPath(xPoints, yPoints, nPoints, close, resolution);
619     }
620     /*
621      * protected GeneralPath createShape(double[] xPoints, double[] yPoints, int
622      * nPoints, boolean close) { GeneralPath path = new
623      * GeneralPath(GeneralPath.WIND_EVEN_ODD); if (nPoints > 0) {
624      * path.moveTo((float)xPoints[0], (float)yPoints[0]); double lastX =
625      * xPoints[0]; double lastY = yPoints[0]; if (close &&
626      * (Math.abs(xPoints[nPoints-1] - lastX) < resolution) &&
627      * (Math.abs(yPoints[nPoints-1] - lastY) < resolution)) { nPoints--; } for
628      * (int i = 1; i < nPoints; i++) { if ((Math.abs(xPoints[i] - lastX) >
629      * resolution) || (Math.abs(yPoints[i] - lastY) > resolution)) {
630      * path.lineTo((float)xPoints[i], (float)yPoints[i]); lastX = xPoints[i];
631      * lastY = yPoints[i]; } } if (close) path.closePath(); } return path; }
632      */
633 }