pdfgraphics2d.java

来自「源码包含生成 PDF 和 HTML 的类库」· Java 代码 · 共 1,670 行 · 第 1/4 页

JAVA
1,670
字号
/* * $Id: PdfGraphics2D.java 3611 2008-11-05 19:45:31Z blowagie $ * * Copyright 2002 by Jim Moore <jim@scolamoore.com>. * * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the License. * * The Original Code is 'iText, a free JAVA-PDF library'. * * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. * All Rights Reserved. * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. * * Contributor(s): all the names of the contributors are added in the source code * where applicable. * * Alternatively, the contents of this file may be used under the terms of the * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the * provisions of LGPL are applicable instead of those above.  If you wish to * allow use of your version of this file only under the terms of the LGPL * License and not to allow others to use your version of this file under * the MPL, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the LGPL. * If you do not delete the provisions above, a recipient may use your version * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE. * * This library is free software; you can redistribute it and/or modify it * under the terms of the MPL as stated above or under the terms of the GNU * Library General Public License as published by the Free Software Foundation; * either version 2 of the License, or any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more * details. * * If you didn't download this code from the following link, you should check if * you aren't using an obsolete version: * http://www.lowagie.com/iText/ */package com.lowagie.text.pdf;import java.awt.AlphaComposite;import java.awt.BasicStroke;import java.awt.Color;import java.awt.Component;import java.awt.Composite;import java.awt.Font;import java.awt.FontMetrics;import java.awt.GradientPaint;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.GraphicsConfiguration;import java.awt.Image;import java.awt.MediaTracker;import java.awt.Paint;import java.awt.Polygon;import java.awt.Rectangle;import java.awt.RenderingHints;import java.awt.Shape;import java.awt.Stroke;import java.awt.TexturePaint;import java.awt.Transparency;import java.awt.RenderingHints.Key;import java.awt.font.FontRenderContext;import java.awt.font.GlyphVector;import java.awt.font.TextAttribute;import java.awt.geom.AffineTransform;import java.awt.geom.Arc2D;import java.awt.geom.Area;import java.awt.geom.Ellipse2D;import java.awt.geom.Line2D;import java.awt.geom.NoninvertibleTransformException;import java.awt.geom.PathIterator;import java.awt.geom.Point2D;import java.awt.geom.Rectangle2D;import java.awt.geom.RoundRectangle2D;import java.awt.image.BufferedImage;import java.awt.image.BufferedImageOp;import java.awt.image.ColorModel;import java.awt.image.ImageObserver;import java.awt.image.RenderedImage;import java.awt.image.WritableRaster;import java.awt.image.renderable.RenderableImage;import java.io.ByteArrayOutputStream;import java.text.AttributedCharacterIterator;import java.util.ArrayList;import java.util.HashMap;import java.util.Hashtable;import java.util.Iterator;import java.util.Map;import java.util.Set;import com.lowagie.text.pdf.internal.PolylineShape;import java.util.Locale;import javax.imageio.IIOImage;import javax.imageio.ImageIO;import javax.imageio.ImageWriteParam;import javax.imageio.ImageWriter;import javax.imageio.plugins.jpeg.JPEGImageWriteParam;import javax.imageio.stream.ImageOutputStream;public class PdfGraphics2D extends Graphics2D {        private static final int FILL = 1;    private static final int STROKE = 2;    private static final int CLIP = 3;    private BasicStroke strokeOne = new BasicStroke(1);        private static final AffineTransform IDENTITY = new AffineTransform();        private Font font;    private BaseFont baseFont;    private float fontSize;    private AffineTransform transform;    private Paint paint;    private Color background;    private float width;    private float height;        private Area clip;        private RenderingHints rhints = new RenderingHints(null);        private Stroke stroke;    private Stroke originalStroke;        private PdfContentByte cb;        /** Storage for BaseFont objects created. */    private HashMap baseFonts;        private boolean disposeCalled = false;        private FontMapper fontMapper;        private ArrayList kids;        private boolean kid = false;        private Graphics2D dg2 = new BufferedImage(2, 2, BufferedImage.TYPE_INT_RGB).createGraphics();        private boolean onlyShapes = false;        private Stroke oldStroke;    private Paint paintFill;    private Paint paintStroke;        private MediaTracker mediaTracker;    // Added by Jurij Bilas    protected boolean underline;          // indicates if the font style is underlined          protected PdfGState fillGState[] = new PdfGState[256];    protected PdfGState strokeGState[] = new PdfGState[256];    protected int currentFillGState = 255;    protected int currentStrokeGState = 255;        public static final int AFM_DIVISOR = 1000; // used to calculate coordinates    private boolean convertImagesToJPEG = false;    private float jpegQuality = .95f;	// Added by Alexej Suchov	private float alpha;	// Added by Alexej Suchov	private Composite composite;	// Added by Alexej Suchov	private Paint realPaint;    private PdfGraphics2D() {        dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);        setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);        setRenderingHint(HyperLinkKey.KEY_INSTANCE, HyperLinkKey.VALUE_HYPERLINKKEY_OFF);    }        /**     * Constructor for PDFGraphics2D.     *     */    PdfGraphics2D(PdfContentByte cb, float width, float height, FontMapper fontMapper, boolean onlyShapes, boolean convertImagesToJPEG, float quality) {        super();        dg2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);        setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);        setRenderingHint(HyperLinkKey.KEY_INSTANCE, HyperLinkKey.VALUE_HYPERLINKKEY_OFF);        this.convertImagesToJPEG = convertImagesToJPEG;        this.jpegQuality = quality;        this.onlyShapes = onlyShapes;        this.transform = new AffineTransform();        this.baseFonts = new HashMap();        if (!onlyShapes) {            this.fontMapper = fontMapper;            if (this.fontMapper == null)                this.fontMapper = new DefaultFontMapper();        }        paint = Color.black;        background = Color.white;        setFont(new Font("sanserif", Font.PLAIN, 12));        this.cb = cb;        cb.saveState();        this.width = width;        this.height = height;        clip = new Area(new Rectangle2D.Float(0, 0, width, height));        clip(clip);        originalStroke = stroke = oldStroke = strokeOne;        setStrokeDiff(stroke, null);        cb.saveState();    }        /**     * @see Graphics2D#draw(Shape)     */    public void draw(Shape s) {        followPath(s, STROKE);    }        /**     * @see Graphics2D#drawImage(Image, AffineTransform, ImageObserver)     */    public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {        return drawImage(img, null, xform, null, obs);    }        /**     * @see Graphics2D#drawImage(BufferedImage, BufferedImageOp, int, int)     */    public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {        BufferedImage result = img;        if (op != null) {            result = op.createCompatibleDestImage(img, img.getColorModel());            result = op.filter(img, result);        }        drawImage(result, x, y, null);    }        /**     * @see Graphics2D#drawRenderedImage(RenderedImage, AffineTransform)     */    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {        BufferedImage image = null;        if (img instanceof BufferedImage) {            image = (BufferedImage)img;        } else {            ColorModel cm = img.getColorModel();            int width = img.getWidth();            int height = img.getHeight();            WritableRaster raster = cm.createCompatibleWritableRaster(width, height);            boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();            Hashtable properties = new Hashtable();            String[] keys = img.getPropertyNames();            if (keys!=null) {                for (int i = 0; i < keys.length; i++) {                    properties.put(keys[i], img.getProperty(keys[i]));                }            }            BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties);            img.copyData(raster);            image=result;        }        drawImage(image, xform, null);    }        /**     * @see Graphics2D#drawRenderableImage(RenderableImage, AffineTransform)     */    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {        drawRenderedImage(img.createDefaultRendering(), xform);    }        /**     * @see Graphics#drawString(String, int, int)     */    public void drawString(String s, int x, int y) {        drawString(s, (float)x, (float)y);    }        /**     * Calculates position and/or stroke thickness depending on the font size     * @param d value to be converted     * @param i font size     * @return position and/or stroke thickness depending on the font size     */    public static double asPoints(double d, int i) {        return d * i / AFM_DIVISOR;    }    /**     * This routine goes through the attributes and sets the font     * before calling the actual string drawing routine     * @param iter     */    protected void doAttributes(AttributedCharacterIterator iter) {        underline = false;        Set set = iter.getAttributes().keySet();        for(Iterator iterator = set.iterator(); iterator.hasNext();) {            AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute)iterator.next();            if (!(attribute instanceof TextAttribute))                continue;            TextAttribute textattribute = (TextAttribute)attribute;            if(textattribute.equals(TextAttribute.FONT)) {                Font font = (Font)iter.getAttributes().get(textattribute);                setFont(font);            }            else if(textattribute.equals(TextAttribute.UNDERLINE)) {                if(iter.getAttributes().get(textattribute) == TextAttribute.UNDERLINE_ON)                    underline = true;            }            else if(textattribute.equals(TextAttribute.SIZE)) {                Object obj = iter.getAttributes().get(textattribute);                if(obj instanceof Integer) {                    int i = ((Integer)obj).intValue();                    setFont(getFont().deriveFont(getFont().getStyle(), i));                }                else if(obj instanceof Float) {                    float f = ((Float)obj).floatValue();                    setFont(getFont().deriveFont(getFont().getStyle(), f));                }            }            else if(textattribute.equals(TextAttribute.FOREGROUND)) {                setColor((Color) iter.getAttributes().get(textattribute));            }            else if(textattribute.equals(TextAttribute.FAMILY)) {              Font font = getFont();              Map fontAttributes = font.getAttributes();              fontAttributes.put(TextAttribute.FAMILY, iter.getAttributes().get(textattribute));              setFont(font.deriveFont(fontAttributes));            }            else if(textattribute.equals(TextAttribute.POSTURE)) {              Font font = getFont();              Map fontAttributes = font.getAttributes();              fontAttributes.put(TextAttribute.POSTURE, iter.getAttributes().get(textattribute));              setFont(font.deriveFont(fontAttributes));             }            else if(textattribute.equals(TextAttribute.WEIGHT)) {              Font font = getFont();              Map fontAttributes = font.getAttributes();              fontAttributes.put(TextAttribute.WEIGHT, iter.getAttributes().get(textattribute));              setFont(font.deriveFont(fontAttributes));             }        }    }    /**     * @see Graphics2D#drawString(String, float, float)     */    public void drawString(String s, float x, float y) {        if (s.length() == 0)            return;        setFillPaint();        if (onlyShapes) {            drawGlyphVector(this.font.layoutGlyphVector(getFontRenderContext(), s.toCharArray(), 0, s.length(), java.awt.Font.LAYOUT_LEFT_TO_RIGHT), x, y);//            Use the following line to compile in JDK 1.3    //            drawGlyphVector(this.font.createGlyphVector(getFontRenderContext(), s), x, y);        }        else {        	boolean restoreTextRenderingMode = false;            AffineTransform at = getTransform();            AffineTransform at2 = getTransform();            at2.translate(x, y);            at2.concatenate(font.getTransform());            setTransform(at2);            AffineTransform inverse = this.normalizeMatrix();            AffineTransform flipper = AffineTransform.getScaleInstance(1,-1);            inverse.concatenate(flipper);            double[] mx = new double[6];            inverse.getMatrix(mx);            cb.beginText();            cb.setFontAndSize(baseFont, fontSize);            // Check if we need to simulate an italic font.            // When there are different fonts for italic, bold, italic bold            // the font.getName() will be different from the font.getFontName()            // value. When they are the same value then we are normally dealing            // with a single font that has been made into an italic or bold            // font.            if (font.isItalic() && font.getFontName().equals(font.getName())) {                float angle = baseFont.getFontDescriptor(BaseFont.ITALICANGLE, 1000);                float angle2 = font.getItalicAngle();                // We don't have an italic version of this font so we need                // to set the font angle ourselves to produce an italic font.                if (angle2 == 0) {                    // The JavaVM didn't have an angle setting for making                    // the font an italic font so use a default of                    // italic angle of 15 degrees.                    angle2 = 15.0f;                } else {                    // This sign of the angle for Java and PDF seams                    // seams to be reversed.                    angle2 = -angle2;                }                if (angle == 0) {                    mx[2] = angle2 / 100.0f;                }            }             cb.setTextMatrix((float)mx[0], (float)mx[1], (float)mx[2], (float)mx[3], (float)mx[4], (float)mx[5]);            Float fontTextAttributeWidth = (Float)font.getAttributes().get(TextAttribute.WIDTH);            fontTextAttributeWidth = (fontTextAttributeWidth == null)                                     ? TextAttribute.WIDTH_REGULAR                                     : fontTextAttributeWidth;            if (!TextAttribute.WIDTH_REGULAR.equals(fontTextAttributeWidth))                cb.setHorizontalScaling(100.0f / fontTextAttributeWidth.floatValue());			            // Check if we need to simulate a bold font.            // Do nothing if the BaseFont is already bold. This test is not foolproof but it will work most of the times.            if (baseFont.getPostscriptFontName().toLowerCase().indexOf("bold") < 0) {                 // Get the weight of the font so we can detect fonts with a weight                // that makes them bold, but the Font.isBold() value is false.                Float weight = (Float) font.getAttributes().get(TextAttribute.WEIGHT);                if (weight == null) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?