| 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  
|