1 49 50 package com.lowagie.text.pdf; 51 52 import java.awt.AlphaComposite ; 53 import java.awt.BasicStroke ; 54 import java.awt.Color ; 55 import java.awt.Component ; 56 import java.awt.Composite ; 57 import java.awt.Font ; 58 import java.awt.FontMetrics ; 59 import java.awt.GradientPaint ; 60 import java.awt.Graphics ; 61 import java.awt.Graphics2D ; 62 import java.awt.GraphicsConfiguration ; 63 import java.awt.Image ; 64 import java.awt.MediaTracker ; 65 import java.awt.Paint ; 66 import java.awt.Polygon ; 67 import java.awt.Rectangle ; 68 import java.awt.RenderingHints ; 69 import java.awt.Shape ; 70 import java.awt.Stroke ; 71 import java.awt.TexturePaint ; 72 import java.awt.Transparency ; 73 import java.awt.RenderingHints.Key; 74 import java.awt.font.FontRenderContext ; 75 import java.awt.font.GlyphVector ; 76 import java.awt.font.TextAttribute ; 77 import java.awt.geom.AffineTransform ; 78 import java.awt.geom.Arc2D ; 79 import java.awt.geom.Area ; 80 import java.awt.geom.Ellipse2D ; 81 import java.awt.geom.Line2D ; 82 import java.awt.geom.NoninvertibleTransformException ; 83 import java.awt.geom.PathIterator ; 84 import java.awt.geom.Point2D ; 85 import java.awt.geom.Rectangle2D ; 86 import java.awt.geom.RoundRectangle2D ; 87 import java.awt.image.BufferedImage ; 88 import java.awt.image.BufferedImageOp ; 89 import java.awt.image.ColorModel ; 90 import java.awt.image.ImageObserver ; 91 import java.awt.image.RenderedImage ; 92 import java.awt.image.WritableRaster ; 93 import java.awt.image.renderable.RenderableImage ; 94 import java.io.ByteArrayOutputStream ; 95 import java.text.AttributedCharacterIterator ; 96 import java.util.ArrayList ; 97 import java.util.HashMap ; 98 import java.util.Hashtable ; 99 import java.util.Iterator ; 100 import java.util.Map ; 101 import java.util.Set ; 102 103 import com.lowagie.text.pdf.internal.PolylineShape; 104 105 public class PdfGraphics2D extends Graphics2D { 106 107 private static final int FILL = 1; 108 private static final int STROKE = 2; 109 private static final int CLIP = 3; 110 private BasicStroke strokeOne = new BasicStroke (1); 111 112 private static final AffineTransform IDENTITY = new AffineTransform (); 113 114 private Font font; 115 private BaseFont baseFont; 116 private float fontSize; 117 private AffineTransform transform; 118 private Paint paint; 119 private Color background; 120 private float width; 121 private float height; 122 123 private Area clip; 124 125 private RenderingHints rhints = new RenderingHints (null); 126 127 private Stroke stroke; 128 private Stroke originalStroke; 129 130 private PdfContentByte cb; 131 132 133 private HashMap baseFonts; 134 135 private boolean disposeCalled = false; 136 137 private FontMapper fontMapper; 138 139 private ArrayList kids; 140 141 private boolean kid = false; 142 143 private Graphics2D dg2 = new BufferedImage (2, 2, BufferedImage.TYPE_INT_RGB).createGraphics(); 144 145 private boolean onlyShapes = false; 146 147 private Stroke oldStroke; 148 private Paint paintFill; 149 private Paint paintStroke; 150 151 private MediaTracker mediaTracker; 152 153 protected boolean underline; 156 protected PdfGState fillGState[] = new PdfGState[256]; 157 protected PdfGState strokeGState[] = new PdfGState[256]; 158 protected int currentFillGState = 255; 159 protected int currentStrokeGState = 255; 160 161 public static final int AFM_DIVISOR = 1000; 163 private boolean convertImagesToJPEG = false; 164 private float jpegQuality = .95f; 165 166 private float alpha; 168 169 private Composite composite; 171 172 private Paint realPaint; 174 175 private PdfGraphics2D() { 176 dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 177 setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 178 } 179 180 184 PdfGraphics2D(PdfContentByte cb, float width, float height, FontMapper fontMapper, boolean onlyShapes, boolean convertImagesToJPEG, float quality) { 185 super(); 186 dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 187 setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 188 try { 189 Class.forName("com.sun.image.codec.jpeg.JPEGCodec"); 190 } 191 catch (Throwable t) { 192 convertImagesToJPEG = false; 193 } 194 this.convertImagesToJPEG = convertImagesToJPEG; 195 this.jpegQuality = quality; 196 this.onlyShapes = onlyShapes; 197 this.transform = new AffineTransform (); 198 this.baseFonts = new HashMap (); 199 if (!onlyShapes) { 200 this.fontMapper = fontMapper; 201 if (this.fontMapper == null) 202 this.fontMapper = new DefaultFontMapper(); 203 } 204 paint = Color.black; 205 background = Color.white; 206 setFont(new Font ("sanserif", Font.PLAIN, 12)); 207 this.cb = cb; 208 cb.saveState(); 209 this.width = width; 210 this.height = height; 211 clip = new Area (new Rectangle2D.Float (0, 0, width, height)); 212 clip(clip); 213 originalStroke = stroke = oldStroke = strokeOne; 214 setStrokeDiff(stroke, null); 215 cb.saveState(); 216 } 217 218 221 public void draw(Shape s) { 222 followPath(s, STROKE); 223 } 224 225 228 public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { 229 return drawImage(img, null, xform, null, obs); 230 } 231 232 235 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { 236 BufferedImage result = img; 237 if (op != null) { 238 result = op.createCompatibleDestImage(img, img.getColorModel()); 239 result = op.filter(img, result); 240 } 241 drawImage(result, x, y, null); 242 } 243 244 247 public void drawRenderedImage(RenderedImage img, AffineTransform xform) { 248 BufferedImage image = null; 249 if (img instanceof BufferedImage ) { 250 image = (BufferedImage )img; 251 } else { 252 ColorModel cm = img.getColorModel(); 253 int width = img.getWidth(); 254 int height = img.getHeight(); 255 WritableRaster raster = cm.createCompatibleWritableRaster(width, height); 256 boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); 257 Hashtable properties = new Hashtable (); 258 String [] keys = img.getPropertyNames(); 259 if (keys!=null) { 260 for (int i = 0; i < keys.length; i++) { 261 properties.put(keys[i], img.getProperty(keys[i])); 262 } 263 } 264 BufferedImage result = new BufferedImage (cm, raster, isAlphaPremultiplied, properties); 265 img.copyData(raster); 266 image=result; 267 } 268 drawImage(image, xform, null); 269 } 270 271 274 public void drawRenderableImage(RenderableImage img, AffineTransform xform) { 275 drawRenderedImage(img.createDefaultRendering(), xform); 276 } 277 278 281 public void drawString(String s, int x, int y) { 282 drawString(s, (float)x, (float)y); 283 } 284 285 291 public static double asPoints(double d, int i) { 292 return (d * (double)i) / (double)AFM_DIVISOR; 293 } 294 299 protected void doAttributes(AttributedCharacterIterator iter) { 300 underline = false; 301 Set set = iter.getAttributes().keySet(); 302 for(Iterator iterator = set.iterator(); iterator.hasNext();) { 303 AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute )iterator.next(); 304 if (!(attribute instanceof TextAttribute )) 305 continue; 306 TextAttribute textattribute = (TextAttribute )attribute; 307 if(textattribute.equals(TextAttribute.FONT)) { 308 Font font = (Font )iter.getAttributes().get(textattribute); 309 setFont(font); 310 } 311 else if(textattribute.equals(TextAttribute.UNDERLINE)) { 312 if(iter.getAttributes().get(textattribute) == TextAttribute.UNDERLINE_ON) 313 underline = true; 314 } 315 else if(textattribute.equals(TextAttribute.SIZE)) { 316 Object obj = iter.getAttributes().get(textattribute); 317 if(obj instanceof Integer ) { 318 int i = ((Integer )obj).intValue(); 319 setFont(getFont().deriveFont(getFont().getStyle(), i)); 320 } 321 else if(obj instanceof Float ) { 322 float f = ((Float )obj).floatValue(); 323 setFont(getFont().deriveFont(getFont().getStyle(), f)); 324 } 325 } 326 else if(textattribute.equals(TextAttribute.FOREGROUND)) { 327 setColor((Color ) iter.getAttributes().get(textattribute)); 328 } 329 else if(textattribute.equals(TextAttribute.FAMILY)) { 330 Font font = getFont(); 331 Map fontAttributes = font.getAttributes(); 332 fontAttributes.put(TextAttribute.FAMILY, iter.getAttributes().get(textattribute)); 333 setFont(font.deriveFont(fontAttributes)); 334 } 335 else if(textattribute.equals(TextAttribute.POSTURE)) { 336 Font font = getFont(); 337 Map fontAttributes = font.getAttributes(); 338 fontAttributes.put(TextAttribute.POSTURE, iter.getAttributes().get(textattribute)); 339 setFont(font.deriveFont(fontAttributes)); 340 } 341 else if(textattribute.equals(TextAttribute.WEIGHT)) { 342 Font font = getFont(); 343 Map fontAttributes = font.getAttributes(); 344 fontAttributes.put(TextAttribute.WEIGHT, iter.getAttributes().get(textattribute)); 345 setFont(font.deriveFont(fontAttributes)); 346 } 347 } 348 } 349 350 353 public void drawString(String s, float x, float y) { 354 if (s.length() == 0) 355 return; 356 setFillPaint(); 357 if (onlyShapes) { 358 drawGlyphVector(this.font.layoutGlyphVector(getFontRenderContext(), s.toCharArray(), 0, s.length(), java.awt.Font.LAYOUT_LEFT_TO_RIGHT), x, y); 359 } 362 else { 363 AffineTransform at = getTransform(); 364 AffineTransform at2 = getTransform(); 365 at2.translate(x, y); 366 at2.concatenate(font.getTransform()); 367 setTransform(at2); 368 AffineTransform inverse = this.normalizeMatrix(); 369 AffineTransform flipper = AffineTransform.getScaleInstance(1,-1); 370 inverse.concatenate(flipper); 371 double[] mx = new double[6]; 372 inverse.getMatrix(mx); 373 cb.beginText(); 374 cb.setFontAndSize(baseFont, fontSize); 375 cb.setTextMatrix((float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]); 376 Float fontTextAttributeWidth = (Float )font.getAttributes().get(TextAttribute.WIDTH); 377 fontTextAttributeWidth = (fontTextAttributeWidth == null) 378 ? TextAttribute.WIDTH_REGULAR 379 : fontTextAttributeWidth; 380 if (!TextAttribute.WIDTH_REGULAR.equals(fontTextAttributeWidth)) 381 cb.setHorizontalScaling(100.0f / fontTextAttributeWidth.floatValue()); 382 double width = 0; 383 if (font.getSize2D() > 0) { 384 float scale = 1000 / font.getSize2D(); 385 width = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)).getStringBounds(s, getFontRenderContext()).getWidth() / scale; 386 } 387 if (s.length() > 1) { 388 float adv = ((float)width - baseFont.getWidthPoint(s, fontSize)) / (s.length() - 1); 389 cb.setCharacterSpacing(adv); 390 } 391 cb.showText(s); 392 if (s.length() > 1) { 393 cb.setCharacterSpacing(0); 394 } 395 if (!TextAttribute.WIDTH_REGULAR.equals(fontTextAttributeWidth)) 396 cb.setHorizontalScaling(100); 397 cb.endText(); 398 setTransform(at); 399 if(underline) 400 { 401 int UnderlineThickness = 50; 404 double d = asPoints((double)UnderlineThickness, (int)fontSize); 406 setStroke(new BasicStroke ((float)d)); 407 y = (float)((double)(y) + asPoints((double)(UnderlineThickness), (int)fontSize)); 408 Line2D line = new Line2D.Double ((double)x, (double)y, (double)(width+x), (double)y); 409 draw(line); 410 } 411 } 412 } 413 414 417 public void drawString(AttributedCharacterIterator iterator, int x, int y) { 418 drawString(iterator, (float)x, (float)y); 419 } 420 421 424 public void drawString(AttributedCharacterIterator iter, float x, float y) { 425 432 StringBuffer stringbuffer = new StringBuffer (iter.getEndIndex()); 433 for(char c = iter.first(); c != '\uFFFF'; c = iter.next()) 434 { 435 if(iter.getIndex() == iter.getRunStart()) 436 { 437 if(stringbuffer.length() > 0) 438 { 439 drawString(stringbuffer.toString(), x, y); 440 FontMetrics fontmetrics = getFontMetrics(); 441 x = (float)((double)x + fontmetrics.getStringBounds(stringbuffer.toString(), this).getWidth()); 442 stringbuffer.delete(0, stringbuffer.length()); 443 } 444 doAttributes(iter); 445 } 446 stringbuffer.append(c); 447 } 448 449 drawString(stringbuffer.toString(), x, y); 450 underline = false; 451 } 452 453 456 public void drawGlyphVector(GlyphVector g, float x, float y) { 457 Shape s = g.getOutline(x, y); 458 fill(s); 459 } 460 461 464 public void fill(Shape s) { 465 followPath(s, FILL); 466 } 467 468 471 public boolean hit(Rectangle rect, Shape s, boolean onStroke) { 472 if (onStroke) { 473 s = stroke.createStrokedShape(s); 474 } 475 s = transform.createTransformedShape(s); 476 Area area = new Area (s); 477 if (clip != null) 478 area.intersect(clip); 479 return area.intersects(rect.x, rect.y, rect.width, rect.height); 480 } 481 482 485 public GraphicsConfiguration getDeviceConfiguration() { 486 return dg2.getDeviceConfiguration(); 487 } 488 489 493 public void setComposite(Composite comp) { 494 495 if (comp instanceof AlphaComposite ) { 496 497 AlphaComposite composite = (AlphaComposite ) comp; 498 499 if (composite.getRule() == 3) { 500 501 alpha = composite.getAlpha(); 502 this.composite = composite; 503 504 if (realPaint != null && (realPaint instanceof Color )) { 505 506 Color c = (Color ) realPaint; 507 paint = new Color (c.getRed(), c.getGreen(), c.getBlue(), 508 (int) ((float) c.getAlpha() * alpha)); 509 } 510 return; 511 } 512 } 513 514 this.composite = comp; 515 alpha = 1.0F; 516 517 } 518 519 523 public void setPaint(Paint paint) { 524 if (paint == null) 525 return; 526 this.paint = paint; 527 realPaint = paint; 528 529 if ((composite instanceof AlphaComposite ) && (paint instanceof Color )) { 530 531 AlphaComposite co = (AlphaComposite ) composite; 532 533 if (co.getRule() == 3) { 534 Color c = (Color ) paint; 535 this.paint = new Color (c.getRed(), c.getGreen(), c.getBlue(), (int) ((float) c.getAlpha() * alpha)); 536 realPaint = paint; 537 } 538 } 539 540 } 541 542 private Stroke transformStroke(Stroke stroke) { 543 if (!(stroke instanceof BasicStroke )) 544 return stroke; 545 BasicStroke st = (BasicStroke )stroke; 546 float scale = (float)Math.sqrt(Math.abs(transform.getDeterminant())); 547 float dash[] = st.getDashArray(); 548 if (dash != null) { 549 for (int k = 0; k < dash.length; ++k) 550 dash[k] *= scale; 551 } 552 return new BasicStroke (st.getLineWidth() * scale, st.getEndCap(), st.getLineJoin(), st.getMiterLimit(), dash, st.getDashPhase() * scale); 553 } 554 555 private void setStrokeDiff(Stroke newStroke, Stroke oldStroke) { 556 if (newStroke == oldStroke) 557 return; 558 if (!(newStroke instanceof BasicStroke )) 559 return; 560 BasicStroke nStroke = (BasicStroke )newStroke; 561 boolean oldOk = (oldStroke instanceof BasicStroke ); 562 BasicStroke oStroke = null; 563 if (oldOk) 564 oStroke = (BasicStroke )oldStroke; 565 if (!oldOk || nStroke.getLineWidth() != oStroke.getLineWidth()) 566 cb.setLineWidth(nStroke.getLineWidth()); 567 if (!oldOk || nStroke.getEndCap() != oStroke.getEndCap()) { 568 switch (nStroke.getEndCap()) { 569 case BasicStroke.CAP_BUTT: 570 cb.setLineCap(0); 571 break; 572 case BasicStroke.CAP_SQUARE: 573 cb.setLineCap(2); 574 break; 575 default: 576 cb.setLineCap(1); 577 } 578 } 579 if (!oldOk || nStroke.getLineJoin() != oStroke.getLineJoin()) { 580 switch (nStroke.getLineJoin()) { 581 case BasicStroke.JOIN_MITER: 582 cb.setLineJoin(0); 583 break; 584 case BasicStroke.JOIN_BEVEL: 585 cb.setLineJoin(2); 586 break; 587 default: 588 cb.setLineJoin(1); 589 } 590 } 591 if (!oldOk || nStroke.getMiterLimit() != oStroke.getMiterLimit()) 592 cb.setMiterLimit(nStroke.getMiterLimit()); 593 boolean makeDash; 594 if (oldOk) { 595 if (nStroke.getDashArray() != null) { 596 if (nStroke.getDashPhase() != oStroke.getDashPhase()) { 597 makeDash = true; 598 } 599 else if (!java.util.Arrays.equals(nStroke.getDashArray(), oStroke.getDashArray())) { 600 makeDash = true; 601 } 602 else 603 makeDash = false; 604 } 605 else if (oStroke.getDashArray() != null) { 606 makeDash = true; 607 } 608 else 609 makeDash = false; 610 } 611 else { 612 makeDash = true; 613 } 614 if (makeDash) { 615 float dash[] = nStroke.getDashArray(); 616 if (dash == null) 617 cb.setLiteral("[]0 d\n"); 618 else { 619 cb.setLiteral('['); 620 int lim = dash.length; 621 for (int k = 0; k < lim; ++k) { 622 cb.setLiteral(dash[k]); 623 cb.setLiteral(' '); 624 } 625 cb.setLiteral(']'); 626 cb.setLiteral(nStroke.getDashPhase()); 627 cb.setLiteral(" d\n"); 628 } 629 } 630 } 631 632 635 public void setStroke(Stroke s) { 636 originalStroke = s; 637 this.stroke = transformStroke(s); 638 } 639 640 641 646 public void setRenderingHint(Key arg0, Object arg1) { 647 if (arg1 != null) { 648 rhints.put(arg0, arg1); 649 } else { 650 rhints.remove(arg0); 651 } 652 } 653 654 658 public Object getRenderingHint(Key arg0) { 659 return rhints.get(arg0); 660 } 661 662 665 public void setRenderingHints(Map hints) { 666 rhints.clear(); 667 rhints.putAll(hints); 668 } 669 670 673 public void addRenderingHints(Map hints) { 674 rhints.putAll(hints); 675 } 676 677 680 public RenderingHints getRenderingHints() { 681 return rhints; 682 } 683 684 687 public void translate(int x, int y) { 688 translate((double)x, (double)y); 689 } 690 691 694 public void translate(double tx, double ty) { 695 transform.translate(tx,ty); 696 } 697 698 701 public void rotate(double theta) { 702 transform.rotate(theta); 703 } 704 705 708 public void rotate(double theta, double x, double y) { 709 transform.rotate(theta, x, y); 710 } 711 712 715 public void scale(double sx, double sy) { 716 transform.scale(sx, sy); 717 this.stroke = transformStroke(originalStroke); 718 } 719 720 723 public void shear(double shx, double shy) { 724 transform.shear(shx, shy); 725 } 726 727 730 public void transform(AffineTransform tx) { 731 transform.concatenate(tx); 732 this.stroke = transformStroke(originalStroke); 733 } 734 735 738 public void setTransform(AffineTransform t) { 739 transform = new AffineTransform (t); 740 this.stroke = transformStroke(originalStroke); 741 } 742 743 746 public AffineTransform getTransform() { 747 return new AffineTransform (transform); 748 } 749 750 754 public Paint getPaint() { 755 if (realPaint != null) { 756 return realPaint; 757 } else { 758 return paint; 759 } 760 } 761 762 765 public Composite getComposite() { 766 return composite; 767 } 768 769 772 public void setBackground(Color color) { 773 background = color; 774 } 775 776 779 public Color getBackground() { 780 return background; 781 } 782 783 786 public Stroke getStroke() { 787 return originalStroke; 788 } 789 790 791 794 public FontRenderContext getFontRenderContext() { 795 boolean antialias = RenderingHints.VALUE_TEXT_ANTIALIAS_ON.equals(getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING)); 796 boolean fractions = RenderingHints.VALUE_FRACTIONALMETRICS_ON.equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS)); 797 return new FontRenderContext (new AffineTransform (), antialias, fractions); 798 } 799 800 803 public Graphics create() { 804 PdfGraphics2D g2 = new PdfGraphics2D(); 805 g2.onlyShapes = this.onlyShapes; 806 g2.transform = new AffineTransform (this.transform); 807 g2.baseFonts = this.baseFonts; 808 g2.fontMapper = this.fontMapper; 809 g2.paint = this.paint; 810 g2.fillGState = this.fillGState; 811 g2.strokeGState = this.strokeGState; 812 g2.background = this.background; 813 g2.mediaTracker = this.mediaTracker; 814 g2.convertImagesToJPEG = this.convertImagesToJPEG; 815 g2.jpegQuality = this.jpegQuality; 816 g2.setFont(this.font); 817 g2.cb = this.cb.getDuplicate(); 818 g2.cb.saveState(); 819 g2.width = this.width; 820 g2.height = this.height; 821 g2.followPath(new Area (new Rectangle2D.Float (0, 0, width, height)), CLIP); 822 if (this.clip != null) 823 g2.clip = new Area (this.clip); 824 g2.composite = composite; 825 g2.stroke = stroke; 826 g2.originalStroke = originalStroke; 827 g2.strokeOne = (BasicStroke )g2.transformStroke(g2.strokeOne); 828 g2.oldStroke = g2.strokeOne; 829 g2.setStrokeDiff(g2.oldStroke, null); 830 g2.cb.saveState(); 831 if (g2.clip != null) 832 g2.followPath(g2.clip, CLIP); 833 g2.kid = true; 834 if (this.kids == null) 835 this.kids = new ArrayList (); 836 this.kids.add(new Integer (cb.getInternalBuffer().size())); 837 this.kids.add(g2); 838 return g2; 839 } 840 841 public PdfContentByte getContent() { 842 return this.cb; 843 } 844 847 public Color getColor() { 848 if (paint instanceof Color ) { 849 return (Color )paint; 850 } else { 851 return Color.black; 852 } 853 } 854 855 858 public void setColor(Color color) { 859 setPaint(color); 860 } 861 862 865 public void setPaintMode() {} 866 867 870 public void setXORMode(Color c1) { 871 872 } 873 874 877 public Font getFont() { 878 return font; 879 } 880 881 884 887 public void setFont(Font f) { 888 if (f == null) 889 return; 890 if (onlyShapes) { 891 font = f; 892 return; 893 } 894 if (f == font) 895 return; 896 font = f; 897 fontSize = f.getSize2D(); 898 baseFont = getCachedBaseFont(f); 899 } 900 901 private BaseFont getCachedBaseFont(Font f) { 902 synchronized (baseFonts) { 903 BaseFont bf = (BaseFont)baseFonts.get(f.getFontName()); 904 if (bf == null) { 905 bf = fontMapper.awtToPdf(f); 906 baseFonts.put(f.getFontName(), bf); 907 } 908 return bf; 909 } 910 } 911 912 915 public FontMetrics getFontMetrics(Font f) { 916 return dg2.getFontMetrics(f); 917 } 918 919 922 public Rectangle getClipBounds() { 923 if (clip == null) 924 return null; 925 return getClip().getBounds(); 926 } 927 928 931 public void clipRect(int x, int y, int width, int height) { 932 Rectangle2D rect = new Rectangle2D.Double (x,y,width,height); 933 clip(rect); 934 } 935 936 939 public void setClip(int x, int y, int width, int height) { 940 Rectangle2D rect = new Rectangle2D.Double (x,y,width,height); 941 setClip(rect); 942 } 943 944 947 public void clip(Shape s) { 948 if (s == null) { 949 setClip(null); 950 return; 951 } 952 s = transform.createTransformedShape(s); 953 if (clip == null) 954 clip = new Area (s); 955 else 956 clip.intersect(new Area (s)); 957 followPath(s, CLIP); 958 } 959 960 963 public Shape getClip() { 964 try { 965 return transform.createInverse().createTransformedShape(clip); 966 } 967 catch (NoninvertibleTransformException e) { 968 return null; 969 } 970 } 971 972 975 public void setClip(Shape s) { 976 cb.restoreState(); 977 cb.saveState(); 978 if (s != null) 979 s = transform.createTransformedShape(s); 980 if (s == null) { 981 clip = null; 982 } 983 else { 984 clip = new Area (s); 985 followPath(s, CLIP); 986 } 987 paintFill = paintStroke = null; 988 currentFillGState = currentStrokeGState = 255; 989 oldStroke = strokeOne; 990 } 991 992 995 public void copyArea(int x, int y, int width, int height, int dx, int dy) { 996 997 } 998 999 1002 public void drawLine(int x1, int y1, int x2, int y2) { 1003 Line2D line = new Line2D.Double ((double)x1, (double)y1, (double)x2, (double)y2); 1004 draw(line); 1005 } 1006 1007 1010 public void drawRect(int x, int y, int width, int height) { 1011 draw(new Rectangle (x, y, width, height)); 1012 } 1013 1014 1017 public void fillRect(int x, int y, int width, int height) { 1018 fill(new Rectangle (x,y,width,height)); 1019 } 1020 1021 1024 public void clearRect(int x, int y, int width, int height) { 1025 Paint temp = paint; 1026 setPaint(background); 1027 fillRect(x,y,width,height); 1028 setPaint(temp); 1029 } 1030 1031 1034 public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { 1035 RoundRectangle2D rect = new RoundRectangle2D.Double (x,y,width,height,arcWidth, arcHeight); 1036 draw(rect); 1037 } 1038 1039 1042 public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { 1043 RoundRectangle2D rect = new RoundRectangle2D.Double (x,y,width,height,arcWidth, arcHeight); 1044 fill(rect); 1045 } 1046 1047 1050 public void drawOval(int x, int y, int width, int height) { 1051 Ellipse2D oval = new Ellipse2D.Float ((float)x, (float)y, (float)width, (float)height); 1052 draw(oval); 1053 } 1054 1055 1058 public void fillOval(int x, int y, int width, int height) { 1059 Ellipse2D oval = new Ellipse2D.Float ((float)x, (float)y, (float)width, (float)height); 1060 fill(oval); 1061 } 1062 1063 1066 public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { 1067 Arc2D arc = new Arc2D.Double (x,y,width,height,startAngle, arcAngle, Arc2D.OPEN); 1068 draw(arc); 1069 1070 } 1071 1072 1075 public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { 1076 Arc2D arc = new Arc2D.Double (x,y,width,height,startAngle, arcAngle, Arc2D.PIE); 1077 fill(arc); 1078 } 1079 1080 1083 public void drawPolyline(int[] x, int[] y, int nPoints) { 1084 PolylineShape polyline = new PolylineShape(x, y, nPoints); 1085 draw(polyline); 1086 } 1087 1088 1091 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { 1092 Polygon poly = new Polygon (xPoints, yPoints, nPoints); 1093 draw(poly); 1094 } 1095 1096 1099 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { 1100 Polygon poly = new Polygon (); 1101 for (int i = 0; i < nPoints; i++) { 1102 poly.addPoint(xPoints[i], yPoints[i]); 1103 } 1104 fill(poly); 1105 } 1106 1107 1110 public boolean drawImage(Image img, int x, int y, ImageObserver observer) { 1111 return drawImage(img, x, y, null, observer); 1112 } 1113 1114 1117 public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { 1118 return drawImage(img, x, y, width, height, null, observer); 1119 } 1120 1121 1124 public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { 1125 waitForImage(img); 1126 return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), bgcolor, observer); 1127 } 1128 1129 1132 public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { 1133 waitForImage(img); 1134 double scalex = width/(double)img.getWidth(observer); 1135 double scaley = height/(double)img.getHeight(observer); 1136 AffineTransform tx = AffineTransform.getTranslateInstance(x,y); 1137 tx.scale(scalex,scaley); 1138 return drawImage(img, null, tx, bgcolor, observer); 1139 } 1140 1141 1144 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { 1145 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); 1146 } 1147 1148 1151 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) { 1152 waitForImage(img); 1153 double dwidth = (double)dx2-dx1; 1154 double dheight = (double)dy2-dy1; 1155 double swidth = (double)sx2-sx1; 1156 double sheight = (double)sy2-sy1; 1157 1158 if (dwidth == 0 || dheight == 0 || swidth == 0 || sheight == 0) return true; 1160 1161 double scalex = dwidth/swidth; 1162 double scaley = dheight/sheight; 1163 1164 double transx = sx1*scalex; 1165 double transy = sy1*scaley; 1166 AffineTransform tx = AffineTransform.getTranslateInstance(dx1-transx,dy1-transy); 1167 tx.scale(scalex,scaley); 1168 1169 BufferedImage mask = new BufferedImage (img.getWidth(observer), img.getHeight(observer), BufferedImage.TYPE_BYTE_BINARY); 1170 Graphics g = mask.getGraphics(); 1171 g.fillRect(sx1,sy1, (int)swidth, (int)sheight); 1172 drawImage(img, mask, tx, null, observer); 1173 g.dispose(); 1174 return true; 1175 } 1176 1177 1180 public void dispose() { 1181 if (kid) 1182 return; 1183 if (!disposeCalled) { 1184 disposeCalled = true; 1185 cb.restoreState(); 1186 cb.restoreState(); 1187 dg2.dispose(); 1188 dg2 = null; 1189 if (kids != null) { 1190 ByteBuffer buf = new ByteBuffer(); 1191 internalDispose(buf); 1192 ByteBuffer buf2 = cb.getInternalBuffer(); 1193 buf2.reset(); 1194 buf2.append(buf); 1195 } 1196 } 1197 } 1198 1199 private void internalDispose(ByteBuffer buf) { 1200 int last = 0; 1201 int pos = 0; 1202 ByteBuffer buf2 = cb.getInternalBuffer(); 1203 if (kids != null) { 1204 for (int k = 0; k < kids.size(); k += 2) { 1205 pos = ((Integer )kids.get(k)).intValue(); 1206 PdfGraphics2D g2 = (PdfGraphics2D)kids.get(k + 1); 1207 g2.cb.restoreState(); 1208 g2.cb.restoreState(); 1209 buf.append(buf2.getBuffer(), last, pos - last); 1210 g2.dg2.dispose(); 1211 g2.dg2 = null; 1212 g2.internalDispose(buf); 1213 last = pos; 1214 } 1215 } 1216 buf.append(buf2.getBuffer(), last, buf2.size() - last); 1217 } 1218 1219 1226 1227 private void followPath(Shape s, int drawType) { 1228 if (s==null) return; 1229 if (drawType==STROKE) { 1230 if (!(stroke instanceof BasicStroke )) { 1231 s = stroke.createStrokedShape(s); 1232 followPath(s, FILL); 1233 return; 1234 } 1235 } 1236 if (drawType==STROKE) { 1237 setStrokeDiff(stroke, oldStroke); 1238 oldStroke = stroke; 1239 setStrokePaint(); 1240 } 1241 else if (drawType==FILL) 1242 setFillPaint(); 1243 PathIterator points; 1244 int traces = 0; 1245 if (drawType == CLIP) 1246 points = s.getPathIterator(IDENTITY); 1247 else 1248 points = s.getPathIterator(transform); 1249 float[] coords = new float[6]; 1250 while(!points.isDone()) { 1251 ++traces; 1252 int segtype = points.currentSegment(coords); 1253 normalizeY(coords); 1254 switch(segtype) { 1255 case PathIterator.SEG_CLOSE: 1256 cb.closePath(); 1257 break; 1258 1259 case PathIterator.SEG_CUBICTO: 1260 cb.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); 1261 break; 1262 1263 case PathIterator.SEG_LINETO: 1264 cb.lineTo(coords[0], coords[1]); 1265 break; 1266 1267 case PathIterator.SEG_MOVETO: 1268 cb.moveTo(coords[0], coords[1]); 1269 break; 1270 1271 case PathIterator.SEG_QUADTO: 1272 cb.curveTo(coords[0], coords[1], coords[2], coords[3]); 1273 break; 1274 } 1275 points.next(); 1276 } 1277 switch (drawType) { 1278 case FILL: 1279 if (traces > 0) { 1280 if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) 1281 cb.eoFill(); 1282 else 1283 cb.fill(); 1284 } 1285 break; 1286 case STROKE: 1287 if (traces > 0) 1288 cb.stroke(); 1289 break; 1290 default: if (traces == 0) 1292 cb.rectangle(0, 0, 0, 0); 1293 if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) 1294 cb.eoClip(); 1295 else 1296 cb.clip(); 1297 cb.newPath(); 1298 } 1299 } 1300 1301 private float normalizeY(float y) { 1302 return this.height - y; 1303 } 1304 1305 private void normalizeY(float[] coords) { 1306 coords[1] = normalizeY(coords[1]); 1307 coords[3] = normalizeY(coords[3]); 1308 coords[5] = normalizeY(coords[5]); 1309 } 1310 1311 private AffineTransform normalizeMatrix() { 1312 double[] mx = new double[6]; 1313 AffineTransform result = AffineTransform.getTranslateInstance(0,0); 1314 result.getMatrix(mx); 1315 mx[3]=-1; 1316 mx[5]=height; 1317 result = new AffineTransform (mx); 1318 result.concatenate(transform); 1319 return result; 1320 } 1321 1322 private boolean drawImage(Image img, Image mask, AffineTransform xform, Color bgColor, ImageObserver obs) { 1323 if (xform==null) return true; 1324 1325 xform.translate(0, img.getHeight(obs)); 1326 xform.scale(img.getWidth(obs), img.getHeight(obs)); 1327 1328 AffineTransform inverse = this.normalizeMatrix(); 1329 AffineTransform flipper = AffineTransform.getScaleInstance(1,-1); 1330 inverse.concatenate(xform); 1331 inverse.concatenate(flipper); 1332 1333 double[] mx = new double[6]; 1334 inverse.getMatrix(mx); 1335 if (currentFillGState != 255) { 1336 PdfGState gs = fillGState[255]; 1337 if (gs == null) { 1338 gs = new PdfGState(); 1339 gs.setFillOpacity(1); 1340 fillGState[255] = gs; 1341 } 1342 cb.setGState(gs); 1343 } 1344 1345 try { 1346 com.lowagie.text.Image image = null; 1347 if(!convertImagesToJPEG){ 1348 image = com.lowagie.text.Image.getInstance(img, bgColor); 1349 } 1350 else{ 1351 BufferedImage scaled = new BufferedImage (img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB); 1352 Graphics2D g3 = scaled.createGraphics(); 1353 g3.drawImage(img, 0, 0, img.getWidth(null), img.getHeight(null), null); 1354 g3.dispose(); 1355 1356 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 1357 com.sun.image.codec.jpeg.JPEGImageEncoder encoder = com.sun.image.codec.jpeg.JPEGCodec.createJPEGEncoder(baos); 1358 com.sun.image.codec.jpeg.JPEGEncodeParam param = com.sun.image.codec.jpeg.JPEGCodec.getDefaultJPEGEncodeParam(scaled); 1359 param.setQuality(jpegQuality, true); 1360 encoder.encode(scaled, param); 1361 scaled.flush(); 1362 scaled = null; 1363 image = com.lowagie.text.Image.getInstance(baos.toByteArray()); 1364 1365 } 1366 if (mask!=null) { 1367 com.lowagie.text.Image msk = com.lowagie.text.Image.getInstance(mask, null, true); 1368 msk.makeMask(); 1369 msk.setInverted(true); 1370 image.setImageMask(msk); 1371 } 1372 cb.addImage(image, (float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]); 1373 } catch (Exception ex) { 1374 throw new IllegalArgumentException (); 1375 } 1376 if (currentFillGState != 255) { 1377 PdfGState gs = fillGState[currentFillGState]; 1378 cb.setGState(gs); 1379 } 1380 return true; 1381 } 1382 1383 private boolean checkNewPaint(Paint oldPaint) { 1384 if (paint == oldPaint) 1385 return false; 1386 return !((paint instanceof Color ) && paint.equals(oldPaint)); 1387 } 1388 1389 private void setFillPaint() { 1390 if (checkNewPaint(paintFill)) { 1391 paintFill = paint; 1392 setPaint(false, 0, 0, true); 1393 } 1394 } 1395 1396 private void setStrokePaint() { 1397 if (checkNewPaint(paintStroke)) { 1398 paintStroke = paint; 1399 setPaint(false, 0, 0, false); 1400 } 1401 } 1402 1403 private void setPaint(boolean invert, double xoffset, double yoffset, boolean fill) { 1404 if (paint instanceof Color ) { 1405 Color color = (Color )paint; 1406 int alpha = color.getAlpha(); 1407 if (fill) { 1408 if (alpha != currentFillGState) { 1409 currentFillGState = alpha; 1410 PdfGState gs = fillGState[alpha]; 1411 if (gs == null) { 1412 gs = new PdfGState(); 1413 gs.setFillOpacity((float)alpha / 255f); 1414 fillGState[alpha] = gs; 1415 } 1416 cb.setGState(gs); 1417 } 1418 cb.setColorFill(color); 1419 } 1420 else { 1421 if (alpha != currentStrokeGState) { 1422 currentStrokeGState = alpha; 1423 PdfGState gs = strokeGState[alpha]; 1424 if (gs == null) { 1425 gs = new PdfGState(); 1426 gs.setStrokeOpacity((float)alpha / 255f); 1427 strokeGState[alpha] = gs; 1428 } 1429 cb.setGState(gs); 1430 } 1431 cb.setColorStroke(color); 1432 } 1433 } 1434 else if (paint instanceof GradientPaint ) { 1435 GradientPaint gp = (GradientPaint )paint; 1436 Point2D p1 = gp.getPoint1(); 1437 transform.transform(p1, p1); 1438 Point2D p2 = gp.getPoint2(); 1439 transform.transform(p2, p2); 1440 Color c1 = gp.getColor1(); 1441 Color c2 = gp.getColor2(); 1442 PdfShading shading = PdfShading.simpleAxial(cb.getPdfWriter(), (float)p1.getX(), normalizeY((float)p1.getY()), (float)p2.getX(), normalizeY((float)p2.getY()), c1, c2); 1443 PdfShadingPattern pat = new PdfShadingPattern(shading); 1444 if (fill) 1445 cb.setShadingFill(pat); 1446 else 1447 cb.setShadingStroke(pat); 1448 } 1449 else if (paint instanceof TexturePaint ) { 1450 try { 1451 TexturePaint tp = (TexturePaint )paint; 1452 BufferedImage img = tp.getImage(); 1453 Rectangle2D rect = tp.getAnchorRect(); 1454 com.lowagie.text.Image image = com.lowagie.text.Image.getInstance(img, null); 1455 PdfPatternPainter pattern = cb.createPattern(image.getWidth(), image.getHeight()); 1456 AffineTransform inverse = this.normalizeMatrix(); 1457 inverse.translate(rect.getX(), rect.getY()); 1458 inverse.scale(rect.getWidth() / image.getWidth(), -rect.getHeight() / image.getHeight()); 1459 double[] mx = new double[6]; 1460 inverse.getMatrix(mx); 1461 pattern.setPatternMatrix((float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]) ; 1462 image.setAbsolutePosition(0,0); 1463 pattern.addImage(image); 1464 if (fill) 1465 cb.setPatternFill(pattern); 1466 else 1467 cb.setPatternStroke(pattern); 1468 } catch (Exception ex) { 1469 if (fill) 1470 cb.setColorFill(Color.gray); 1471 else 1472 cb.setColorStroke(Color.gray); 1473 } 1474 } 1475 else { 1476 try { 1477 BufferedImage img = null; 1478 int type = BufferedImage.TYPE_4BYTE_ABGR; 1479 if (paint.getTransparency() == Transparency.OPAQUE) { 1480 type = BufferedImage.TYPE_3BYTE_BGR; 1481 } 1482 img = new BufferedImage ((int)width, (int)height, type); 1483 Graphics2D g = (Graphics2D )img.getGraphics(); 1484 g.transform(transform); 1485 AffineTransform inv = transform.createInverse(); 1486 Shape fillRect = new Rectangle2D.Double (0,0,img.getWidth(),img.getHeight()); 1487 fillRect = inv.createTransformedShape(fillRect); 1488 g.setPaint(paint); 1489 g.fill(fillRect); 1490 if (invert) { 1491 AffineTransform tx = new AffineTransform (); 1492 tx.scale(1,-1); 1493 tx.translate(-xoffset,-yoffset); 1494 g.drawImage(img,tx,null); 1495 } 1496 g.dispose(); 1497 g = null; 1498 com.lowagie.text.Image image = com.lowagie.text.Image.getInstance(img, null); 1499 PdfPatternPainter pattern = cb.createPattern(width, height); 1500 image.setAbsolutePosition(0,0); 1501 pattern.addImage(image); 1502 if (fill) 1503 cb.setPatternFill(pattern); 1504 else 1505 cb.setPatternStroke(pattern); 1506 } catch (Exception ex) { 1507 if (fill) 1508 cb.setColorFill(Color.gray); 1509 else 1510 cb.setColorStroke(Color.gray); 1511 } 1512 } 1513 } 1514 1515 private synchronized void waitForImage(java.awt.Image image) { 1516 if (mediaTracker == null) 1517 mediaTracker = new MediaTracker (new PdfGraphics2D.fakeComponent()); 1518 mediaTracker.addImage(image, 0); 1519 try { 1520 mediaTracker.waitForID(0); 1521 } 1522 catch (InterruptedException e) { 1523 } 1525 mediaTracker.removeImage(image); 1526 } 1527 1528 static private class fakeComponent extends Component { 1529 1530 private static final long serialVersionUID = 6450197945596086638L; 1531 } 1532} 1533 | Popular Tags |