0001: /*
0002: * $Id: PdfGraphics2D.java 2912 2007-09-06 10:30:41Z psoares33 $
0003: *
0004: * Copyright 2002 by Jim Moore <jim@scolamoore.com>.
0005: *
0006: * The contents of this file are subject to the Mozilla Public License Version 1.1
0007: * (the "License"); you may not use this file except in compliance with the License.
0008: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0009: *
0010: * Software distributed under the License is distributed on an "AS IS" basis,
0011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012: * for the specific language governing rights and limitations under the License.
0013: *
0014: * The Original Code is 'iText, a free JAVA-PDF library'.
0015: *
0016: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0017: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0018: * All Rights Reserved.
0019: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0020: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0021: *
0022: * Contributor(s): all the names of the contributors are added in the source code
0023: * where applicable.
0024: *
0025: * Alternatively, the contents of this file may be used under the terms of the
0026: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0027: * provisions of LGPL are applicable instead of those above. If you wish to
0028: * allow use of your version of this file only under the terms of the LGPL
0029: * License and not to allow others to use your version of this file under
0030: * the MPL, indicate your decision by deleting the provisions above and
0031: * replace them with the notice and other provisions required by the LGPL.
0032: * If you do not delete the provisions above, a recipient may use your version
0033: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0034: *
0035: * This library is free software; you can redistribute it and/or modify it
0036: * under the terms of the MPL as stated above or under the terms of the GNU
0037: * Library General Public License as published by the Free Software Foundation;
0038: * either version 2 of the License, or any later version.
0039: *
0040: * This library is distributed in the hope that it will be useful, but WITHOUT
0041: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0042: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0043: * details.
0044: *
0045: * If you didn't download this code from the following link, you should check if
0046: * you aren't using an obsolete version:
0047: * http://www.lowagie.com/iText/
0048: */
0049:
0050: package com.lowagie.text.pdf;
0051:
0052: import java.awt.AlphaComposite;
0053: import java.awt.BasicStroke;
0054: import java.awt.Color;
0055: import java.awt.Component;
0056: import java.awt.Composite;
0057: import java.awt.Font;
0058: import java.awt.FontMetrics;
0059: import java.awt.GradientPaint;
0060: import java.awt.Graphics;
0061: import java.awt.Graphics2D;
0062: import java.awt.GraphicsConfiguration;
0063: import java.awt.Image;
0064: import java.awt.MediaTracker;
0065: import java.awt.Paint;
0066: import java.awt.Polygon;
0067: import java.awt.Rectangle;
0068: import java.awt.RenderingHints;
0069: import java.awt.Shape;
0070: import java.awt.Stroke;
0071: import java.awt.TexturePaint;
0072: import java.awt.Transparency;
0073: import java.awt.RenderingHints.Key;
0074: import java.awt.font.FontRenderContext;
0075: import java.awt.font.GlyphVector;
0076: import java.awt.font.TextAttribute;
0077: import java.awt.geom.AffineTransform;
0078: import java.awt.geom.Arc2D;
0079: import java.awt.geom.Area;
0080: import java.awt.geom.Ellipse2D;
0081: import java.awt.geom.Line2D;
0082: import java.awt.geom.NoninvertibleTransformException;
0083: import java.awt.geom.PathIterator;
0084: import java.awt.geom.Point2D;
0085: import java.awt.geom.Rectangle2D;
0086: import java.awt.geom.RoundRectangle2D;
0087: import java.awt.image.BufferedImage;
0088: import java.awt.image.BufferedImageOp;
0089: import java.awt.image.ColorModel;
0090: import java.awt.image.ImageObserver;
0091: import java.awt.image.RenderedImage;
0092: import java.awt.image.WritableRaster;
0093: import java.awt.image.renderable.RenderableImage;
0094: import java.io.ByteArrayOutputStream;
0095: import java.text.AttributedCharacterIterator;
0096: import java.util.ArrayList;
0097: import java.util.HashMap;
0098: import java.util.Hashtable;
0099: import java.util.Iterator;
0100: import java.util.Map;
0101: import java.util.Set;
0102:
0103: import com.lowagie.text.pdf.internal.PolylineShape;
0104: import java.util.Locale;
0105: import javax.imageio.IIOImage;
0106: import javax.imageio.ImageIO;
0107: import javax.imageio.ImageWriteParam;
0108: import javax.imageio.ImageWriter;
0109: import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
0110: import javax.imageio.stream.ImageOutputStream;
0111:
0112: public class PdfGraphics2D extends Graphics2D {
0113:
0114: private static final int FILL = 1;
0115: private static final int STROKE = 2;
0116: private static final int CLIP = 3;
0117: private BasicStroke strokeOne = new BasicStroke(1);
0118:
0119: private static final AffineTransform IDENTITY = new AffineTransform();
0120:
0121: private Font font;
0122: private BaseFont baseFont;
0123: private float fontSize;
0124: private AffineTransform transform;
0125: private Paint paint;
0126: private Color background;
0127: private float width;
0128: private float height;
0129:
0130: private Area clip;
0131:
0132: private RenderingHints rhints = new RenderingHints(null);
0133:
0134: private Stroke stroke;
0135: private Stroke originalStroke;
0136:
0137: private PdfContentByte cb;
0138:
0139: /** Storage for BaseFont objects created. */
0140: private HashMap baseFonts;
0141:
0142: private boolean disposeCalled = false;
0143:
0144: private FontMapper fontMapper;
0145:
0146: private ArrayList kids;
0147:
0148: private boolean kid = false;
0149:
0150: private Graphics2D dg2 = new BufferedImage(2, 2,
0151: BufferedImage.TYPE_INT_RGB).createGraphics();
0152:
0153: private boolean onlyShapes = false;
0154:
0155: private Stroke oldStroke;
0156: private Paint paintFill;
0157: private Paint paintStroke;
0158:
0159: private MediaTracker mediaTracker;
0160:
0161: // Added by Jurij Bilas
0162: protected boolean underline; // indicates if the font style is underlined
0163:
0164: protected PdfGState fillGState[] = new PdfGState[256];
0165: protected PdfGState strokeGState[] = new PdfGState[256];
0166: protected int currentFillGState = 255;
0167: protected int currentStrokeGState = 255;
0168:
0169: public static final int AFM_DIVISOR = 1000; // used to calculate coordinates
0170:
0171: private boolean convertImagesToJPEG = false;
0172: private float jpegQuality = .95f;
0173:
0174: // Added by Alexej Suchov
0175: private float alpha;
0176:
0177: // Added by Alexej Suchov
0178: private Composite composite;
0179:
0180: // Added by Alexej Suchov
0181: private Paint realPaint;
0182:
0183: private PdfGraphics2D() {
0184: dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
0185: RenderingHints.VALUE_FRACTIONALMETRICS_ON);
0186: setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
0187: RenderingHints.VALUE_FRACTIONALMETRICS_ON);
0188: }
0189:
0190: /**
0191: * Constructor for PDFGraphics2D.
0192: *
0193: */
0194: PdfGraphics2D(PdfContentByte cb, float width, float height,
0195: FontMapper fontMapper, boolean onlyShapes,
0196: boolean convertImagesToJPEG, float quality) {
0197: super ();
0198: dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
0199: RenderingHints.VALUE_FRACTIONALMETRICS_ON);
0200: setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
0201: RenderingHints.VALUE_FRACTIONALMETRICS_ON);
0202: this .convertImagesToJPEG = convertImagesToJPEG;
0203: this .jpegQuality = quality;
0204: this .onlyShapes = onlyShapes;
0205: this .transform = new AffineTransform();
0206: this .baseFonts = new HashMap();
0207: if (!onlyShapes) {
0208: this .fontMapper = fontMapper;
0209: if (this .fontMapper == null)
0210: this .fontMapper = new DefaultFontMapper();
0211: }
0212: paint = Color.black;
0213: background = Color.white;
0214: setFont(new Font("sanserif", Font.PLAIN, 12));
0215: this .cb = cb;
0216: cb.saveState();
0217: this .width = width;
0218: this .height = height;
0219: clip = new Area(new Rectangle2D.Float(0, 0, width, height));
0220: clip(clip);
0221: originalStroke = stroke = oldStroke = strokeOne;
0222: setStrokeDiff(stroke, null);
0223: cb.saveState();
0224: }
0225:
0226: /**
0227: * @see Graphics2D#draw(Shape)
0228: */
0229: public void draw(Shape s) {
0230: followPath(s, STROKE);
0231: }
0232:
0233: /**
0234: * @see Graphics2D#drawImage(Image, AffineTransform, ImageObserver)
0235: */
0236: public boolean drawImage(Image img, AffineTransform xform,
0237: ImageObserver obs) {
0238: return drawImage(img, null, xform, null, obs);
0239: }
0240:
0241: /**
0242: * @see Graphics2D#drawImage(BufferedImage, BufferedImageOp, int, int)
0243: */
0244: public void drawImage(BufferedImage img, BufferedImageOp op, int x,
0245: int y) {
0246: BufferedImage result = img;
0247: if (op != null) {
0248: result = op.createCompatibleDestImage(img, img
0249: .getColorModel());
0250: result = op.filter(img, result);
0251: }
0252: drawImage(result, x, y, null);
0253: }
0254:
0255: /**
0256: * @see Graphics2D#drawRenderedImage(RenderedImage, AffineTransform)
0257: */
0258: public void drawRenderedImage(RenderedImage img,
0259: AffineTransform xform) {
0260: BufferedImage image = null;
0261: if (img instanceof BufferedImage) {
0262: image = (BufferedImage) img;
0263: } else {
0264: ColorModel cm = img.getColorModel();
0265: int width = img.getWidth();
0266: int height = img.getHeight();
0267: WritableRaster raster = cm.createCompatibleWritableRaster(
0268: width, height);
0269: boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
0270: Hashtable properties = new Hashtable();
0271: String[] keys = img.getPropertyNames();
0272: if (keys != null) {
0273: for (int i = 0; i < keys.length; i++) {
0274: properties.put(keys[i], img.getProperty(keys[i]));
0275: }
0276: }
0277: BufferedImage result = new BufferedImage(cm, raster,
0278: isAlphaPremultiplied, properties);
0279: img.copyData(raster);
0280: image = result;
0281: }
0282: drawImage(image, xform, null);
0283: }
0284:
0285: /**
0286: * @see Graphics2D#drawRenderableImage(RenderableImage, AffineTransform)
0287: */
0288: public void drawRenderableImage(RenderableImage img,
0289: AffineTransform xform) {
0290: drawRenderedImage(img.createDefaultRendering(), xform);
0291: }
0292:
0293: /**
0294: * @see Graphics#drawString(String, int, int)
0295: */
0296: public void drawString(String s, int x, int y) {
0297: drawString(s, (float) x, (float) y);
0298: }
0299:
0300: /**
0301: * Calculates position and/or stroke thickness depending on the font size
0302: * @param d value to be converted
0303: * @param i font size
0304: * @return position and/or stroke thickness depending on the font size
0305: */
0306: public static double asPoints(double d, int i) {
0307: return (d * (double) i) / (double) AFM_DIVISOR;
0308: }
0309:
0310: /**
0311: * This routine goes through the attributes and sets the font
0312: * before calling the actual string drawing routine
0313: * @param iter
0314: */
0315: protected void doAttributes(AttributedCharacterIterator iter) {
0316: underline = false;
0317: Set set = iter.getAttributes().keySet();
0318: for (Iterator iterator = set.iterator(); iterator.hasNext();) {
0319: AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) iterator
0320: .next();
0321: if (!(attribute instanceof TextAttribute))
0322: continue;
0323: TextAttribute textattribute = (TextAttribute) attribute;
0324: if (textattribute.equals(TextAttribute.FONT)) {
0325: Font font = (Font) iter.getAttributes().get(
0326: textattribute);
0327: setFont(font);
0328: } else if (textattribute.equals(TextAttribute.UNDERLINE)) {
0329: if (iter.getAttributes().get(textattribute) == TextAttribute.UNDERLINE_ON)
0330: underline = true;
0331: } else if (textattribute.equals(TextAttribute.SIZE)) {
0332: Object obj = iter.getAttributes().get(textattribute);
0333: if (obj instanceof Integer) {
0334: int i = ((Integer) obj).intValue();
0335: setFont(getFont().deriveFont(getFont().getStyle(),
0336: i));
0337: } else if (obj instanceof Float) {
0338: float f = ((Float) obj).floatValue();
0339: setFont(getFont().deriveFont(getFont().getStyle(),
0340: f));
0341: }
0342: } else if (textattribute.equals(TextAttribute.FOREGROUND)) {
0343: setColor((Color) iter.getAttributes()
0344: .get(textattribute));
0345: } else if (textattribute.equals(TextAttribute.FAMILY)) {
0346: Font font = getFont();
0347: Map fontAttributes = font.getAttributes();
0348: fontAttributes.put(TextAttribute.FAMILY, iter
0349: .getAttributes().get(textattribute));
0350: setFont(font.deriveFont(fontAttributes));
0351: } else if (textattribute.equals(TextAttribute.POSTURE)) {
0352: Font font = getFont();
0353: Map fontAttributes = font.getAttributes();
0354: fontAttributes.put(TextAttribute.POSTURE, iter
0355: .getAttributes().get(textattribute));
0356: setFont(font.deriveFont(fontAttributes));
0357: } else if (textattribute.equals(TextAttribute.WEIGHT)) {
0358: Font font = getFont();
0359: Map fontAttributes = font.getAttributes();
0360: fontAttributes.put(TextAttribute.WEIGHT, iter
0361: .getAttributes().get(textattribute));
0362: setFont(font.deriveFont(fontAttributes));
0363: }
0364: }
0365: }
0366:
0367: /**
0368: * @see Graphics2D#drawString(String, float, float)
0369: */
0370: public void drawString(String s, float x, float y) {
0371: if (s.length() == 0)
0372: return;
0373: setFillPaint();
0374: if (onlyShapes) {
0375: drawGlyphVector(this .font.layoutGlyphVector(
0376: getFontRenderContext(), s.toCharArray(), 0, s
0377: .length(),
0378: java.awt.Font.LAYOUT_LEFT_TO_RIGHT), x, y);
0379: // Use the following line to compile in JDK 1.3
0380: // drawGlyphVector(this.font.createGlyphVector(getFontRenderContext(), s), x, y);
0381: } else {
0382: boolean restoreTextRenderingMode = false;
0383: AffineTransform at = getTransform();
0384: AffineTransform at2 = getTransform();
0385: at2.translate(x, y);
0386: at2.concatenate(font.getTransform());
0387: setTransform(at2);
0388: AffineTransform inverse = this .normalizeMatrix();
0389: AffineTransform flipper = AffineTransform.getScaleInstance(
0390: 1, -1);
0391: inverse.concatenate(flipper);
0392: double[] mx = new double[6];
0393: inverse.getMatrix(mx);
0394: cb.beginText();
0395: cb.setFontAndSize(baseFont, fontSize);
0396: // Check if we need to simulate an italic font.
0397: // When there are different fonts for italic, bold, italic bold
0398: // the font.getName() will be different from the font.getFontName()
0399: // value. When they are the same value then we are normally dealing
0400: // with a single font that has been made into an italic or bold
0401: // font.
0402: if (font.isItalic()
0403: && font.getFontName().equals(font.getName())) {
0404: float angle = baseFont.getFontDescriptor(
0405: BaseFont.ITALICANGLE, 1000);
0406: float angle2 = font.getItalicAngle();
0407: // We don't have an italic version of this font so we need
0408: // to set the font angle ourselves to produce an italic font.
0409: if (angle2 == 0) {
0410: // The JavaVM didn't have an angle setting for making
0411: // the font an italic font so use a default of
0412: // italic angle of 15 degrees.
0413: angle2 = 15.0f;
0414: } else {
0415: // This sign of the angle for Java and PDF seams
0416: // seams to be reversed.
0417: angle2 = -angle2;
0418: }
0419: if (angle == 0) {
0420: mx[2] = angle2 / 100.0f;
0421: }
0422: }
0423: cb.setTextMatrix((float) mx[0], (float) mx[1],
0424: (float) mx[2], (float) mx[3], (float) mx[4],
0425: (float) mx[5]);
0426: Float fontTextAttributeWidth = (Float) font.getAttributes()
0427: .get(TextAttribute.WIDTH);
0428: fontTextAttributeWidth = (fontTextAttributeWidth == null) ? TextAttribute.WIDTH_REGULAR
0429: : fontTextAttributeWidth;
0430: if (!TextAttribute.WIDTH_REGULAR
0431: .equals(fontTextAttributeWidth))
0432: cb.setHorizontalScaling(100.0f / fontTextAttributeWidth
0433: .floatValue());
0434:
0435: // Check if we need to simulate a bold font.
0436: // Do nothing if the BaseFont is already bold. This test is not foolproof but it will work most of the times.
0437: if (baseFont.getPostscriptFontName().toLowerCase().indexOf(
0438: "bold") < 0) {
0439: // Get the weight of the font so we can detect fonts with a weight
0440: // that makes them bold, but the Font.isBold() value is false.
0441: Float weight = (Float) font.getAttributes().get(
0442: TextAttribute.WEIGHT);
0443: if (weight == null) {
0444: weight = (font.isBold()) ? TextAttribute.WEIGHT_BOLD
0445: : TextAttribute.WEIGHT_REGULAR;
0446: }
0447: if ((font.isBold() || (weight.floatValue() >= TextAttribute.WEIGHT_SEMIBOLD
0448: .floatValue()))
0449: && (font.getFontName().equals(font.getName()))) {
0450: // Simulate a bold font.
0451: float strokeWidth = font.getSize2D()
0452: * (weight.floatValue() - TextAttribute.WEIGHT_REGULAR
0453: .floatValue()) / 30f;
0454: if (strokeWidth != 1) {
0455: cb
0456: .setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);
0457: cb.setLineWidth(strokeWidth);
0458: cb.setColorStroke(getColor());
0459: restoreTextRenderingMode = true;
0460: }
0461: }
0462: }
0463:
0464: double width = 0;
0465: if (font.getSize2D() > 0) {
0466: float scale = 1000 / font.getSize2D();
0467: width = font.deriveFont(
0468: AffineTransform.getScaleInstance(scale, scale))
0469: .getStringBounds(s, getFontRenderContext())
0470: .getWidth()
0471: / scale;
0472: }
0473: if (s.length() > 1) {
0474: float adv = ((float) width - baseFont.getWidthPoint(s,
0475: fontSize))
0476: / (s.length() - 1);
0477: cb.setCharacterSpacing(adv);
0478: }
0479: cb.showText(s);
0480: if (s.length() > 1) {
0481: cb.setCharacterSpacing(0);
0482: }
0483: if (!TextAttribute.WIDTH_REGULAR
0484: .equals(fontTextAttributeWidth))
0485: cb.setHorizontalScaling(100);
0486:
0487: // Restore the original TextRenderingMode if needed.
0488: if (restoreTextRenderingMode) {
0489: cb
0490: .setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
0491: }
0492:
0493: cb.endText();
0494: setTransform(at);
0495: if (underline) {
0496: // These two are supposed to be taken from the .AFM file
0497: //int UnderlinePosition = -100;
0498: int UnderlineThickness = 50;
0499: //
0500: double d = asPoints((double) UnderlineThickness,
0501: (int) fontSize);
0502: setStroke(new BasicStroke((float) d));
0503: y = (float) ((double) (y) + asPoints(
0504: (double) (UnderlineThickness), (int) fontSize));
0505: Line2D line = new Line2D.Double((double) x, (double) y,
0506: (double) (width + x), (double) y);
0507: draw(line);
0508: }
0509: }
0510: }
0511:
0512: /**
0513: * @see Graphics#drawString(AttributedCharacterIterator, int, int)
0514: */
0515: public void drawString(AttributedCharacterIterator iterator, int x,
0516: int y) {
0517: drawString(iterator, (float) x, (float) y);
0518: }
0519:
0520: /**
0521: * @see Graphics2D#drawString(AttributedCharacterIterator, float, float)
0522: */
0523: public void drawString(AttributedCharacterIterator iter, float x,
0524: float y) {
0525: /*
0526: StringBuffer sb = new StringBuffer();
0527: for(char c = iter.first(); c != AttributedCharacterIterator.DONE; c = iter.next()) {
0528: sb.append(c);
0529: }
0530: drawString(sb.toString(),x,y);
0531: */
0532: StringBuffer stringbuffer = new StringBuffer(iter.getEndIndex());
0533: for (char c = iter.first(); c != '\uFFFF'; c = iter.next()) {
0534: if (iter.getIndex() == iter.getRunStart()) {
0535: if (stringbuffer.length() > 0) {
0536: drawString(stringbuffer.toString(), x, y);
0537: FontMetrics fontmetrics = getFontMetrics();
0538: x = (float) ((double) x + fontmetrics
0539: .getStringBounds(stringbuffer.toString(),
0540: this ).getWidth());
0541: stringbuffer.delete(0, stringbuffer.length());
0542: }
0543: doAttributes(iter);
0544: }
0545: stringbuffer.append(c);
0546: }
0547:
0548: drawString(stringbuffer.toString(), x, y);
0549: underline = false;
0550: }
0551:
0552: /**
0553: * @see Graphics2D#drawGlyphVector(GlyphVector, float, float)
0554: */
0555: public void drawGlyphVector(GlyphVector g, float x, float y) {
0556: Shape s = g.getOutline(x, y);
0557: fill(s);
0558: }
0559:
0560: /**
0561: * @see Graphics2D#fill(Shape)
0562: */
0563: public void fill(Shape s) {
0564: followPath(s, FILL);
0565: }
0566:
0567: /**
0568: * @see Graphics2D#hit(Rectangle, Shape, boolean)
0569: */
0570: public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
0571: if (onStroke) {
0572: s = stroke.createStrokedShape(s);
0573: }
0574: s = transform.createTransformedShape(s);
0575: Area area = new Area(s);
0576: if (clip != null)
0577: area.intersect(clip);
0578: return area.intersects(rect.x, rect.y, rect.width, rect.height);
0579: }
0580:
0581: /**
0582: * @see Graphics2D#getDeviceConfiguration()
0583: */
0584: public GraphicsConfiguration getDeviceConfiguration() {
0585: return dg2.getDeviceConfiguration();
0586: }
0587:
0588: /**
0589: * Method contributed by Alexej Suchov
0590: * @see Graphics2D#setComposite(Composite)
0591: */
0592: public void setComposite(Composite comp) {
0593:
0594: if (comp instanceof AlphaComposite) {
0595:
0596: AlphaComposite composite = (AlphaComposite) comp;
0597:
0598: if (composite.getRule() == 3) {
0599:
0600: alpha = composite.getAlpha();
0601: this .composite = composite;
0602:
0603: if (realPaint != null && (realPaint instanceof Color)) {
0604:
0605: Color c = (Color) realPaint;
0606: paint = new Color(c.getRed(), c.getGreen(), c
0607: .getBlue(),
0608: (int) ((float) c.getAlpha() * alpha));
0609: }
0610: return;
0611: }
0612: }
0613:
0614: this .composite = comp;
0615: alpha = 1.0F;
0616:
0617: }
0618:
0619: /**
0620: * Method contributed by Alexej Suchov
0621: * @see Graphics2D#setPaint(Paint)
0622: */
0623: public void setPaint(Paint paint) {
0624: if (paint == null)
0625: return;
0626: this .paint = paint;
0627: realPaint = paint;
0628:
0629: if ((composite instanceof AlphaComposite)
0630: && (paint instanceof Color)) {
0631:
0632: AlphaComposite co = (AlphaComposite) composite;
0633:
0634: if (co.getRule() == 3) {
0635: Color c = (Color) paint;
0636: this .paint = new Color(c.getRed(), c.getGreen(), c
0637: .getBlue(),
0638: (int) ((float) c.getAlpha() * alpha));
0639: realPaint = paint;
0640: }
0641: }
0642:
0643: }
0644:
0645: private Stroke transformStroke(Stroke stroke) {
0646: if (!(stroke instanceof BasicStroke))
0647: return stroke;
0648: BasicStroke st = (BasicStroke) stroke;
0649: float scale = (float) Math.sqrt(Math.abs(transform
0650: .getDeterminant()));
0651: float dash[] = st.getDashArray();
0652: if (dash != null) {
0653: for (int k = 0; k < dash.length; ++k)
0654: dash[k] *= scale;
0655: }
0656: return new BasicStroke(st.getLineWidth() * scale, st
0657: .getEndCap(), st.getLineJoin(), st.getMiterLimit(),
0658: dash, st.getDashPhase() * scale);
0659: }
0660:
0661: private void setStrokeDiff(Stroke newStroke, Stroke oldStroke) {
0662: if (newStroke == oldStroke)
0663: return;
0664: if (!(newStroke instanceof BasicStroke))
0665: return;
0666: BasicStroke nStroke = (BasicStroke) newStroke;
0667: boolean oldOk = (oldStroke instanceof BasicStroke);
0668: BasicStroke oStroke = null;
0669: if (oldOk)
0670: oStroke = (BasicStroke) oldStroke;
0671: if (!oldOk || nStroke.getLineWidth() != oStroke.getLineWidth())
0672: cb.setLineWidth(nStroke.getLineWidth());
0673: if (!oldOk || nStroke.getEndCap() != oStroke.getEndCap()) {
0674: switch (nStroke.getEndCap()) {
0675: case BasicStroke.CAP_BUTT:
0676: cb.setLineCap(0);
0677: break;
0678: case BasicStroke.CAP_SQUARE:
0679: cb.setLineCap(2);
0680: break;
0681: default:
0682: cb.setLineCap(1);
0683: }
0684: }
0685: if (!oldOk || nStroke.getLineJoin() != oStroke.getLineJoin()) {
0686: switch (nStroke.getLineJoin()) {
0687: case BasicStroke.JOIN_MITER:
0688: cb.setLineJoin(0);
0689: break;
0690: case BasicStroke.JOIN_BEVEL:
0691: cb.setLineJoin(2);
0692: break;
0693: default:
0694: cb.setLineJoin(1);
0695: }
0696: }
0697: if (!oldOk
0698: || nStroke.getMiterLimit() != oStroke.getMiterLimit())
0699: cb.setMiterLimit(nStroke.getMiterLimit());
0700: boolean makeDash;
0701: if (oldOk) {
0702: if (nStroke.getDashArray() != null) {
0703: if (nStroke.getDashPhase() != oStroke.getDashPhase()) {
0704: makeDash = true;
0705: } else if (!java.util.Arrays.equals(nStroke
0706: .getDashArray(), oStroke.getDashArray())) {
0707: makeDash = true;
0708: } else
0709: makeDash = false;
0710: } else if (oStroke.getDashArray() != null) {
0711: makeDash = true;
0712: } else
0713: makeDash = false;
0714: } else {
0715: makeDash = true;
0716: }
0717: if (makeDash) {
0718: float dash[] = nStroke.getDashArray();
0719: if (dash == null)
0720: cb.setLiteral("[]0 d\n");
0721: else {
0722: cb.setLiteral('[');
0723: int lim = dash.length;
0724: for (int k = 0; k < lim; ++k) {
0725: cb.setLiteral(dash[k]);
0726: cb.setLiteral(' ');
0727: }
0728: cb.setLiteral(']');
0729: cb.setLiteral(nStroke.getDashPhase());
0730: cb.setLiteral(" d\n");
0731: }
0732: }
0733: }
0734:
0735: /**
0736: * @see Graphics2D#setStroke(Stroke)
0737: */
0738: public void setStroke(Stroke s) {
0739: originalStroke = s;
0740: this .stroke = transformStroke(s);
0741: }
0742:
0743: /**
0744: * Sets a rendering hint
0745: * @param arg0
0746: * @param arg1
0747: */
0748: public void setRenderingHint(Key arg0, Object arg1) {
0749: if (arg1 != null) {
0750: rhints.put(arg0, arg1);
0751: } else {
0752: rhints.remove(arg0);
0753: }
0754: }
0755:
0756: /**
0757: * @param arg0 a key
0758: * @return the rendering hint
0759: */
0760: public Object getRenderingHint(Key arg0) {
0761: return rhints.get(arg0);
0762: }
0763:
0764: /**
0765: * @see Graphics2D#setRenderingHints(Map)
0766: */
0767: public void setRenderingHints(Map hints) {
0768: rhints.clear();
0769: rhints.putAll(hints);
0770: }
0771:
0772: /**
0773: * @see Graphics2D#addRenderingHints(Map)
0774: */
0775: public void addRenderingHints(Map hints) {
0776: rhints.putAll(hints);
0777: }
0778:
0779: /**
0780: * @see Graphics2D#getRenderingHints()
0781: */
0782: public RenderingHints getRenderingHints() {
0783: return rhints;
0784: }
0785:
0786: /**
0787: * @see Graphics#translate(int, int)
0788: */
0789: public void translate(int x, int y) {
0790: translate((double) x, (double) y);
0791: }
0792:
0793: /**
0794: * @see Graphics2D#translate(double, double)
0795: */
0796: public void translate(double tx, double ty) {
0797: transform.translate(tx, ty);
0798: }
0799:
0800: /**
0801: * @see Graphics2D#rotate(double)
0802: */
0803: public void rotate(double theta) {
0804: transform.rotate(theta);
0805: }
0806:
0807: /**
0808: * @see Graphics2D#rotate(double, double, double)
0809: */
0810: public void rotate(double theta, double x, double y) {
0811: transform.rotate(theta, x, y);
0812: }
0813:
0814: /**
0815: * @see Graphics2D#scale(double, double)
0816: */
0817: public void scale(double sx, double sy) {
0818: transform.scale(sx, sy);
0819: this .stroke = transformStroke(originalStroke);
0820: }
0821:
0822: /**
0823: * @see Graphics2D#shear(double, double)
0824: */
0825: public void shear(double shx, double shy) {
0826: transform.shear(shx, shy);
0827: }
0828:
0829: /**
0830: * @see Graphics2D#transform(AffineTransform)
0831: */
0832: public void transform(AffineTransform tx) {
0833: transform.concatenate(tx);
0834: this .stroke = transformStroke(originalStroke);
0835: }
0836:
0837: /**
0838: * @see Graphics2D#setTransform(AffineTransform)
0839: */
0840: public void setTransform(AffineTransform t) {
0841: transform = new AffineTransform(t);
0842: this .stroke = transformStroke(originalStroke);
0843: }
0844:
0845: /**
0846: * @see Graphics2D#getTransform()
0847: */
0848: public AffineTransform getTransform() {
0849: return new AffineTransform(transform);
0850: }
0851:
0852: /**
0853: * Method contributed by Alexej Suchov
0854: * @see Graphics2D#getPaint()
0855: */
0856: public Paint getPaint() {
0857: if (realPaint != null) {
0858: return realPaint;
0859: } else {
0860: return paint;
0861: }
0862: }
0863:
0864: /**
0865: * @see Graphics2D#getComposite()
0866: */
0867: public Composite getComposite() {
0868: return composite;
0869: }
0870:
0871: /**
0872: * @see Graphics2D#setBackground(Color)
0873: */
0874: public void setBackground(Color color) {
0875: background = color;
0876: }
0877:
0878: /**
0879: * @see Graphics2D#getBackground()
0880: */
0881: public Color getBackground() {
0882: return background;
0883: }
0884:
0885: /**
0886: * @see Graphics2D#getStroke()
0887: */
0888: public Stroke getStroke() {
0889: return originalStroke;
0890: }
0891:
0892: /**
0893: * @see Graphics2D#getFontRenderContext()
0894: */
0895: public FontRenderContext getFontRenderContext() {
0896: boolean antialias = RenderingHints.VALUE_TEXT_ANTIALIAS_ON
0897: .equals(getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING));
0898: boolean fractions = RenderingHints.VALUE_FRACTIONALMETRICS_ON
0899: .equals(getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS));
0900: return new FontRenderContext(new AffineTransform(), antialias,
0901: fractions);
0902: }
0903:
0904: /**
0905: * @see Graphics#create()
0906: */
0907: public Graphics create() {
0908: PdfGraphics2D g2 = new PdfGraphics2D();
0909: g2.onlyShapes = this .onlyShapes;
0910: g2.transform = new AffineTransform(this .transform);
0911: g2.baseFonts = this .baseFonts;
0912: g2.fontMapper = this .fontMapper;
0913: g2.paint = this .paint;
0914: g2.fillGState = this .fillGState;
0915: g2.strokeGState = this .strokeGState;
0916: g2.background = this .background;
0917: g2.mediaTracker = this .mediaTracker;
0918: g2.convertImagesToJPEG = this .convertImagesToJPEG;
0919: g2.jpegQuality = this .jpegQuality;
0920: g2.setFont(this .font);
0921: g2.cb = this .cb.getDuplicate();
0922: g2.cb.saveState();
0923: g2.width = this .width;
0924: g2.height = this .height;
0925: g2.followPath(new Area(new Rectangle2D.Float(0, 0, width,
0926: height)), CLIP);
0927: if (this .clip != null)
0928: g2.clip = new Area(this .clip);
0929: g2.composite = composite;
0930: g2.stroke = stroke;
0931: g2.originalStroke = originalStroke;
0932: g2.strokeOne = (BasicStroke) g2.transformStroke(g2.strokeOne);
0933: g2.oldStroke = g2.strokeOne;
0934: g2.setStrokeDiff(g2.oldStroke, null);
0935: g2.cb.saveState();
0936: if (g2.clip != null)
0937: g2.followPath(g2.clip, CLIP);
0938: g2.kid = true;
0939: if (this .kids == null)
0940: this .kids = new ArrayList();
0941: this .kids.add(new Integer(cb.getInternalBuffer().size()));
0942: this .kids.add(g2);
0943: return g2;
0944: }
0945:
0946: public PdfContentByte getContent() {
0947: return this .cb;
0948: }
0949:
0950: /**
0951: * @see Graphics#getColor()
0952: */
0953: public Color getColor() {
0954: if (paint instanceof Color) {
0955: return (Color) paint;
0956: } else {
0957: return Color.black;
0958: }
0959: }
0960:
0961: /**
0962: * @see Graphics#setColor(Color)
0963: */
0964: public void setColor(Color color) {
0965: setPaint(color);
0966: }
0967:
0968: /**
0969: * @see Graphics#setPaintMode()
0970: */
0971: public void setPaintMode() {
0972: }
0973:
0974: /**
0975: * @see Graphics#setXORMode(Color)
0976: */
0977: public void setXORMode(Color c1) {
0978:
0979: }
0980:
0981: /**
0982: * @see Graphics#getFont()
0983: */
0984: public Font getFont() {
0985: return font;
0986: }
0987:
0988: /**
0989: * @see Graphics#setFont(Font)
0990: */
0991: /**
0992: * Sets the current font.
0993: */
0994: public void setFont(Font f) {
0995: if (f == null)
0996: return;
0997: if (onlyShapes) {
0998: font = f;
0999: return;
1000: }
1001: if (f == font)
1002: return;
1003: font = f;
1004: fontSize = f.getSize2D();
1005: baseFont = getCachedBaseFont(f);
1006: }
1007:
1008: private BaseFont getCachedBaseFont(Font f) {
1009: synchronized (baseFonts) {
1010: BaseFont bf = (BaseFont) baseFonts.get(f.getFontName());
1011: if (bf == null) {
1012: bf = fontMapper.awtToPdf(f);
1013: baseFonts.put(f.getFontName(), bf);
1014: }
1015: return bf;
1016: }
1017: }
1018:
1019: /**
1020: * @see Graphics#getFontMetrics(Font)
1021: */
1022: public FontMetrics getFontMetrics(Font f) {
1023: return dg2.getFontMetrics(f);
1024: }
1025:
1026: /**
1027: * @see Graphics#getClipBounds()
1028: */
1029: public Rectangle getClipBounds() {
1030: if (clip == null)
1031: return null;
1032: return getClip().getBounds();
1033: }
1034:
1035: /**
1036: * @see Graphics#clipRect(int, int, int, int)
1037: */
1038: public void clipRect(int x, int y, int width, int height) {
1039: Rectangle2D rect = new Rectangle2D.Double(x, y, width, height);
1040: clip(rect);
1041: }
1042:
1043: /**
1044: * @see Graphics#setClip(int, int, int, int)
1045: */
1046: public void setClip(int x, int y, int width, int height) {
1047: Rectangle2D rect = new Rectangle2D.Double(x, y, width, height);
1048: setClip(rect);
1049: }
1050:
1051: /**
1052: * @see Graphics2D#clip(Shape)
1053: */
1054: public void clip(Shape s) {
1055: if (s == null) {
1056: setClip(null);
1057: return;
1058: }
1059: s = transform.createTransformedShape(s);
1060: if (clip == null)
1061: clip = new Area(s);
1062: else
1063: clip.intersect(new Area(s));
1064: followPath(s, CLIP);
1065: }
1066:
1067: /**
1068: * @see Graphics#getClip()
1069: */
1070: public Shape getClip() {
1071: try {
1072: return transform.createInverse().createTransformedShape(
1073: clip);
1074: } catch (NoninvertibleTransformException e) {
1075: return null;
1076: }
1077: }
1078:
1079: /**
1080: * @see Graphics#setClip(Shape)
1081: */
1082: public void setClip(Shape s) {
1083: cb.restoreState();
1084: cb.saveState();
1085: if (s != null)
1086: s = transform.createTransformedShape(s);
1087: if (s == null) {
1088: clip = null;
1089: } else {
1090: clip = new Area(s);
1091: followPath(s, CLIP);
1092: }
1093: paintFill = paintStroke = null;
1094: currentFillGState = currentStrokeGState = 255;
1095: oldStroke = strokeOne;
1096: }
1097:
1098: /**
1099: * @see Graphics#copyArea(int, int, int, int, int, int)
1100: */
1101: public void copyArea(int x, int y, int width, int height, int dx,
1102: int dy) {
1103:
1104: }
1105:
1106: /**
1107: * @see Graphics#drawLine(int, int, int, int)
1108: */
1109: public void drawLine(int x1, int y1, int x2, int y2) {
1110: Line2D line = new Line2D.Double((double) x1, (double) y1,
1111: (double) x2, (double) y2);
1112: draw(line);
1113: }
1114:
1115: /**
1116: * @see Graphics#fillRect(int, int, int, int)
1117: */
1118: public void drawRect(int x, int y, int width, int height) {
1119: draw(new Rectangle(x, y, width, height));
1120: }
1121:
1122: /**
1123: * @see Graphics#fillRect(int, int, int, int)
1124: */
1125: public void fillRect(int x, int y, int width, int height) {
1126: fill(new Rectangle(x, y, width, height));
1127: }
1128:
1129: /**
1130: * @see Graphics#clearRect(int, int, int, int)
1131: */
1132: public void clearRect(int x, int y, int width, int height) {
1133: Paint temp = paint;
1134: setPaint(background);
1135: fillRect(x, y, width, height);
1136: setPaint(temp);
1137: }
1138:
1139: /**
1140: * @see Graphics#drawRoundRect(int, int, int, int, int, int)
1141: */
1142: public void drawRoundRect(int x, int y, int width, int height,
1143: int arcWidth, int arcHeight) {
1144: RoundRectangle2D rect = new RoundRectangle2D.Double(x, y,
1145: width, height, arcWidth, arcHeight);
1146: draw(rect);
1147: }
1148:
1149: /**
1150: * @see Graphics#fillRoundRect(int, int, int, int, int, int)
1151: */
1152: public void fillRoundRect(int x, int y, int width, int height,
1153: int arcWidth, int arcHeight) {
1154: RoundRectangle2D rect = new RoundRectangle2D.Double(x, y,
1155: width, height, arcWidth, arcHeight);
1156: fill(rect);
1157: }
1158:
1159: /**
1160: * @see Graphics#drawOval(int, int, int, int)
1161: */
1162: public void drawOval(int x, int y, int width, int height) {
1163: Ellipse2D oval = new Ellipse2D.Float((float) x, (float) y,
1164: (float) width, (float) height);
1165: draw(oval);
1166: }
1167:
1168: /**
1169: * @see Graphics#fillOval(int, int, int, int)
1170: */
1171: public void fillOval(int x, int y, int width, int height) {
1172: Ellipse2D oval = new Ellipse2D.Float((float) x, (float) y,
1173: (float) width, (float) height);
1174: fill(oval);
1175: }
1176:
1177: /**
1178: * @see Graphics#drawArc(int, int, int, int, int, int)
1179: */
1180: public void drawArc(int x, int y, int width, int height,
1181: int startAngle, int arcAngle) {
1182: Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle,
1183: arcAngle, Arc2D.OPEN);
1184: draw(arc);
1185:
1186: }
1187:
1188: /**
1189: * @see Graphics#fillArc(int, int, int, int, int, int)
1190: */
1191: public void fillArc(int x, int y, int width, int height,
1192: int startAngle, int arcAngle) {
1193: Arc2D arc = new Arc2D.Double(x, y, width, height, startAngle,
1194: arcAngle, Arc2D.PIE);
1195: fill(arc);
1196: }
1197:
1198: /**
1199: * @see Graphics#drawPolyline(int[], int[], int)
1200: */
1201: public void drawPolyline(int[] x, int[] y, int nPoints) {
1202: PolylineShape polyline = new PolylineShape(x, y, nPoints);
1203: draw(polyline);
1204: }
1205:
1206: /**
1207: * @see Graphics#drawPolygon(int[], int[], int)
1208: */
1209: public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
1210: Polygon poly = new Polygon(xPoints, yPoints, nPoints);
1211: draw(poly);
1212: }
1213:
1214: /**
1215: * @see Graphics#fillPolygon(int[], int[], int)
1216: */
1217: public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
1218: Polygon poly = new Polygon();
1219: for (int i = 0; i < nPoints; i++) {
1220: poly.addPoint(xPoints[i], yPoints[i]);
1221: }
1222: fill(poly);
1223: }
1224:
1225: /**
1226: * @see Graphics#drawImage(Image, int, int, ImageObserver)
1227: */
1228: public boolean drawImage(Image img, int x, int y,
1229: ImageObserver observer) {
1230: return drawImage(img, x, y, null, observer);
1231: }
1232:
1233: /**
1234: * @see Graphics#drawImage(Image, int, int, int, int, ImageObserver)
1235: */
1236: public boolean drawImage(Image img, int x, int y, int width,
1237: int height, ImageObserver observer) {
1238: return drawImage(img, x, y, width, height, null, observer);
1239: }
1240:
1241: /**
1242: * @see Graphics#drawImage(Image, int, int, Color, ImageObserver)
1243: */
1244: public boolean drawImage(Image img, int x, int y, Color bgcolor,
1245: ImageObserver observer) {
1246: waitForImage(img);
1247: return drawImage(img, x, y, img.getWidth(observer), img
1248: .getHeight(observer), bgcolor, observer);
1249: }
1250:
1251: /**
1252: * @see Graphics#drawImage(Image, int, int, int, int, Color, ImageObserver)
1253: */
1254: public boolean drawImage(Image img, int x, int y, int width,
1255: int height, Color bgcolor, ImageObserver observer) {
1256: waitForImage(img);
1257: double scalex = width / (double) img.getWidth(observer);
1258: double scaley = height / (double) img.getHeight(observer);
1259: AffineTransform tx = AffineTransform.getTranslateInstance(x, y);
1260: tx.scale(scalex, scaley);
1261: return drawImage(img, null, tx, bgcolor, observer);
1262: }
1263:
1264: /**
1265: * @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int, ImageObserver)
1266: */
1267: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
1268: int dy2, int sx1, int sy1, int sx2, int sy2,
1269: ImageObserver observer) {
1270: return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
1271: null, observer);
1272: }
1273:
1274: /**
1275: * @see Graphics#drawImage(Image, int, int, int, int, int, int, int, int, Color, ImageObserver)
1276: */
1277: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
1278: int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1279: ImageObserver observer) {
1280: waitForImage(img);
1281: double dwidth = (double) dx2 - dx1;
1282: double dheight = (double) dy2 - dy1;
1283: double swidth = (double) sx2 - sx1;
1284: double sheight = (double) sy2 - sy1;
1285:
1286: //if either width or height is 0, then there is nothing to draw
1287: if (dwidth == 0 || dheight == 0 || swidth == 0 || sheight == 0)
1288: return true;
1289:
1290: double scalex = dwidth / swidth;
1291: double scaley = dheight / sheight;
1292:
1293: double transx = sx1 * scalex;
1294: double transy = sy1 * scaley;
1295: AffineTransform tx = AffineTransform.getTranslateInstance(dx1
1296: - transx, dy1 - transy);
1297: tx.scale(scalex, scaley);
1298:
1299: BufferedImage mask = new BufferedImage(img.getWidth(observer),
1300: img.getHeight(observer), BufferedImage.TYPE_BYTE_BINARY);
1301: Graphics g = mask.getGraphics();
1302: g.fillRect(sx1, sy1, (int) swidth, (int) sheight);
1303: drawImage(img, mask, tx, null, observer);
1304: g.dispose();
1305: return true;
1306: }
1307:
1308: /**
1309: * @see Graphics#dispose()
1310: */
1311: public void dispose() {
1312: if (kid)
1313: return;
1314: if (!disposeCalled) {
1315: disposeCalled = true;
1316: cb.restoreState();
1317: cb.restoreState();
1318: dg2.dispose();
1319: dg2 = null;
1320: if (kids != null) {
1321: ByteBuffer buf = new ByteBuffer();
1322: internalDispose(buf);
1323: ByteBuffer buf2 = cb.getInternalBuffer();
1324: buf2.reset();
1325: buf2.append(buf);
1326: }
1327: }
1328: }
1329:
1330: private void internalDispose(ByteBuffer buf) {
1331: int last = 0;
1332: int pos = 0;
1333: ByteBuffer buf2 = cb.getInternalBuffer();
1334: if (kids != null) {
1335: for (int k = 0; k < kids.size(); k += 2) {
1336: pos = ((Integer) kids.get(k)).intValue();
1337: PdfGraphics2D g2 = (PdfGraphics2D) kids.get(k + 1);
1338: g2.cb.restoreState();
1339: g2.cb.restoreState();
1340: buf.append(buf2.getBuffer(), last, pos - last);
1341: g2.dg2.dispose();
1342: g2.dg2 = null;
1343: g2.internalDispose(buf);
1344: last = pos;
1345: }
1346: }
1347: buf.append(buf2.getBuffer(), last, buf2.size() - last);
1348: }
1349:
1350: ///////////////////////////////////////////////
1351: //
1352: //
1353: // implementation specific methods
1354: //
1355: //
1356:
1357: private void followPath(Shape s, int drawType) {
1358: if (s == null)
1359: return;
1360: if (drawType == STROKE) {
1361: if (!(stroke instanceof BasicStroke)) {
1362: s = stroke.createStrokedShape(s);
1363: followPath(s, FILL);
1364: return;
1365: }
1366: }
1367: if (drawType == STROKE) {
1368: setStrokeDiff(stroke, oldStroke);
1369: oldStroke = stroke;
1370: setStrokePaint();
1371: } else if (drawType == FILL)
1372: setFillPaint();
1373: PathIterator points;
1374: int traces = 0;
1375: if (drawType == CLIP)
1376: points = s.getPathIterator(IDENTITY);
1377: else
1378: points = s.getPathIterator(transform);
1379: float[] coords = new float[6];
1380: while (!points.isDone()) {
1381: ++traces;
1382: int segtype = points.currentSegment(coords);
1383: normalizeY(coords);
1384: switch (segtype) {
1385: case PathIterator.SEG_CLOSE:
1386: cb.closePath();
1387: break;
1388:
1389: case PathIterator.SEG_CUBICTO:
1390: cb.curveTo(coords[0], coords[1], coords[2], coords[3],
1391: coords[4], coords[5]);
1392: break;
1393:
1394: case PathIterator.SEG_LINETO:
1395: cb.lineTo(coords[0], coords[1]);
1396: break;
1397:
1398: case PathIterator.SEG_MOVETO:
1399: cb.moveTo(coords[0], coords[1]);
1400: break;
1401:
1402: case PathIterator.SEG_QUADTO:
1403: cb.curveTo(coords[0], coords[1], coords[2], coords[3]);
1404: break;
1405: }
1406: points.next();
1407: }
1408: switch (drawType) {
1409: case FILL:
1410: if (traces > 0) {
1411: if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD)
1412: cb.eoFill();
1413: else
1414: cb.fill();
1415: }
1416: break;
1417: case STROKE:
1418: if (traces > 0)
1419: cb.stroke();
1420: break;
1421: default: //drawType==CLIP
1422: if (traces == 0)
1423: cb.rectangle(0, 0, 0, 0);
1424: if (points.getWindingRule() == PathIterator.WIND_EVEN_ODD)
1425: cb.eoClip();
1426: else
1427: cb.clip();
1428: cb.newPath();
1429: }
1430: }
1431:
1432: private float normalizeY(float y) {
1433: return this .height - y;
1434: }
1435:
1436: private void normalizeY(float[] coords) {
1437: coords[1] = normalizeY(coords[1]);
1438: coords[3] = normalizeY(coords[3]);
1439: coords[5] = normalizeY(coords[5]);
1440: }
1441:
1442: private AffineTransform normalizeMatrix() {
1443: double[] mx = new double[6];
1444: AffineTransform result = AffineTransform.getTranslateInstance(
1445: 0, 0);
1446: result.getMatrix(mx);
1447: mx[3] = -1;
1448: mx[5] = height;
1449: result = new AffineTransform(mx);
1450: result.concatenate(transform);
1451: return result;
1452: }
1453:
1454: private boolean drawImage(Image img, Image mask,
1455: AffineTransform xform, Color bgColor, ImageObserver obs) {
1456: if (xform == null)
1457: return true;
1458:
1459: xform.translate(0, img.getHeight(obs));
1460: xform.scale(img.getWidth(obs), img.getHeight(obs));
1461:
1462: AffineTransform inverse = this .normalizeMatrix();
1463: AffineTransform flipper = AffineTransform.getScaleInstance(1,
1464: -1);
1465: inverse.concatenate(xform);
1466: inverse.concatenate(flipper);
1467:
1468: double[] mx = new double[6];
1469: inverse.getMatrix(mx);
1470: if (currentFillGState != 255) {
1471: PdfGState gs = fillGState[255];
1472: if (gs == null) {
1473: gs = new PdfGState();
1474: gs.setFillOpacity(1);
1475: fillGState[255] = gs;
1476: }
1477: cb.setGState(gs);
1478: }
1479:
1480: try {
1481: com.lowagie.text.Image image = null;
1482: if (!convertImagesToJPEG) {
1483: image = com.lowagie.text.Image
1484: .getInstance(img, bgColor);
1485: } else {
1486: BufferedImage scaled = new BufferedImage(img
1487: .getWidth(null), img.getHeight(null),
1488: BufferedImage.TYPE_INT_RGB);
1489: Graphics2D g3 = scaled.createGraphics();
1490: g3.drawImage(img, 0, 0, img.getWidth(null), img
1491: .getHeight(null), null);
1492: g3.dispose();
1493:
1494: ByteArrayOutputStream baos = new ByteArrayOutputStream();
1495: ImageWriteParam iwparam = new JPEGImageWriteParam(
1496: Locale.getDefault());
1497: iwparam
1498: .setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
1499: iwparam.setCompressionQuality(jpegQuality);//Set here your compression rate
1500: ImageWriter iw = (ImageWriter) ImageIO
1501: .getImageWritersByFormatName("jpg").next();
1502: ImageOutputStream ios = ImageIO
1503: .createImageOutputStream(baos);
1504: iw.setOutput(ios);
1505: iw.write(null, new IIOImage(scaled, null, null),
1506: iwparam);
1507: iw.dispose();
1508: ios.close();
1509:
1510: scaled.flush();
1511: scaled = null;
1512: image = com.lowagie.text.Image.getInstance(baos
1513: .toByteArray());
1514:
1515: }
1516: if (mask != null) {
1517: com.lowagie.text.Image msk = com.lowagie.text.Image
1518: .getInstance(mask, null, true);
1519: msk.makeMask();
1520: msk.setInverted(true);
1521: image.setImageMask(msk);
1522: }
1523: cb.addImage(image, (float) mx[0], (float) mx[1],
1524: (float) mx[2], (float) mx[3], (float) mx[4],
1525: (float) mx[5]);
1526: } catch (Exception ex) {
1527: throw new IllegalArgumentException();
1528: }
1529: if (currentFillGState != 255) {
1530: PdfGState gs = fillGState[currentFillGState];
1531: cb.setGState(gs);
1532: }
1533: return true;
1534: }
1535:
1536: private boolean checkNewPaint(Paint oldPaint) {
1537: if (paint == oldPaint)
1538: return false;
1539: return !((paint instanceof Color) && paint.equals(oldPaint));
1540: }
1541:
1542: private void setFillPaint() {
1543: if (checkNewPaint(paintFill)) {
1544: paintFill = paint;
1545: setPaint(false, 0, 0, true);
1546: }
1547: }
1548:
1549: private void setStrokePaint() {
1550: if (checkNewPaint(paintStroke)) {
1551: paintStroke = paint;
1552: setPaint(false, 0, 0, false);
1553: }
1554: }
1555:
1556: private void setPaint(boolean invert, double xoffset,
1557: double yoffset, boolean fill) {
1558: if (paint instanceof Color) {
1559: Color color = (Color) paint;
1560: int alpha = color.getAlpha();
1561: if (fill) {
1562: if (alpha != currentFillGState) {
1563: currentFillGState = alpha;
1564: PdfGState gs = fillGState[alpha];
1565: if (gs == null) {
1566: gs = new PdfGState();
1567: gs.setFillOpacity((float) alpha / 255f);
1568: fillGState[alpha] = gs;
1569: }
1570: cb.setGState(gs);
1571: }
1572: cb.setColorFill(color);
1573: } else {
1574: if (alpha != currentStrokeGState) {
1575: currentStrokeGState = alpha;
1576: PdfGState gs = strokeGState[alpha];
1577: if (gs == null) {
1578: gs = new PdfGState();
1579: gs.setStrokeOpacity((float) alpha / 255f);
1580: strokeGState[alpha] = gs;
1581: }
1582: cb.setGState(gs);
1583: }
1584: cb.setColorStroke(color);
1585: }
1586: } else if (paint instanceof GradientPaint) {
1587: GradientPaint gp = (GradientPaint) paint;
1588: Point2D p1 = gp.getPoint1();
1589: transform.transform(p1, p1);
1590: Point2D p2 = gp.getPoint2();
1591: transform.transform(p2, p2);
1592: Color c1 = gp.getColor1();
1593: Color c2 = gp.getColor2();
1594: PdfShading shading = PdfShading.simpleAxial(cb
1595: .getPdfWriter(), (float) p1.getX(),
1596: normalizeY((float) p1.getY()), (float) p2.getX(),
1597: normalizeY((float) p2.getY()), c1, c2);
1598: PdfShadingPattern pat = new PdfShadingPattern(shading);
1599: if (fill)
1600: cb.setShadingFill(pat);
1601: else
1602: cb.setShadingStroke(pat);
1603: } else if (paint instanceof TexturePaint) {
1604: try {
1605: TexturePaint tp = (TexturePaint) paint;
1606: BufferedImage img = tp.getImage();
1607: Rectangle2D rect = tp.getAnchorRect();
1608: com.lowagie.text.Image image = com.lowagie.text.Image
1609: .getInstance(img, null);
1610: PdfPatternPainter pattern = cb.createPattern(image
1611: .getWidth(), image.getHeight());
1612: AffineTransform inverse = this .normalizeMatrix();
1613: inverse.translate(rect.getX(), rect.getY());
1614: inverse.scale(rect.getWidth() / image.getWidth(), -rect
1615: .getHeight()
1616: / image.getHeight());
1617: double[] mx = new double[6];
1618: inverse.getMatrix(mx);
1619: pattern.setPatternMatrix((float) mx[0], (float) mx[1],
1620: (float) mx[2], (float) mx[3], (float) mx[4],
1621: (float) mx[5]);
1622: image.setAbsolutePosition(0, 0);
1623: pattern.addImage(image);
1624: if (fill)
1625: cb.setPatternFill(pattern);
1626: else
1627: cb.setPatternStroke(pattern);
1628: } catch (Exception ex) {
1629: if (fill)
1630: cb.setColorFill(Color.gray);
1631: else
1632: cb.setColorStroke(Color.gray);
1633: }
1634: } else {
1635: try {
1636: BufferedImage img = null;
1637: int type = BufferedImage.TYPE_4BYTE_ABGR;
1638: if (paint.getTransparency() == Transparency.OPAQUE) {
1639: type = BufferedImage.TYPE_3BYTE_BGR;
1640: }
1641: img = new BufferedImage((int) width, (int) height, type);
1642: Graphics2D g = (Graphics2D) img.getGraphics();
1643: g.transform(transform);
1644: AffineTransform inv = transform.createInverse();
1645: Shape fillRect = new Rectangle2D.Double(0, 0, img
1646: .getWidth(), img.getHeight());
1647: fillRect = inv.createTransformedShape(fillRect);
1648: g.setPaint(paint);
1649: g.fill(fillRect);
1650: if (invert) {
1651: AffineTransform tx = new AffineTransform();
1652: tx.scale(1, -1);
1653: tx.translate(-xoffset, -yoffset);
1654: g.drawImage(img, tx, null);
1655: }
1656: g.dispose();
1657: g = null;
1658: com.lowagie.text.Image image = com.lowagie.text.Image
1659: .getInstance(img, null);
1660: PdfPatternPainter pattern = cb.createPattern(width,
1661: height);
1662: image.setAbsolutePosition(0, 0);
1663: pattern.addImage(image);
1664: if (fill)
1665: cb.setPatternFill(pattern);
1666: else
1667: cb.setPatternStroke(pattern);
1668: } catch (Exception ex) {
1669: if (fill)
1670: cb.setColorFill(Color.gray);
1671: else
1672: cb.setColorStroke(Color.gray);
1673: }
1674: }
1675: }
1676:
1677: private synchronized void waitForImage(java.awt.Image image) {
1678: if (mediaTracker == null)
1679: mediaTracker = new MediaTracker(
1680: new PdfGraphics2D.fakeComponent());
1681: mediaTracker.addImage(image, 0);
1682: try {
1683: mediaTracker.waitForID(0);
1684: } catch (InterruptedException e) {
1685: // empty on purpose
1686: }
1687: mediaTracker.removeImage(image);
1688: }
1689:
1690: static private class fakeComponent extends Component {
1691:
1692: private static final long serialVersionUID = 6450197945596086638L;
1693: }
1694: }
|