1 /* 2 * $Id$ 3 * 4 * Copyright 2002 by Jim Moore <jim@scolamoore.com>. 5 * 6 * The contents of this file are subject to the Mozilla Public License Version 1.1 7 * (the "License"); you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at http://www.mozilla.org/MPL/ 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the License. 13 * 14 * The Original Code is 'iText, a free JAVA-PDF library'. 15 * 16 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by 17 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. 18 * All Rights Reserved. 19 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer 20 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. 21 * 22 * Contributor(s): all the names of the contributors are added in the source code 23 * where applicable. 24 * 25 * Alternatively, the contents of this file may be used under the terms of the 26 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the 27 * provisions of LGPL are applicable instead of those above. If you wish to 28 * allow use of your version of this file only under the terms of the LGPL 29 * License and not to allow others to use your version of this file under 30 * the MPL, indicate your decision by deleting the provisions above and 31 * replace them with the notice and other provisions required by the LGPL. 32 * If you do not delete the provisions above, a recipient may use your version 33 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. 34 * 35 * This library is free software; you can redistribute it and/or modify it 36 * under the terms of the MPL as stated above or under the terms of the GNU 37 * Library General Public License as published by the Free Software Foundation; 38 * either version 2 of the License, or any later version. 39 * 40 * This library is distributed in the hope that it will be useful, but WITHOUT 41 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 42 * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more 43 * details. 44 * 45 * If you didn't download this code from the following link, you should check if 46 * you aren't using an obsolete version: 47 * http://www.lowagie.com/iText/ 48 */ 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 import java.util.Locale; 105 import javax.imageio.IIOImage; 106 import javax.imageio.ImageIO; 107 import javax.imageio.ImageWriteParam; 108 import javax.imageio.ImageWriter; 109 import javax.imageio.plugins.jpeg.JPEGImageWriteParam; 110 import javax.imageio.stream.ImageOutputStream; 111 112 public class PdfGraphics2D extends Graphics2D { 113 114 private static final int FILL = 1; 115 private static final int STROKE = 2; 116 private static final int CLIP = 3; 117 private BasicStroke strokeOne = new BasicStroke(1); 118 119 private static final AffineTransform IDENTITY = new AffineTransform(); 120 121 private Font font; 122 private BaseFont baseFont; 123 private float fontSize; 124 private AffineTransform transform; 125 private Paint paint; 126 private Color background; 127 private float width; 128 private float height; 129 130 private Area clip; 131 132 private RenderingHints rhints = new RenderingHints(null); 133 134 private Stroke stroke; 135 private Stroke originalStroke; 136 137 private PdfContentByte cb; 138 139 /** Storage for BaseFont objects created. */ 140 private HashMap baseFonts; 141 142 private boolean disposeCalled = false; 143 144 private FontMapper fontMapper; 145 146 private ArrayList kids; 147 148 private boolean kid = false; 149 150 private Graphics2D dg2 = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB).createGraphics(); 151 152 private boolean onlyShapes = false; 153 154 private Stroke oldStroke; 155 private Paint paintFill; 156 private Paint paintStroke; 157 158 private MediaTracker mediaTracker; 159 160 // Added by Jurij Bilas 161 protected boolean underline; // indicates if the font style is underlined 162 163 protected PdfGState fillGState[] = new PdfGState[256]; 164 protected PdfGState strokeGState[] = new PdfGState[256]; 165 protected int currentFillGState = 255; 166 protected int currentStrokeGState = 255; 167 168 public static final int AFM_DIVISOR = 1000; // used to calculate coordinates 169 170 private boolean convertImagesToJPEG = false; 171 private float jpegQuality = .95f; 172 173 // Added by Alexej Suchov 174 private float alpha; 175 176 // Added by Alexej Suchov 177 private Composite composite; 178 179 // Added by Alexej Suchov 180 private Paint realPaint; 181 PdfGraphics2D()182 private PdfGraphics2D() { 183 dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 184 setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 185 setRenderingHint(HyperLinkKey.KEY_INSTANCE, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); 186 } 187 188 /** 189 * Constructor for PDFGraphics2D. 190 * 191 */ PdfGraphics2D(PdfContentByte cb, float width, float height, FontMapper fontMapper, boolean onlyShapes, boolean convertImagesToJPEG, float quality)192 PdfGraphics2D(PdfContentByte cb, float width, float height, FontMapper fontMapper, boolean onlyShapes, boolean convertImagesToJPEG, float quality) { 193 super(); 194 dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 195 setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 196 setRenderingHint(HyperLinkKey.KEY_INSTANCE, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); 197 this.convertImagesToJPEG = convertImagesToJPEG; 198 this.jpegQuality = quality; 199 this.onlyShapes = onlyShapes; 200 this.transform = new AffineTransform(); 201 this.baseFonts = new HashMap(); 202 if (!onlyShapes) { 203 this.fontMapper = fontMapper; 204 if (this.fontMapper == null) 205 this.fontMapper = new DefaultFontMapper(); 206 } 207 paint = Color.black; 208 background = Color.white; 209 setFont(new Font("sanserif", Font.PLAIN, 12)); 210 this.cb = cb; 211 cb.saveState(); 212 this.width = width; 213 this.height = height; 214 clip = new Area(new Rectangle2D.Float(0, 0, width, height)); 215 clip(clip); 216 originalStroke = stroke = oldStroke = strokeOne; 217 setStrokeDiff(stroke, null); 218 cb.saveState(); 219 } 220 221 /** 222 * @see Graphics2D#draw(Shape) 223 */ draw(Shape s)224 public void draw(Shape s) { 225 followPath(s, STROKE); 226 } 227 228 /** 229 * @see Graphics2D#drawImage(Image, AffineTransform, ImageObserver) 230 */ drawImage(Image img, AffineTransform xform, ImageObserver obs)231 public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { 232 return drawImage(img, null, xform, null, obs); 233 } 234 235 /** 236 * @see Graphics2D#drawImage(BufferedImage, BufferedImageOp, int, int) 237 */ drawImage(BufferedImage img, BufferedImageOp op, int x, int y)238 public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { 239 BufferedImage result = img; 240 if (op != null) { 241 result = op.createCompatibleDestImage(img, img.getColorModel()); 242 result = op.filter(img, result); 243 } 244 drawImage(result, x, y, null); 245 } 246 247 /** 248 * @see Graphics2D#drawRenderedImage(RenderedImage, AffineTransform) 249 */ drawRenderedImage(RenderedImage img, AffineTransform xform)250 public void drawRenderedImage(RenderedImage img, AffineTransform xform) { 251 BufferedImage image = null; 252 if (img instanceof BufferedImage) { 253 image = (BufferedImage)img; 254 } else { 255 ColorModel cm = img.getColorModel(); 256 int width = img.getWidth(); 257 int height = img.getHeight(); 258 WritableRaster raster = cm.createCompatibleWritableRaster(width, height); 259 boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); 260 Hashtable properties = new Hashtable(); 261 String[] keys = img.getPropertyNames(); 262 if (keys!=null) { 263 for (int i = 0; i < keys.length; i++) { 264 properties.put(keys[i], img.getProperty(keys[i])); 265 } 266 } 267 BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties); 268 img.copyData(raster); 269 image=result; 270 } 271 drawImage(image, xform, null); 272 } 273 274 /** 275 * @see Graphics2D#drawRenderableImage(RenderableImage, AffineTransform) 276 */ drawRenderableImage(RenderableImage img, AffineTransform xform)277 public void drawRenderableImage(RenderableImage img, AffineTransform xform) { 278 drawRenderedImage(img.createDefaultRendering(), xform); 279 } 280 281 /** 282 * @see Graphics#drawString(String, int, int) 283 */ drawString(String s, int x, int y)284 public void drawString(String s, int x, int y) { 285 drawString(s, (float)x, (float)y); 286 } 287 288 /** 289 * Calculates position and/or stroke thickness depending on the font size 290 * @param d value to be converted 291 * @param i font size 292 * @return position and/or stroke thickness depending on the font size 293 */ asPoints(double d, int i)294 public static double asPoints(double d, int i) { 295 return d * i / AFM_DIVISOR; 296 } 297 /** 298 * This routine goes through the attributes and sets the font 299 * before calling the actual string drawing routine 300 * @param iter 301 */ doAttributes(AttributedCharacterIterator iter)302 protected void doAttributes(AttributedCharacterIterator iter) { 303 underline = false; 304 Set set = iter.getAttributes().keySet(); 305 for(Iterator iterator = set.iterator(); iterator.hasNext();) { 306 AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute)iterator.next(); 307 if (!(attribute instanceof TextAttribute)) 308 continue; 309 TextAttribute textattribute = (TextAttribute)attribute; 310 if(textattribute.equals(TextAttribute.FONT)) { 311 Font font = (Font)iter.getAttributes().get(textattribute); 312 setFont(font); 313 } 314 else if(textattribute.equals(TextAttribute.UNDERLINE)) { 315 if(iter.getAttributes().get(textattribute) == TextAttribute.UNDERLINE_ON) 316 underline = true; 317 } 318 else if(textattribute.equals(TextAttribute.SIZE)) { 319 Object obj = iter.getAttributes().get(textattribute); 320 if(obj instanceof Integer) { 321 int i = ((Integer)obj).intValue(); 322 setFont(getFont().deriveFont(getFont().getStyle(), i)); 323 } 324 else if(obj instanceof Float) { 325 float f = ((Float)obj).floatValue(); 326 setFont(getFont().deriveFont(getFont().getStyle(), f)); 327 } 328 } 329 else if(textattribute.equals(TextAttribute.FOREGROUND)) { 330 setColor((Color) iter.getAttributes().get(textattribute)); 331 } 332 else if(textattribute.equals(TextAttribute.FAMILY)) { 333 Font font = getFont(); 334 Map fontAttributes = font.getAttributes(); 335 fontAttributes.put(TextAttribute.FAMILY, iter.getAttributes().get(textattribute)); 336 setFont(font.deriveFont(fontAttributes)); 337 } 338 else if(textattribute.equals(TextAttribute.POSTURE)) { 339 Font font = getFont(); 340 Map fontAttributes = font.getAttributes(); 341 fontAttributes.put(TextAttribute.POSTURE, iter.getAttributes().get(textattribute)); 342 setFont(font.deriveFont(fontAttributes)); 343 } 344 else if(textattribute.equals(TextAttribute.WEIGHT)) { 345 Font font = getFont(); 346 Map fontAttributes = font.getAttributes(); 347 fontAttributes.put(TextAttribute.WEIGHT, iter.getAttributes().get(textattribute)); 348 setFont(font.deriveFont(fontAttributes)); 349 } 350 } 351 } 352 353 /** 354 * @see Graphics2D#drawString(String, float, float) 355 */ drawString(String s, float x, float y)356 public void drawString(String s, float x, float y) { 357 if (s.length() == 0) 358 return; 359 setFillPaint(); 360 if (onlyShapes) { 361 drawGlyphVector(this.font.layoutGlyphVector(getFontRenderContext(), s.toCharArray(), 0, s.length(), java.awt.Font.LAYOUT_LEFT_TO_RIGHT), x, y); 362 // Use the following line to compile in JDK 1.3 363 // drawGlyphVector(this.font.createGlyphVector(getFontRenderContext(), s), x, y); 364 } 365 else { 366 boolean restoreTextRenderingMode = false; 367 AffineTransform at = getTransform(); 368 AffineTransform at2 = getTransform(); 369 at2.translate(x, y); 370 at2.concatenate(font.getTransform()); 371 setTransform(at2); 372 AffineTransform inverse = this.normalizeMatrix(); 373 AffineTransform flipper = AffineTransform.getScaleInstance(1,-1); 374 inverse.concatenate(flipper); 375 double[] mx = new double[6]; 376 inverse.getMatrix(mx); 377 cb.beginText(); 378 cb.setFontAndSize(baseFont, fontSize); 379 // Check if we need to simulate an italic font. 380 // When there are different fonts for italic, bold, italic bold 381 // the font.getName() will be different from the font.getFontName() 382 // value. When they are the same value then we are normally dealing 383 // with a single font that has been made into an italic or bold 384 // font. 385 if (font.isItalic() && font.getFontName().equals(font.getName())) { 386 float angle = baseFont.getFontDescriptor(BaseFont.ITALICANGLE, 1000); 387 float angle2 = font.getItalicAngle(); 388 // We don't have an italic version of this font so we need 389 // to set the font angle ourselves to produce an italic font. 390 if (angle2 == 0) { 391 // The JavaVM didn't have an angle setting for making 392 // the font an italic font so use a default of 393 // italic angle of 15 degrees. 394 angle2 = 15.0f; 395 } else { 396 // This sign of the angle for Java and PDF seams 397 // seams to be reversed. 398 angle2 = -angle2; 399 } 400 if (angle == 0) { 401 mx[2] = angle2 / 100.0f; 402 } 403 } 404 cb.setTextMatrix((float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]); 405 Float fontTextAttributeWidth = (Float)font.getAttributes().get(TextAttribute.WIDTH); 406 fontTextAttributeWidth = (fontTextAttributeWidth == null) 407 ? TextAttribute.WIDTH_REGULAR 408 : fontTextAttributeWidth; 409 if (!TextAttribute.WIDTH_REGULAR.equals(fontTextAttributeWidth)) 410 cb.setHorizontalScaling(100.0f / fontTextAttributeWidth.floatValue()); 411 412 // Check if we need to simulate a bold font. 413 // Do nothing if the BaseFont is already bold. This test is not foolproof but it will work most of the times. 414 if (baseFont.getPostscriptFontName().toLowerCase().indexOf("bold") < 0) { 415 // Get the weight of the font so we can detect fonts with a weight 416 // that makes them bold, but the Font.isBold() value is false. 417 Float weight = (Float) font.getAttributes().get(TextAttribute.WEIGHT); 418 if (weight == null) { 419 weight = (font.isBold()) ? TextAttribute.WEIGHT_BOLD 420 : TextAttribute.WEIGHT_REGULAR; 421 } 422 if ((font.isBold() || (weight.floatValue() >= TextAttribute.WEIGHT_SEMIBOLD.floatValue())) 423 && (font.getFontName().equals(font.getName()))) { 424 // Simulate a bold font. 425 float strokeWidth = font.getSize2D() * (weight.floatValue() - TextAttribute.WEIGHT_REGULAR.floatValue()) / 30f; 426 if (strokeWidth != 1) { 427 if(realPaint instanceof Color){ 428 cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE); 429 cb.setLineWidth(strokeWidth); 430 Color color = (Color)realPaint; 431 int alpha = color.getAlpha(); 432 if (alpha != currentStrokeGState) { 433 currentStrokeGState = alpha; 434 PdfGState gs = strokeGState[alpha]; 435 if (gs == null) { 436 gs = new PdfGState(); 437 gs.setStrokeOpacity(alpha / 255f); 438 strokeGState[alpha] = gs; 439 } 440 cb.setGState(gs); 441 } 442 cb.setColorStroke(color); 443 restoreTextRenderingMode = true; 444 } 445 } 446 } 447 } 448 449 double width = 0; 450 if (font.getSize2D() > 0) { 451 float scale = 1000 / font.getSize2D(); 452 Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)); 453 width = derivedFont.getStringBounds(s, getFontRenderContext()).getWidth(); 454 if (derivedFont.isTransformed()) 455 width /= scale; 456 } 457 // if the hyperlink flag is set add an action to the text 458 Object url = getRenderingHint(HyperLinkKey.KEY_INSTANCE); 459 if (url != null && !url.equals(HyperLinkKey.VALUE_HYPERLINKKEY_OFF)) 460 { 461 float scale = 1000 / font.getSize2D(); 462 Font derivedFont = font.deriveFont(AffineTransform.getScaleInstance(scale, scale)); 463 double height = derivedFont.getStringBounds(s, getFontRenderContext()).getHeight(); 464 if (derivedFont.isTransformed()) 465 height /= scale; 466 double leftX = cb.getXTLM(); 467 double leftY = cb.getYTLM(); 468 PdfAction action = new PdfAction(url.toString()); 469 cb.setAction(action, (float)leftX, (float)leftY, (float)(leftX+width), (float)(leftY+height)); 470 } 471 if (s.length() > 1) { 472 float adv = ((float)width - baseFont.getWidthPoint(s, fontSize)) / (s.length() - 1); 473 cb.setCharacterSpacing(adv); 474 } 475 cb.showText(s); 476 if (s.length() > 1) { 477 cb.setCharacterSpacing(0); 478 } 479 if (!TextAttribute.WIDTH_REGULAR.equals(fontTextAttributeWidth)) 480 cb.setHorizontalScaling(100); 481 482 // Restore the original TextRenderingMode if needed. 483 if (restoreTextRenderingMode) { 484 cb.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL); 485 } 486 487 cb.endText(); 488 setTransform(at); 489 if(underline) 490 { 491 // These two are supposed to be taken from the .AFM file 492 //int UnderlinePosition = -100; 493 int UnderlineThickness = 50; 494 // 495 double d = asPoints(UnderlineThickness, (int)fontSize); 496 Stroke savedStroke = originalStroke; 497 setStroke(new BasicStroke((float)d)); 498 y = (float)(y + asPoints(UnderlineThickness, (int)fontSize)); 499 Line2D line = new Line2D.Double(x, y, width+x, y); 500 draw(line); 501 setStroke(savedStroke); 502 } 503 } 504 } 505 506 /** 507 * @see Graphics#drawString(AttributedCharacterIterator, int, int) 508 */ drawString(AttributedCharacterIterator iterator, int x, int y)509 public void drawString(AttributedCharacterIterator iterator, int x, int y) { 510 drawString(iterator, (float)x, (float)y); 511 } 512 513 /** 514 * @see Graphics2D#drawString(AttributedCharacterIterator, float, float) 515 */ drawString(AttributedCharacterIterator iter, float x, float y)516 public void drawString(AttributedCharacterIterator iter, float x, float y) { 517 /* 518 StringBuffer sb = new StringBuffer(); 519 for(char c = iter.first(); c != AttributedCharacterIterator.DONE; c = iter.next()) { 520 sb.append(c); 521 } 522 drawString(sb.toString(),x,y); 523 */ 524 StringBuffer stringbuffer = new StringBuffer(iter.getEndIndex()); 525 for(char c = iter.first(); c != '\uFFFF'; c = iter.next()) 526 { 527 if(iter.getIndex() == iter.getRunStart()) 528 { 529 if(stringbuffer.length() > 0) 530 { 531 drawString(stringbuffer.toString(), x, y); 532 FontMetrics fontmetrics = getFontMetrics(); 533 x = (float)(x + fontmetrics.getStringBounds(stringbuffer.toString(), this).getWidth()); 534 stringbuffer.delete(0, stringbuffer.length()); 535 } 536 doAttributes(iter); 537 } 538 stringbuffer.append(c); 539 } 540 541 drawString(stringbuffer.toString(), x, y); 542 underline = false; 543 } 544 545 /** 546 * @see Graphics2D#drawGlyphVector(GlyphVector, float, float) 547 */ drawGlyphVector(GlyphVector g, float x, float y)548 public void drawGlyphVector(GlyphVector g, float x, float y) { 549 Shape s = g.getOutline(x, y); 550 fill(s); 551 } 552 553 /** 554 * @see Graphics2D#fill(Shape) 555 */ fill(Shape s)556 public void fill(Shape s) { 557 followPath(s, FILL); 558 } 559 560 /** 561 * @see Graphics2D#hit(Rectangle, Shape, boolean) 562 */ hit(Rectangle rect, Shape s, boolean onStroke)563 public boolean hit(Rectangle rect, Shape s, boolean onStroke) { 564 if (onStroke) { 565 s = stroke.createStrokedShape(s); 566 } 567 s = transform.createTransformedShape(s); 568 Area area = new Area(s); 569 if (clip != null) 570 area.intersect(clip); 571 return area.intersects(rect.x, rect.y, rect.width, rect.height); 572 } 573 574 /** 575 * @see Graphics2D#getDeviceConfiguration() 576 */ getDeviceConfiguration()577 public GraphicsConfiguration getDeviceConfiguration() { 578 return dg2.getDeviceConfiguration(); 579 } 580 581 /** 582 * Method contributed by Alexej Suchov 583 * @see Graphics2D#setComposite(Composite) 584 */ setComposite(Composite comp)585 public void setComposite(Composite comp) { 586 587 if (comp instanceof AlphaComposite) { 588 589 AlphaComposite composite = (AlphaComposite) comp; 590 591 if (composite.getRule() == 3) { 592 593 alpha = composite.getAlpha(); 594 this.composite = composite; 595 596 if (realPaint != null && (realPaint instanceof Color)) { 597 598 Color c = (Color) realPaint; 599 paint = new Color(c.getRed(), c.getGreen(), c.getBlue(), 600 (int) (c.getAlpha() * alpha)); 601 } 602 return; 603 } 604 } 605 606 this.composite = comp; 607 alpha = 1.0F; 608 609 } 610 611 /** 612 * Method contributed by Alexej Suchov 613 * @see Graphics2D#setPaint(Paint) 614 */ setPaint(Paint paint)615 public void setPaint(Paint paint) { 616 if (paint == null) 617 return; 618 this.paint = paint; 619 realPaint = paint; 620 621 if ((composite instanceof AlphaComposite) && (paint instanceof Color)) { 622 623 AlphaComposite co = (AlphaComposite) composite; 624 625 if (co.getRule() == 3) { 626 Color c = (Color) paint; 627 this.paint = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int) (c.getAlpha() * alpha)); 628 realPaint = paint; 629 } 630 } 631 632 } 633 transformStroke(Stroke stroke)634 private Stroke transformStroke(Stroke stroke) { 635 if (!(stroke instanceof BasicStroke)) 636 return stroke; 637 BasicStroke st = (BasicStroke)stroke; 638 float scale = (float)Math.sqrt(Math.abs(transform.getDeterminant())); 639 float dash[] = st.getDashArray(); 640 if (dash != null) { 641 for (int k = 0; k < dash.length; ++k) 642 dash[k] *= scale; 643 } 644 return new BasicStroke(st.getLineWidth() * scale, st.getEndCap(), st.getLineJoin(), st.getMiterLimit(), dash, st.getDashPhase() * scale); 645 } 646 setStrokeDiff(Stroke newStroke, Stroke oldStroke)647 private void setStrokeDiff(Stroke newStroke, Stroke oldStroke) { 648 if (newStroke == oldStroke) 649 return; 650 if (!(newStroke instanceof BasicStroke)) 651 return; 652 BasicStroke nStroke = (BasicStroke)newStroke; 653 boolean oldOk = (oldStroke instanceof BasicStroke); 654 BasicStroke oStroke = null; 655 if (oldOk) 656 oStroke = (BasicStroke)oldStroke; 657 if (!oldOk || nStroke.getLineWidth() != oStroke.getLineWidth()) 658 cb.setLineWidth(nStroke.getLineWidth()); 659 if (!oldOk || nStroke.getEndCap() != oStroke.getEndCap()) { 660 switch (nStroke.getEndCap()) { 661 case BasicStroke.CAP_BUTT: 662 cb.setLineCap(0); 663 break; 664 case BasicStroke.CAP_SQUARE: 665 cb.setLineCap(2); 666 break; 667 default: 668 cb.setLineCap(1); 669 } 670 } 671 if (!oldOk || nStroke.getLineJoin() != oStroke.getLineJoin()) { 672 switch (nStroke.getLineJoin()) { 673 case BasicStroke.JOIN_MITER: 674 cb.setLineJoin(0); 675 break; 676 case BasicStroke.JOIN_BEVEL: 677 cb.setLineJoin(2); 678 break; 679 default: 680 cb.setLineJoin(1); 681 } 682 } 683 if (!oldOk || nStroke.getMiterLimit() != oStroke.getMiterLimit()) 684 cb.setMiterLimit(nStroke.getMiterLimit()); 685 boolean makeDash; 686 if (oldOk) { 687 if (nStroke.getDashArray() != null) { 688 if (nStroke.getDashPhase() != oStroke.getDashPhase()) { 689 makeDash = true; 690 } 691 else if (!java.util.Arrays.equals(nStroke.getDashArray(), oStroke.getDashArray())) { 692 makeDash = true; 693 } 694 else 695 makeDash = false; 696 } 697 else if (oStroke.getDashArray() != null) { 698 makeDash = true; 699 } 700 else 701 makeDash = false; 702 } 703 else { 704 makeDash = true; 705 } 706 if (makeDash) { 707 float dash[] = nStroke.getDashArray(); 708 if (dash == null) 709 cb.setLiteral("[]0 d\n"); 710 else { 711 cb.setLiteral('['); 712 int lim = dash.length; 713 for (int k = 0; k < lim; ++k) { 714 cb.setLiteral(dash[k]); 715 cb.setLiteral(' '); 716 } 717 cb.setLiteral(']'); 718 cb.setLiteral(nStroke.getDashPhase()); 719 cb.setLiteral(" d\n"); 720 } 721 } 722 } 723 724 /** 725 * @see Graphics2D#setStroke(Stroke) 726 */ setStroke(Stroke s)727 public void setStroke(Stroke s) { 728 originalStroke = s; 729 this.stroke = transformStroke(s); 730 } 731 732 733 /** 734 * Sets a rendering hint 735 * @param arg0 736 * @param arg1 737 */ setRenderingHint(Key arg0, Object arg1)738 public void setRenderingHint(Key arg0, Object arg1) { 739 if (arg1 != null) { 740 rhints.put(arg0, arg1); 741 } else { 742 if (arg0 instanceof HyperLinkKey) 743 { 744 rhints.put(arg0, HyperLinkKey.VALUE_HYPERLINKKEY_OFF); 745 } 746 else 747 { 748 rhints.remove(arg0); 749 } 750 } 751 } 752 753 /** 754 * @param arg0 a key 755 * @return the rendering hint 756 */ getRenderingHint(Key arg0)757 public Object getRenderingHint(Key arg0) { 758 return rhints.get(arg0); 759 } 760 761 /** 762 * @see Graphics2D#setRenderingHints(Map) 763 */ setRenderingHints(Map hints)764 public void setRenderingHints(Map hints) { 765 rhints.clear(); 766 rhints.putAll(hints); 767 } 768 769 /** 770 * @see Graphics2D#addRenderingHints(Map) 771 */ addRenderingHints(Map hints)772 public void addRenderingHints(Map hints) { 773 rhints.putAll(hints); 774 } 775 776 /** 777 * @see Graphics2D#getRenderingHints() 778 */ getRenderingHints()779 public RenderingHints getRenderingHints() { 780 return rhints; 781 } 782 783 /** 784 * @see Graphics#translate(int, int) 785 */ translate(int x, int y)786 public void translate(int x, int y) { 787 translate((double)x, (double)y); 788 } 789 790 /** 791 * @see Graphics2D#translate(double, double) 792 */ translate(double tx, double ty)793 public void translate(double tx, double ty) { 794 transform.translate(tx,ty); 795 } 796 797 /** 798 * @see Graphics2D#rotate(double) 799 */ rotate(double theta)800 public void rotate(double theta) { 801 transform.rotate(theta); 802 } 803 804 /** 805 * @see Graphics2D#rotate(double, double, double) 806 */ rotate(double theta, double x, double y)807 public void rotate(double theta, double x, double y) { 808 transform.rotate(theta, x, y); 809 } 810 811 /** 812 * @see Graphics2D#scale(double, double) 813 */ scale(double sx, double sy)814 public void scale(double sx, double sy) { 815 transform.scale(sx, sy); 816 this.stroke = transformStroke(originalStroke); 817 } 818 819 /** 820 * @see Graphics2D#shear(double, double) 821 */ shear(double shx, double shy)822 public void shear(double shx, double shy) { 823 transform.shear(shx, shy); 824 } 825 826 /** 827 * @see Graphics2D#transform(AffineTransform) 828 */ transform(AffineTransform tx)829 public void transform(AffineTransform tx) { 830 transform.concatenate(tx); 831 this.stroke = transformStroke(originalStroke); 832 } 833 834 /** 835 * @see Graphics2D#setTransform(AffineTransform) 836 */ setTransform(AffineTransform t)837 public void setTransform(AffineTransform t) { 838 transform = new AffineTransform(t); 839 this.stroke = transformStroke(originalStroke); 840 } 841 842 /** 843 * @see Graphics2D#getTransform() 844 */ getTransform()845 public AffineTransform getTransform() { 846 return new AffineTransform(transform); 847 } 848 849 /** 850 * Method contributed by Alexej Suchov 851 * @see Graphics2D#getPaint() 852 */ getPaint()853 public Paint getPaint() { 854 if (realPaint != null) { 855 return realPaint; 856 } else { 857 return paint; 858 } 859 } 860 861 /** 862 * @see Graphics2D#getComposite() 863 */ getComposite()864 public Composite getComposite() { 865 return composite; 866 } 867 868 /** 869 * @see Graphics2D#setBackground(Color) 870 */ setBackground(Color color)871 public void setBackground(Color color) { 872 background = color; 873 } 874 875 /** 876 * @see Graphics2D#getBackground() 877 */ getBackground()878 public Color getBackground() { 879 return background; 880 } 881 882 /** 883 * @see Graphics2D#getStroke() 884 */ getStroke()885 public Stroke getStroke() { 886 return originalStroke; 887 } 888 889 890 /** 891 * @see Graphics2D#getFontRenderContext() 892 */ getFontRenderContext()893 public FontRenderContext getFontRenderContext() { 894 boolean antialias = RenderingHints.VALUE_TEXT_ANTIALIAS_ON.equals(getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING)); 895 boolean fractions = RenderingHints.VALUE_FRACTIONALMETRICS_ON.equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS)); 896 return new FontRenderContext(new AffineTransform(), antialias, fractions); 897 } 898 899 /** 900 * @see Graphics#create() 901 */ create()902 public Graphics create() { 903 PdfGraphics2D g2 = new PdfGraphics2D(); 904 g2.rhints.putAll( this.rhints ); 905 g2.onlyShapes = this.onlyShapes; 906 g2.transform = new AffineTransform(this.transform); 907 g2.baseFonts = this.baseFonts; 908 g2.fontMapper = this.fontMapper; 909 g2.paint = this.paint; 910 g2.fillGState = this.fillGState; 911 g2.currentFillGState = this.currentFillGState; 912 g2.strokeGState = this.strokeGState; 913 g2.background = this.background; 914 g2.mediaTracker = this.mediaTracker; 915 g2.convertImagesToJPEG = this.convertImagesToJPEG; 916 g2.jpegQuality = this.jpegQuality; 917 g2.setFont(this.font); 918 g2.cb = this.cb.getDuplicate(); 919 g2.cb.saveState(); 920 g2.width = this.width; 921 g2.height = this.height; 922 g2.followPath(new Area(new Rectangle2D.Float(0, 0, width, height)), CLIP); 923 if (this.clip != null) 924 g2.clip = new Area(this.clip); 925 g2.composite = composite; 926 g2.stroke = stroke; 927 g2.originalStroke = originalStroke; 928 g2.strokeOne = (BasicStroke)g2.transformStroke(g2.strokeOne); 929 g2.oldStroke = g2.strokeOne; 930 g2.setStrokeDiff(g2.oldStroke, null); 931 g2.cb.saveState(); 932 if (g2.clip != null) 933 g2.followPath(g2.clip, CLIP); 934 g2.kid = true; 935 if (this.kids == null) 936 this.kids = new ArrayList(); 937 this.kids.add(new Integer(cb.getInternalBuffer().size())); 938 this.kids.add(g2); 939 return g2; 940 } 941 getContent()942 public PdfContentByte getContent() { 943 return this.cb; 944 } 945 /** 946 * @see Graphics#getColor() 947 */ getColor()948 public Color getColor() { 949 if (paint instanceof Color) { 950 return (Color)paint; 951 } else { 952 return Color.black; 953 } 954 } 955 956 /** 957 * @see Graphics#setColor(Color) 958 */ setColor(Color color)959 public void setColor(Color color) { 960 setPaint(color); 961 } 962 963 /** 964 * @see Graphics#setPaintMode() 965 */ setPaintMode()966 public void setPaintMode() {} 967 968 /** 969 * @see Graphics#setXORMode(Color) 970 */ setXORMode(Color c1)971 public void setXORMode(Color c1) { 972 973 } 974 975 /** 976 * @see Graphics#getFont() 977 */ getFont()978 public Font getFont() { 979 return font; 980 } 981 982 /** 983 * @see Graphics#setFont(Font) 984 */ 985 /** 986 * Sets the current font. 987 */ setFont(Font f)988 public void setFont(Font f) { 989 if (f == null) 990 return; 991 if (onlyShapes) { 992 font = f; 993 return; 994 } 995 if (f == font) 996 return; 997 font = f; 998 fontSize = f.getSize2D(); 999 baseFont = getCachedBaseFont(f); 1000 } 1001 getCachedBaseFont(Font f)1002 private BaseFont getCachedBaseFont(Font f) { 1003 synchronized (baseFonts) { 1004 BaseFont bf = (BaseFont)baseFonts.get(f.getFontName()); 1005 if (bf == null) { 1006 bf = fontMapper.awtToPdf(f); 1007 baseFonts.put(f.getFontName(), bf); 1008 } 1009 return bf; 1010 } 1011 } 1012 1013 /** 1014 * @see Graphics#getFontMetrics(Font) 1015 */ getFontMetrics(Font f)1016 public FontMetrics getFontMetrics(Font f) { 1017 return dg2.getFontMetrics(f); 1018 } 1019 1020 /** 1021 * @see Graphics#getClipBounds() 1022 */ getClipBounds()1023 public Rectangle getClipBounds() { 1024 if (clip == null) 1025 return null; 1026 return getClip().getBounds(); 1027 } 1028 1029 /** 1030 * @see Graphics#clipRect(int, int, int, int) 1031 */ clipRect(int x, int y, int width, int height)1032 public void clipRect(int x, int y, int width, int height) { 1033 Rectangle2D rect = new Rectangle2D.Double(x,y,width,height); 1034 clip(rect); 1035 } 1036 1037 /** 1038 * @see Graphics#setClip(int, int, int, int) 1039 */ setClip(int x, int y, int width, int height)1040 public void setClip(int x, int y, int width, int height) { 1041 Rectangle2D rect = new Rectangle2D.Double(x,y,width,height); 1042 setClip(rect); 1043 } 1044 1045 /** 1046 * @see Graphics2D#clip(Shape) 1047 */ clip(Shape s)1048 public void clip(Shape s) { 1049 if (s == null) { 1050 setClip(null); 1051 return; 1052 } 1053 s = transform.createTransformedShape(s); 1054 if (clip == null) 1055 clip = new Area(s); 1056 else 1057 clip.intersect(new Area(s)); 1058 followPath(s, CLIP); 1059 } 1060 1061 /** 1062 * @see Graphics#getClip() 1063 */ getClip()1064 public Shape getClip() { 1065 try { 1066 return transform.createInverse().createTransformedShape(clip); 1067 } 1068 catch (NoninvertibleTransformException e) { 1069 return null; 1070 } 1071 } 1072 1073 /** 1074 * @see Graphics#setClip(Shape) 1075 */ setClip(Shape s)1076 public void setClip(Shape s) { 1077 cb.restoreState(); 1078 cb.saveState(); 1079 if (s != null) 1080 s = transform.createTransformedShape(s); 1081 if (s == null) { 1082 clip = null; 1083 } 1084 else { 1085 clip = new Area(s); 1086 followPath(s, CLIP); 1087 } 1088 paintFill = paintStroke = null; 1089 currentFillGState = currentStrokeGState = 255; 1090 oldStroke = strokeOne; 1091 } 1092 1093 /** 1094 * @see Graphics#copyArea(int, int, int, int, int, int) 1095 */ copyArea(int x, int y, int width, int height, int dx, int dy)1096 public void copyArea(int x, int y, int width, int height, int dx, int dy) { 1097 1098 } 1099 1100 /** 1101 * @see Graphics#drawLine(int, int, int, int) 1102 */ drawLine(int x1, int y1, int x2, int y2)1103 public void drawLine(int x1, int y1, int x2, int y2) { 1104 Line2D line = new Line2D.Double(x1, y1, x2, y2); 1105 draw(line); 1106 } 1107 1108 /** 1109 * @see Graphics#fillRect(int, int, int, int) 1110 */ drawRect(int x, int y, int width, int height)1111 public void drawRect(int x, int y, int width, int height) { 1112 draw(new Rectangle(x, y, width, height)); 1113 } 1114 1115 /** 1116 * @see Graphics#fillRect(int, int, int, int) 1117 */ fillRect(int x, int y, int width, int height)1118 public void fillRect(int x, int y, int width, int height) { 1119 fill(new Rectangle(x,y,width,height)); 1120 } 1121 1122 /** 1123 * @see Graphics#clearRect(int, int, int, int) 1124 */ clearRect(int x, int y, int width, int height)1125 public void clearRect(int x, int y, int width, int height) { 1126 Paint temp = paint; 1127 setPaint(background); 1128 fillRect(x,y,width,height); 1129 setPaint(temp); 1130 } 1131 1132 /** 1133 * @see Graphics#drawRoundRect(int, int, int, int, int, int) 1134 */ drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)1135 public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { 1136 RoundRectangle2D rect = new RoundRectangle2D.Double(x,y,width,height,arcWidth, arcHeight); 1137 draw(rect); 1138 } 1139 1140 /** 1141 * @see Graphics#fillRoundRect(int, int, int, int, int, int) 1142 */ fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)1143 public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { 1144 RoundRectangle2D rect = new RoundRectangle2D.Double(x,y,width,height,arcWidth, arcHeight); 1145 fill(rect); 1146 } 1147 1148 /** 1149 * @see Graphics#drawOval(int, int, int, int) 1150 */ drawOval(int x, int y, int width, int height)1151 public void drawOval(int x, int y, int width, int height) { 1152 Ellipse2D oval = new Ellipse2D.Float(x, y, width, height); 1153 draw(oval); 1154 } 1155 1156 /** 1157 * @see Graphics#fillOval(int, int, int, int) 1158 */ fillOval(int x, int y, int width, int height)1159 public void fillOval(int x, int y, int width, int height) { 1160 Ellipse2D oval = new Ellipse2D.Float(x, y, width, height); 1161 fill(oval); 1162 } 1163 1164 /** 1165 * @see Graphics#drawArc(int, int, int, int, int, int) 1166 */ drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)1167 public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { 1168 Arc2D arc = new Arc2D.Double(x,y,width,height,startAngle, arcAngle, Arc2D.OPEN); 1169 draw(arc); 1170 1171 } 1172 1173 /** 1174 * @see Graphics#fillArc(int, int, int, int, int, int) 1175 */ fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)1176 public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { 1177 Arc2D arc = new Arc2D.Double(x,y,width,height,startAngle, arcAngle, Arc2D.PIE); 1178 fill(arc); 1179 } 1180 1181 /** 1182 * @see Graphics#drawPolyline(int[], int[], int) 1183 */ drawPolyline(int[] x, int[] y, int nPoints)1184 public void drawPolyline(int[] x, int[] y, int nPoints) { 1185 PolylineShape polyline = new PolylineShape(x, y, nPoints); 1186 draw(polyline); 1187 } 1188 1189 /** 1190 * @see Graphics#drawPolygon(int[], int[], int) 1191 */ drawPolygon(int[] xPoints, int[] yPoints, int nPoints)1192 public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { 1193 Polygon poly = new Polygon(xPoints, yPoints, nPoints); 1194 draw(poly); 1195 } 1196 1197 /** 1198 * @see Graphics#fillPolygon(int[], int[], int) 1199 */ fillPolygon(int[] xPoints, int[] yPoints, int nPoints)1200 public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { 1201 Polygon poly = new Polygon(); 1202 for (int i = 0; i < nPoints; i++) { 1203 poly.addPoint(xPoints[i], yPoints[i]); 1204 } 1205 fill(poly); 1206 } 1207 1208 /** 1209 * @see Graphics#drawImage(Image, int, int, ImageObserver) 1210 */ drawImage(Image img, int x, int y, ImageObserver observer)1211 public boolean drawImage(Image img, int x, int y, ImageObserver observer) { 1212 return drawImage(img, x, y, null, observer); 1213 } 1214 1215 /** 1216 * @see Graphics#drawImage(Image, int, int, int, int, ImageObserver) 1217 */ drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)1218 public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { 1219 return drawImage(img, x, y, width, height, null, observer); 1220 } 1221 1222 /** 1223 * @see Graphics#drawImage(Image, int, int, Color, ImageObserver) 1224 */ drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer)1225 public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { 1226 waitForImage(img); 1227 return drawImage(img, x, y, img.getWidth(observer), img.getHeight(observer), bgcolor, observer); 1228 } 1229 1230 /** 1231 * @see Graphics#drawImage(Image, int, int, int, int, Color, ImageObserver) 1232 */ drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)1233 public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { 1234 waitForImage(img); 1235 double scalex = width/(double)img.getWidth(observer); 1236 double scaley = height/(double)img.getHeight(observer); 1237 AffineTransform tx = AffineTransform.getTranslateInstance(x,y); 1238 tx.scale(scalex,scaley); 1239 return drawImage(img, null, tx, bgcolor, observer); 1240 } 1241 1242 /** 1243 * @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int, ImageObserver) 1244 */ drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)1245 public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { 1246 return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); 1247 } 1248 1249 /** 1250 * @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int, Color, ImageObserver) 1251 */ drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer)1252 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) { 1253 waitForImage(img); 1254 double dwidth = (double)dx2-dx1; 1255 double dheight = (double)dy2-dy1; 1256 double swidth = (double)sx2-sx1; 1257 double sheight = (double)sy2-sy1; 1258 1259 //if either width or height is 0, then there is nothing to draw 1260 if (dwidth == 0 || dheight == 0 || swidth == 0 || sheight == 0) return true; 1261 1262 double scalex = dwidth/swidth; 1263 double scaley = dheight/sheight; 1264 1265 double transx = sx1*scalex; 1266 double transy = sy1*scaley; 1267 AffineTransform tx = AffineTransform.getTranslateInstance(dx1-transx,dy1-transy); 1268 tx.scale(scalex,scaley); 1269 1270 BufferedImage mask = new BufferedImage(img.getWidth(observer), img.getHeight(observer), BufferedImage.TYPE_BYTE_BINARY); 1271 Graphics g = mask.getGraphics(); 1272 g.fillRect(sx1,sy1, (int)swidth, (int)sheight); 1273 drawImage(img, mask, tx, null, observer); 1274 g.dispose(); 1275 return true; 1276 } 1277 1278 /** 1279 * @see Graphics#dispose() 1280 */ dispose()1281 public void dispose() { 1282 if (kid) 1283 return; 1284 if (!disposeCalled) { 1285 disposeCalled = true; 1286 cb.restoreState(); 1287 cb.restoreState(); 1288 dg2.dispose(); 1289 dg2 = null; 1290 if (kids != null) { 1291 ByteBuffer buf = new ByteBuffer(); 1292 internalDispose(buf); 1293 ByteBuffer buf2 = cb.getInternalBuffer(); 1294 buf2.reset(); 1295 buf2.append(buf); 1296 } 1297 } 1298 } 1299 internalDispose(ByteBuffer buf)1300 private void internalDispose(ByteBuffer buf) { 1301 int last = 0; 1302 int pos = 0; 1303 ByteBuffer buf2 = cb.getInternalBuffer(); 1304 if (kids != null) { 1305 for (int k = 0; k < kids.size(); k += 2) { 1306 pos = ((Integer)kids.get(k)).intValue(); 1307 PdfGraphics2D g2 = (PdfGraphics2D)kids.get(k + 1); 1308 g2.cb.restoreState(); 1309 g2.cb.restoreState(); 1310 buf.append(buf2.getBuffer(), last, pos - last); 1311 g2.dg2.dispose(); 1312 g2.dg2 = null; 1313 g2.internalDispose(buf); 1314 last = pos; 1315 } 1316 } 1317 buf.append(buf2.getBuffer(), last, buf2.size() - last); 1318 } 1319 1320 /////////////////////////////////////////////// 1321 // 1322 // 1323 // implementation specific methods 1324 // 1325 // 1326 1327 followPath(Shape s, int drawType)1328 private void followPath(Shape s, int drawType) { 1329 if (s==null) return; 1330 if (drawType==STROKE) { 1331 if (!(stroke instanceof BasicStroke)) { 1332 s = stroke.createStrokedShape(s); 1333 followPath(s, FILL); 1334 return; 1335 } 1336 } 1337 if (drawType==STROKE) { 1338 setStrokeDiff(stroke, oldStroke); 1339 oldStroke = stroke; 1340 setStrokePaint(); 1341 } 1342 else if (drawType==FILL) 1343 setFillPaint(); 1344 PathIterator points; 1345 int traces = 0; 1346 if (drawType == CLIP) 1347 points = s.getPathIterator(IDENTITY); 1348 else 1349 points = s.getPathIterator(transform); 1350 float[] coords = new float[6]; 1351 while(!points.isDone()) { 1352 ++traces; 1353 int segtype = points.currentSegment(coords); 1354 normalizeY(coords); 1355 switch(segtype) { 1356 case PathIterator.SEG_CLOSE: 1357 cb.closePath(); 1358 break; 1359 1360 case PathIterator.SEG_CUBICTO: 1361 cb.curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); 1362 break; 1363 1364 case PathIterator.SEG_LINETO: 1365 cb.lineTo(coords[0], coords[1]); 1366 break; 1367 1368 case PathIterator.SEG_MOVETO: 1369 cb.moveTo(coords[0], coords[1]); 1370 break; 1371 1372 case PathIterator.SEG_QUADTO: 1373 cb.curveTo(coords[0], coords[1], coords[2], coords[3]); 1374 break; 1375 } 1376 points.next(); 1377 } 1378 switch (drawType) { 1379 case FILL: 1380 if (traces > 0) { 1381 if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) 1382 cb.eoFill(); 1383 else 1384 cb.fill(); 1385 } 1386 break; 1387 case STROKE: 1388 if (traces > 0) 1389 cb.stroke(); 1390 break; 1391 default: //drawType==CLIP 1392 if (traces == 0) 1393 cb.rectangle(0, 0, 0, 0); 1394 if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD) 1395 cb.eoClip(); 1396 else 1397 cb.clip(); 1398 cb.newPath(); 1399 } 1400 } 1401 normalizeY(float y)1402 private float normalizeY(float y) { 1403 return this.height - y; 1404 } 1405 normalizeY(float[] coords)1406 private void normalizeY(float[] coords) { 1407 coords[1] = normalizeY(coords[1]); 1408 coords[3] = normalizeY(coords[3]); 1409 coords[5] = normalizeY(coords[5]); 1410 } 1411 normalizeMatrix()1412 private AffineTransform normalizeMatrix() { 1413 double[] mx = new double[6]; 1414 AffineTransform result = AffineTransform.getTranslateInstance(0,0); 1415 result.getMatrix(mx); 1416 mx[3]=-1; 1417 mx[5]=height; 1418 result = new AffineTransform(mx); 1419 result.concatenate(transform); 1420 return result; 1421 } 1422 drawImage(Image img, Image mask, AffineTransform xform, Color bgColor, ImageObserver obs)1423 private boolean drawImage(Image img, Image mask, AffineTransform xform, Color bgColor, ImageObserver obs) { 1424 if (xform==null) 1425 xform = new AffineTransform(); 1426 else 1427 xform = new AffineTransform(xform); 1428 xform.translate(0, img.getHeight(obs)); 1429 xform.scale(img.getWidth(obs), img.getHeight(obs)); 1430 1431 AffineTransform inverse = this.normalizeMatrix(); 1432 AffineTransform flipper = AffineTransform.getScaleInstance(1,-1); 1433 inverse.concatenate(xform); 1434 inverse.concatenate(flipper); 1435 1436 double[] mx = new double[6]; 1437 inverse.getMatrix(mx); 1438 if (currentFillGState != 255) { 1439 PdfGState gs = fillGState[255]; 1440 if (gs == null) { 1441 gs = new PdfGState(); 1442 gs.setFillOpacity(1); 1443 fillGState[255] = gs; 1444 } 1445 cb.setGState(gs); 1446 } 1447 1448 try { 1449 com.lowagie.text.Image image = null; 1450 if(!convertImagesToJPEG){ 1451 image = com.lowagie.text.Image.getInstance(img, bgColor); 1452 } 1453 else{ 1454 BufferedImage scaled = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB); 1455 Graphics2D g3 = scaled.createGraphics(); 1456 g3.drawImage(img, 0, 0, img.getWidth(null), img.getHeight(null), null); 1457 g3.dispose(); 1458 1459 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1460 ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault()); 1461 iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 1462 iwparam.setCompressionQuality(jpegQuality);//Set here your compression rate 1463 ImageWriter iw = (ImageWriter)ImageIO.getImageWritersByFormatName("jpg").next(); 1464 ImageOutputStream ios = ImageIO.createImageOutputStream(baos); 1465 iw.setOutput(ios); 1466 iw.write(null, new IIOImage(scaled, null, null), iwparam); 1467 iw.dispose(); 1468 ios.close(); 1469 1470 scaled.flush(); 1471 scaled = null; 1472 image = com.lowagie.text.Image.getInstance(baos.toByteArray()); 1473 1474 } 1475 if (mask!=null) { 1476 com.lowagie.text.Image msk = com.lowagie.text.Image.getInstance(mask, null, true); 1477 msk.makeMask(); 1478 msk.setInverted(true); 1479 image.setImageMask(msk); 1480 } 1481 cb.addImage(image, (float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]); 1482 Object url = getRenderingHint(HyperLinkKey.KEY_INSTANCE); 1483 if (url != null && !url.equals(HyperLinkKey.VALUE_HYPERLINKKEY_OFF)) { 1484 PdfAction action = new PdfAction(url.toString()); 1485 cb.setAction(action, (float)mx[4], (float)mx[5], (float)(mx[0]+mx[4]), (float)(mx[3]+mx[5])); 1486 } 1487 } catch (Exception ex) { 1488 throw new IllegalArgumentException(); 1489 } 1490 if (currentFillGState != 255) { 1491 PdfGState gs = fillGState[currentFillGState]; 1492 cb.setGState(gs); 1493 } 1494 return true; 1495 } 1496 checkNewPaint(Paint oldPaint)1497 private boolean checkNewPaint(Paint oldPaint) { 1498 if (paint == oldPaint) 1499 return false; 1500 return !((paint instanceof Color) && paint.equals(oldPaint)); 1501 } 1502 setFillPaint()1503 private void setFillPaint() { 1504 if (checkNewPaint(paintFill)) { 1505 paintFill = paint; 1506 setPaint(false, 0, 0, true); 1507 } 1508 } 1509 setStrokePaint()1510 private void setStrokePaint() { 1511 if (checkNewPaint(paintStroke)) { 1512 paintStroke = paint; 1513 setPaint(false, 0, 0, false); 1514 } 1515 } 1516 setPaint(boolean invert, double xoffset, double yoffset, boolean fill)1517 private void setPaint(boolean invert, double xoffset, double yoffset, boolean fill) { 1518 if (paint instanceof Color) { 1519 Color color = (Color)paint; 1520 int alpha = color.getAlpha(); 1521 if (fill) { 1522 if (alpha != currentFillGState) { 1523 currentFillGState = alpha; 1524 PdfGState gs = fillGState[alpha]; 1525 if (gs == null) { 1526 gs = new PdfGState(); 1527 gs.setFillOpacity(alpha / 255f); 1528 fillGState[alpha] = gs; 1529 } 1530 cb.setGState(gs); 1531 } 1532 cb.setColorFill(color); 1533 } 1534 else { 1535 if (alpha != currentStrokeGState) { 1536 currentStrokeGState = alpha; 1537 PdfGState gs = strokeGState[alpha]; 1538 if (gs == null) { 1539 gs = new PdfGState(); 1540 gs.setStrokeOpacity(alpha / 255f); 1541 strokeGState[alpha] = gs; 1542 } 1543 cb.setGState(gs); 1544 } 1545 cb.setColorStroke(color); 1546 } 1547 } 1548 else if (paint instanceof GradientPaint) { 1549 GradientPaint gp = (GradientPaint)paint; 1550 Point2D p1 = gp.getPoint1(); 1551 transform.transform(p1, p1); 1552 Point2D p2 = gp.getPoint2(); 1553 transform.transform(p2, p2); 1554 Color c1 = gp.getColor1(); 1555 Color c2 = gp.getColor2(); 1556 PdfShading shading = PdfShading.simpleAxial(cb.getPdfWriter(), (float)p1.getX(), normalizeY((float)p1.getY()), (float)p2.getX(), normalizeY((float)p2.getY()), c1, c2); 1557 PdfShadingPattern pat = new PdfShadingPattern(shading); 1558 if (fill) 1559 cb.setShadingFill(pat); 1560 else 1561 cb.setShadingStroke(pat); 1562 } 1563 else if (paint instanceof TexturePaint) { 1564 try { 1565 TexturePaint tp = (TexturePaint)paint; 1566 BufferedImage img = tp.getImage(); 1567 Rectangle2D rect = tp.getAnchorRect(); 1568 com.lowagie.text.Image image = com.lowagie.text.Image.getInstance(img, null); 1569 PdfPatternPainter pattern = cb.createPattern(image.getWidth(), image.getHeight()); 1570 AffineTransform inverse = this.normalizeMatrix(); 1571 inverse.translate(rect.getX(), rect.getY()); 1572 inverse.scale(rect.getWidth() / image.getWidth(), -rect.getHeight() / image.getHeight()); 1573 double[] mx = new double[6]; 1574 inverse.getMatrix(mx); 1575 pattern.setPatternMatrix((float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]) ; 1576 image.setAbsolutePosition(0,0); 1577 pattern.addImage(image); 1578 if (fill) 1579 cb.setPatternFill(pattern); 1580 else 1581 cb.setPatternStroke(pattern); 1582 } catch (Exception ex) { 1583 if (fill) 1584 cb.setColorFill(Color.gray); 1585 else 1586 cb.setColorStroke(Color.gray); 1587 } 1588 } 1589 else { 1590 try { 1591 BufferedImage img = null; 1592 int type = BufferedImage.TYPE_4BYTE_ABGR; 1593 if (paint.getTransparency() == Transparency.OPAQUE) { 1594 type = BufferedImage.TYPE_3BYTE_BGR; 1595 } 1596 img = new BufferedImage((int)width, (int)height, type); 1597 Graphics2D g = (Graphics2D)img.getGraphics(); 1598 g.transform(transform); 1599 AffineTransform inv = transform.createInverse(); 1600 Shape fillRect = new Rectangle2D.Double(0,0,img.getWidth(),img.getHeight()); 1601 fillRect = inv.createTransformedShape(fillRect); 1602 g.setPaint(paint); 1603 g.fill(fillRect); 1604 if (invert) { 1605 AffineTransform tx = new AffineTransform(); 1606 tx.scale(1,-1); 1607 tx.translate(-xoffset,-yoffset); 1608 g.drawImage(img,tx,null); 1609 } 1610 g.dispose(); 1611 g = null; 1612 com.lowagie.text.Image image = com.lowagie.text.Image.getInstance(img, null); 1613 PdfPatternPainter pattern = cb.createPattern(width, height); 1614 image.setAbsolutePosition(0,0); 1615 pattern.addImage(image); 1616 if (fill) 1617 cb.setPatternFill(pattern); 1618 else 1619 cb.setPatternStroke(pattern); 1620 } catch (Exception ex) { 1621 if (fill) 1622 cb.setColorFill(Color.gray); 1623 else 1624 cb.setColorStroke(Color.gray); 1625 } 1626 } 1627 } 1628 waitForImage(java.awt.Image image)1629 private synchronized void waitForImage(java.awt.Image image) { 1630 if (mediaTracker == null) 1631 mediaTracker = new MediaTracker(new PdfGraphics2D.FakeComponent()); 1632 mediaTracker.addImage(image, 0); 1633 try { 1634 mediaTracker.waitForID(0); 1635 } 1636 catch (InterruptedException e) { 1637 // empty on purpose 1638 } 1639 mediaTracker.removeImage(image); 1640 } 1641 1642 static private class FakeComponent extends Component { 1643 1644 private static final long serialVersionUID = 6450197945596086638L; 1645 } 1646 1647 /** 1648 * @since 2.0.8 1649 */ 1650 public static class HyperLinkKey extends RenderingHints.Key 1651 { 1652 public static final HyperLinkKey KEY_INSTANCE = new HyperLinkKey(9999); 1653 public static final Object VALUE_HYPERLINKKEY_OFF = "0"; 1654 HyperLinkKey(int arg0)1655 protected HyperLinkKey(int arg0) { 1656 super(arg0); 1657 } 1658 isCompatibleValue(Object val)1659 public boolean isCompatibleValue(Object val) 1660 { 1661 return true; 1662 } toString()1663 public String toString() 1664 { 1665 return "HyperLinkKey"; 1666 } 1667 } 1668 1669 } 1670