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