You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by pb...@apache.org on 2002/08/31 17:17:29 UTC

cvs commit: xml-fop/src/org/apache/fop/svg PDFGraphics2D.java

pbwest      2002/08/31 08:17:29

  Modified:    src/org/apache/fop/svg Tag: fop-0_20_2-maintain
                        PDFGraphics2D.java
  Log:
  Stripped CRs
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.20.2.7  +1421 -1421xml-fop/src/org/apache/fop/svg/PDFGraphics2D.java
  
  Index: PDFGraphics2D.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/org/apache/fop/svg/PDFGraphics2D.java,v
  retrieving revision 1.20.2.6
  retrieving revision 1.20.2.7
  diff -u -r1.20.2.6 -r1.20.2.7
  --- PDFGraphics2D.java	2 Aug 2002 20:28:58 -0000	1.20.2.6
  +++ PDFGraphics2D.java	31 Aug 2002 15:17:28 -0000	1.20.2.7
  @@ -1,1421 +1,1421 @@
  -/*
  - * $Id$
  - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  - * For details on use and redistribution please refer to the
  - * LICENSE file included with these sources.
  - */
  -
  -package org.apache.fop.svg;
  -
  -import org.apache.fop.apps.FOPException;
  -import org.apache.fop.datatypes.ColorSpace;
  -import org.apache.fop.fonts.*;
  -import org.apache.fop.image.*;
  -import org.apache.fop.layout.*;
  -import org.apache.fop.pdf.*;
  -import org.apache.fop.render.pdf.*;
  -import org.apache.fop.render.pdf.CIDFont;
  -import org.apache.fop.render.pdf.fonts.LazyFont;
  -
  -import org.apache.batik.ext.awt.g2d.*;
  -import org.apache.batik.ext.awt.image.GraphicsUtil;
  -
  -import java.awt.*;
  -import java.awt.Font;
  -import java.awt.Image;
  -import java.awt.font.*;
  -import java.awt.geom.*;
  -import java.awt.image.*;
  -import java.awt.image.renderable.*;
  -import java.io.*;
  -import java.text.AttributedCharacterIterator;
  -import java.text.CharacterIterator;
  -import java.util.ArrayList;
  -import java.util.HashMap;
  -import java.util.Map;
  -
  -/**
  - * This concrete implementation of <tt>AbstractGraphics2D</tt> is a
  - * simple help to programmers to get started with their own
  - * implementation of <tt>Graphics2D</tt>.
  - * <tt>DefaultGraphics2D</tt> implements all the abstract methods
  - * is <tt>AbstractGraphics2D</tt> and makes it easy to start
  - * implementing a <tt>Graphic2D</tt> piece-meal.
  - *
  - * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
  - * @version $Id$
  - * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D
  - */
  -public class PDFGraphics2D extends AbstractGraphics2D {
  -    boolean standalone = false;
  -
  -    /**
  -     * the PDF Document being created
  -     */
  -    protected PDFDocument pdfDoc;
  -
  -    /**
  -     * the current annotation list to add annotations to
  -     */
  -    PDFAnnotList currentAnnotList = null;
  -
  -    protected FontState fontState;
  -    protected FontState ovFontState = null;
  -
  -    /**
  -     * the current stream to add PDF commands to
  -     */
  -    StringWriter currentStream = new StringWriter();
  -
  -    /**
  -     * the current (internal) font name
  -     */
  -    protected String currentFontName;
  -
  -    /**
  -     * the current font size in millipoints
  -     */
  -    protected int currentFontSize;
  -
  -    /**
  -     * the current vertical position in millipoints from bottom
  -     */
  -    protected int currentYPosition = 0;
  -
  -    /**
  -     * the current horizontal position in millipoints from left
  -     */
  -    protected int currentXPosition = 0;
  -
  -    /**
  -     * the current colour for use in svg
  -     */
  -    PDFColor currentColour = new PDFColor(0, 0, 0);
  -
  -    /**
  -     * A registry of images that have already been drawn. They are mapped to 
  -     * a structure with the PDF xObjectNum, width and height. This
  -     * prevents multiple copies from being stored, which can greatly
  -     * reduce the size of a PDF graphic that uses the same image over and over
  -     * (e.g. graphic bullets, map icons, etc.).
  -     */
  -    private HashMap imageInfos = new HashMap();
  -    private static class ImageInfo {
  -        public int width;
  -        public int height;
  -        public int xObjectNum;
  -    }
  -
  -    /**
  -     * Create a new PDFGraphics2D with the given pdf document info.
  -     * This is used to create a Graphics object for use inside an already
  -     * existing document.
  -     */
  -    public PDFGraphics2D(boolean textAsShapes, FontState fs, PDFDocument doc,
  -                         String font, int size, int xpos, int ypos) {
  -        super(textAsShapes);
  -        pdfDoc = doc;
  -        currentFontName = font;
  -        currentFontSize = size;
  -        currentYPosition = ypos;
  -        currentXPosition = xpos;
  -        fontState = fs;
  -    }
  -
  -    public PDFGraphics2D(boolean textAsShapes) {
  -        super(textAsShapes);
  -    }
  -
  -    public String getString() {
  -        return currentStream.toString();
  -    }
  -
  -    public void setGraphicContext(GraphicContext c) {
  -        gc = c;
  -    }
  -
  -    public void setOverrideFontState(FontState infont) {
  -        ovFontState = infont;
  -    }
  -
  -    /**
  -     * This constructor supports the create method
  -     */
  -    public PDFGraphics2D(PDFGraphics2D g) {
  -        super(g);
  -    }
  -
  -    /**
  -     * Creates a new <code>Graphics</code> object that is
  -     * a copy of this <code>Graphics</code> object.
  -     * @return     a new graphics context that is a copy of
  -     * this graphics context.
  -     */
  -    public Graphics create() {
  -        return new PDFGraphics2D(this);
  -    }
  -
  -    /**
  -     * This is a pdf specific method used to add a link to the
  -     * pdf document.
  -     */
  -    public void addLink(Shape bounds, AffineTransform trans, String dest, int linkType) {
  -        if(currentAnnotList == null) {
  -            currentAnnotList = pdfDoc.makeAnnotList();
  -        }
  -        AffineTransform at = getTransform();
  -        Shape b = at.createTransformedShape(bounds);
  -        b = trans.createTransformedShape(b);
  -        Rectangle rect = b.getBounds();
  -        // this handles the / 1000 in PDFLink
  -        rect.x = rect.x * 1000;
  -        rect.y = rect.y * 1000;
  -        rect.height = -rect.height * 1000;
  -        rect.width = rect.width * 1000;
  -        if(linkType != LinkSet.EXTERNAL) {
  -            String pdfdest = "/XYZ " + dest;
  -            currentAnnotList.addLink(pdfDoc.makeLinkCurrentPage(rect, pdfdest));
  -        } else {
  -            currentAnnotList.addLink(pdfDoc.makeLink(rect,
  -                                                 dest, linkType));
  -        }
  -    }
  -
  -    public PDFAnnotList getAnnotList() {
  -        return currentAnnotList;
  -    }
  -
  -    public void addJpegImage(JpegImage jpeg, float x, float y, float width, float height) {
  -        int xObjectNum = this.pdfDoc.addImage(jpeg);
  -
  -        AffineTransform at = getTransform();
  -        double[] matrix = new double[6];
  -        at.getMatrix(matrix);
  -        currentStream.write("q\n");
  -        Shape imclip = getClip();
  -        writeClip(imclip);
  -        currentStream.write("" + matrix[0] + " " + matrix[1] + " "
  -                            + matrix[2] + " " + matrix[3] + " "
  -                            + matrix[4] + " " + matrix[5] + " cm\n");
  -
  -        currentStream.write("" + width + " 0 0 "
  -                          + (-height) + " "
  -                          + x + " "
  -                          + (y + height) + " cm\n" + "/Im"
  -                          + xObjectNum + " Do\nQ\n");
  -    }
  -
  -    /**
  -     * Draws as much of the specified image as is currently available.
  -     * The image is drawn with its top-left corner at
  -     * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
  -     * space. Transparent pixels in the image do not affect whatever
  -     * pixels are already there.
  -     * <p>
  -     * This method returns immediately in all cases, even if the
  -     * complete image has not yet been loaded, and it has not been dithered
  -     * and converted for the current output device.
  -     * <p>
  -     * If the image has not yet been completely loaded, then
  -     * <code>drawImage</code> returns <code>false</code>. As more of
  -     * the image becomes available, the process that draws the image notifies
  -     * the specified image observer.
  -     * @param    img the specified image to be drawn.
  -     * @param    x   the <i>x</i> coordinate.
  -     * @param    y   the <i>y</i> coordinate.
  -     * @param    observer    object to be notified as more of
  -     * the image is converted.
  -     * @see      java.awt.Image
  -     * @see      java.awt.image.ImageObserver
  -     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  -     */
  -    public boolean drawImage(Image img, int x, int y,
  -                             ImageObserver observer) {
  -        // System.err.println("drawImage:x, y");
  -
  -        // first we look to see if we've already added this image to 
  -        // the pdf document. If so, we just reuse the reference;
  -        // otherwise we have to build a FopImage and add it to the pdf
  -        // document
  -        ImageInfo imageInfo = (ImageInfo)imageInfos.get(img);
  -        if (imageInfo == null) {
  -            // OK, have to build and add a PDF image
  -            imageInfo = new ImageInfo();
  -            imageInfo.width = img.getWidth(observer);
  -            imageInfo.height = img.getHeight(observer);
  -            
  -            if (imageInfo.width == -1 || imageInfo.height == -1) {
  -                return false;
  -            }
  -            
  -            Dimension size = new Dimension(imageInfo.width * 3, imageInfo.height * 3);
  -            BufferedImage buf = buildBufferedImage(size);
  -            
  -            java.awt.Graphics2D g = buf.createGraphics();
  -            g.setComposite(AlphaComposite.SrcOver);
  -            g.setBackground(new Color(1, 1, 1, 0));
  -            g.setPaint(new Color(1, 1, 1, 0));
  -            g.fillRect(0, 0, imageInfo.width * 3, imageInfo.height * 3);
  -            g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
  -            
  -            if (!g.drawImage(img, 0, 0, buf.getWidth(), buf.getHeight(), observer)) {
  -                return false;
  -            }
  -            g.dispose();
  -            
  -            final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3];
  -            final byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
  -            
  -            Raster raster = buf.getData();
  -            DataBuffer bd = raster.getDataBuffer();
  -                
  -            int count = 0;
  -            int maskpos = 0;
  -            int[] iarray;
  -            int i, j, val, alpha, add, mult;
  -            switch (bd.getDataType()) {
  -            case DataBuffer.TYPE_INT:
  -                int[][] idata = ((DataBufferInt)bd).getBankData();
  -                for (i = 0; i < idata.length; i++) {
  -                    iarray = idata[i];
  -                    for (j = 0; j < iarray.length; j++) {
  -                        val = iarray[j];
  -                        alpha = val >>> 24;
  -                        // mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF);
  -                        if (alpha != 255) {
  -                            // System.out.println("Alpha: " + alpha);
  -                            // Composite with opaque white...
  -                            add = (255 - alpha);
  -                            mult = (alpha << 16) / 255;
  -                            result[count++] =
  -                                (byte)(add
  -                                       + ((((val >> 16) & 0xFF) * mult) >> 16));
  -                            result[count++] =
  -                                (byte)(add
  -                                       + ((((val >> 8) & 0xFF) * mult) >> 16));
  -                            result[count++] = (byte)(add
  -                                                     + ((((val) & 0xFF) * mult)
  -                                                        >> 16));
  -                        } else {
  -                            result[count++] = (byte)((val >> 16) & 0xFF);
  -                            result[count++] = (byte)((val >> 8) & 0xFF);
  -                            result[count++] = (byte)((val) & 0xFF);
  -                        }
  -                    }
  -                }
  -                break;
  -            default:
  -                // error
  -                break;
  -                }
  -            
  -            try {
  -                FopImage fopimg = new TempImage("TempImage:" + img.toString(), buf.getWidth(), buf.getHeight(), result, mask);
  -                imageInfo.xObjectNum = this.pdfDoc.addImage(fopimg);
  -                imageInfos.put(img, imageInfo);
  -            } catch (Exception e) {
  -                e.printStackTrace();
  -            }
  -        }
  -
  -        // now do any transformation required and add the actual image
  -        // placement instance
  -        AffineTransform at = getTransform();
  -        double[] matrix = new double[6];
  -        at.getMatrix(matrix);
  -        currentStream.write("q\n");
  -        Shape imclip = getClip();
  -        writeClip(imclip);
  -        currentStream.write("" + matrix[0] + " " + matrix[1] + " "
  -                            + matrix[2] + " " + matrix[3] + " "
  -                            + matrix[4] + " " + matrix[5] + " cm\n");
  -        currentStream.write("" + imageInfo.width + " 0 0 " + (-imageInfo.height) + " " + x
  -                            + " " + (y + imageInfo.height) + " cm\n" + "/Im"
  -                            + imageInfo.xObjectNum + " Do\nQ\n");
  -        return true;
  -    }
  -
  -    public BufferedImage buildBufferedImage(Dimension size) {
  -        return new BufferedImage(size.width, size.height,
  -                                 BufferedImage.TYPE_INT_ARGB);
  -    }
  -
  -    class TempImage implements FopImage {
  -        int m_height;
  -        int m_width;
  -        int m_bitsPerPixel;
  -        ColorSpace m_colorSpace;
  -        int m_bitmapSiye;
  -        byte[] m_bitmaps;
  -        byte[] m_mask;
  -        PDFColor transparent = new PDFColor(255, 255, 255);
  -        String url;
  -
  -        TempImage(String url, int width, int height, byte[] result,
  -                  byte[] mask) throws FopImageException {
  -            this.url = url;
  -            this.m_height = height;
  -            this.m_width = width;
  -            this.m_bitsPerPixel = 8;
  -            this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
  -            // this.m_isTransparent = false;
  -            // this.m_bitmapsSize = this.m_width * this.m_height * 3;
  -            this.m_bitmaps = result;
  -            this.m_mask = mask;
  -        }
  -
  -        public boolean invertImage() {
  -            return false;
  -        }
  -
  -        public String getURL() {
  -            return url;
  -        }
  -
  -        // image size
  -        public int getWidth() throws FopImageException {
  -            return m_width;
  -        }
  -
  -        public int getHeight() throws FopImageException {
  -            return m_height;
  -        }
  -
  -        // DeviceGray, DeviceRGB, or DeviceCMYK
  -        public ColorSpace getColorSpace() throws FopImageException {
  -            return m_colorSpace;
  -        }
  -
  -        // bits per pixel
  -        public int getBitsPerPixel() throws FopImageException {
  -            return m_bitsPerPixel;
  -        }
  -
  -        // For transparent images
  -        public boolean isTransparent() throws FopImageException {
  -            return transparent != null;
  -        }
  -
  -        public PDFColor getTransparentColor() throws FopImageException {
  -            return transparent;
  -        }
  -
  -        public byte[] getMask() throws FopImageException {
  -            return m_mask;
  -        }
  -
  -        // get the image bytes, and bytes properties
  -
  -        // get uncompressed image bytes
  -        public byte[] getBitmaps() throws FopImageException {
  -            return m_bitmaps;
  -        }
  -
  -        // width * (bitsPerPixel / 8) * height, no ?
  -        public int getBitmapsSize() throws FopImageException {
  -            return m_width * m_height * 3;
  -        }
  -
  -        // get compressed image bytes
  -        // I don't know if we really need it, nor if it
  -        // should be changed...
  -        public byte[] getRessourceBytes() throws FopImageException {
  -            return null;
  -        }
  -
  -        public int getRessourceBytesSize() throws FopImageException {
  -            return 0;
  -        }
  -
  -        // return null if no corresponding PDFFilter
  -        public PDFFilter getPDFFilter() throws FopImageException {
  -            return null;
  -        }
  -
  -        // release memory
  -        public void close() {}
  -
  -    }
  -
  -
  -    /**
  -     * Draws as much of the specified image as has already been scaled
  -     * to fit inside the specified rectangle.
  -     * <p>
  -     * The image is drawn inside the specified rectangle of this
  -     * graphics context's coordinate space, and is scaled if
  -     * necessary. Transparent pixels do not affect whatever pixels
  -     * are already there.
  -     * <p>
  -     * This method returns immediately in all cases, even if the
  -     * entire image has not yet been scaled, dithered, and converted
  -     * for the current output device.
  -     * If the current output representation is not yet complete, then
  -     * <code>drawImage</code> returns <code>false</code>. As more of
  -     * the image becomes available, the process that draws the image notifies
  -     * the image observer by calling its <code>imageUpdate</code> method.
  -     * <p>
  -     * A scaled version of an image will not necessarily be
  -     * available immediately just because an unscaled version of the
  -     * image has been constructed for this output device.  Each size of
  -     * the image may be cached separately and generated from the original
  -     * data in a separate image production sequence.
  -     * @param    img    the specified image to be drawn.
  -     * @param    x      the <i>x</i> coordinate.
  -     * @param    y      the <i>y</i> coordinate.
  -     * @param    width  the width of the rectangle.
  -     * @param    height the height of the rectangle.
  -     * @param    observer    object to be notified as more of
  -     * the image is converted.
  -     * @see      java.awt.Image
  -     * @see      java.awt.image.ImageObserver
  -     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  -     */
  -    public boolean drawImage(Image img, int x, int y, int width, int height,
  -                             ImageObserver observer) {
  -        System.out.println("drawImage");
  -        return true;
  -    }
  -
  -    /**
  -     * Disposes of this graphics context and releases
  -     * any system resources that it is using.
  -     * A <code>Graphics</code> object cannot be used after
  -     * <code>dispose</code>has been called.
  -     * <p>
  -     * When a Java program runs, a large number of <code>Graphics</code>
  -     * objects can be created within a short time frame.
  -     * Although the finalization process of the garbage collector
  -     * also disposes of the same system resources, it is preferable
  -     * to manually free the associated resources by calling this
  -     * method rather than to rely on a finalization process which
  -     * may not run to completion for a long period of time.
  -     * <p>
  -     * Graphics objects which are provided as arguments to the
  -     * <code>paint</code> and <code>update</code> methods
  -     * of components are automatically released by the system when
  -     * those methods return. For efficiency, programmers should
  -     * call <code>dispose</code> when finished using
  -     * a <code>Graphics</code> object only if it was created
  -     * directly from a component or another <code>Graphics</code> object.
  -     * @see         java.awt.Graphics#finalize
  -     * @see         java.awt.Component#paint
  -     * @see         java.awt.Component#update
  -     * @see         java.awt.Component#getGraphics
  -     * @see         java.awt.Graphics#create
  -     */
  -    public void dispose() {
  -        // System.out.println("dispose");
  -        pdfDoc = null;
  -        fontState = null;
  -        currentStream = null;
  -        currentFontName = null;
  -        currentColour = null;
  -    }
  -
  -    /**
  -     * Strokes the outline of a <code>Shape</code> using the settings of the
  -     * current <code>Graphics2D</code> context.  The rendering attributes
  -     * applied include the <code>Clip</code>, <code>Transform</code>,
  -     * <code>Paint</code>, <code>Composite</code> and
  -     * <code>Stroke</code> attributes.
  -     * @param s the <code>Shape</code> to be rendered
  -     * @see #setStroke
  -     * @see #setPaint
  -     * @see java.awt.Graphics#setColor
  -     * @see #transform
  -     * @see #setTransform
  -     * @see #clip
  -     * @see #setClip
  -     * @see #setComposite
  -     */
  -    public void draw(Shape s) {
  -        // System.out.println("draw(Shape)");
  -        Color c;
  -        c = getColor();
  -        if(c.getAlpha() == 0) {
  -            return;
  -        }
  -
  -        currentStream.write("q\n");
  -        Shape imclip = getClip();
  -        writeClip(imclip);
  -        applyColor(c, false);
  -
  -        applyPaint(getPaint(), false);
  -        applyStroke(getStroke());
  -
  -        AffineTransform trans = getTransform();
  -        double[] tranvals = new double[6];
  -        trans.getMatrix(tranvals);
  -        currentStream.write(PDFNumber.doubleOut(tranvals[0]) + " "
  -                            + PDFNumber.doubleOut(tranvals[1]) + " "
  -                            + PDFNumber.doubleOut(tranvals[2]) + " "
  -                            + PDFNumber.doubleOut(tranvals[3]) + " "
  -                            + PDFNumber.doubleOut(tranvals[4]) + " "
  -                            + PDFNumber.doubleOut(tranvals[5]) + " cm\n");
  -
  -        PathIterator iter = s.getPathIterator(new AffineTransform());
  -        while (!iter.isDone()) {
  -            double vals[] = new double[6];
  -            int type = iter.currentSegment(vals);
  -            switch (type) {
  -            case PathIterator.SEG_CUBICTO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " "
  -                                    + PDFNumber.doubleOut(vals[2]) + " "
  -                                    + PDFNumber.doubleOut(vals[3]) + " "
  -                                    + PDFNumber.doubleOut(vals[4]) + " "
  -                                    + PDFNumber.doubleOut(vals[5]) + " c\n");
  -                break;
  -            case PathIterator.SEG_LINETO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " l\n");
  -                break;
  -            case PathIterator.SEG_MOVETO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " m\n");
  -                break;
  -            case PathIterator.SEG_QUADTO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " "
  -                                    + PDFNumber.doubleOut(vals[2]) + " "
  -                                    + PDFNumber.doubleOut(vals[3]) + " y\n");
  -                break;
  -            case PathIterator.SEG_CLOSE:
  -                currentStream.write("h\n");
  -                break;
  -            default:
  -                break;
  -            }
  -            iter.next();
  -        }
  -        doDrawing(false, true, false);
  -        currentStream.write("Q\n");
  -    }
  -
  -    protected void writeClip(Shape s) {
  -        if (s == null) {
  -            return;
  -        }
  -        PathIterator iter = s.getPathIterator(getTransform());
  -        while (!iter.isDone()) {
  -            double vals[] = new double[6];
  -            int type = iter.currentSegment(vals);
  -            switch (type) {
  -            case PathIterator.SEG_CUBICTO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " "
  -                                    + PDFNumber.doubleOut(vals[2]) + " "
  -                                    + PDFNumber.doubleOut(vals[3]) + " "
  -                                    + PDFNumber.doubleOut(vals[4]) + " "
  -                                    + PDFNumber.doubleOut(vals[5]) + " c\n");
  -                break;
  -            case PathIterator.SEG_LINETO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " l\n");
  -                break;
  -            case PathIterator.SEG_MOVETO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " m\n");
  -                break;
  -            case PathIterator.SEG_QUADTO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " "
  -                                    + PDFNumber.doubleOut(vals[2]) + " "
  -                                    + PDFNumber.doubleOut(vals[3]) + " y\n");
  -                break;
  -            case PathIterator.SEG_CLOSE:
  -                currentStream.write("h\n");
  -                break;
  -            default:
  -                break;
  -            }
  -            iter.next();
  -        }
  -        // clip area
  -        currentStream.write("W\n");
  -        currentStream.write("n\n");
  -    }
  -
  -    protected void applyColor(Color col, boolean fill) {
  -        Color c = col;
  -        if (c.getColorSpace().getType()
  -                == java.awt.color.ColorSpace.TYPE_RGB) {
  -            currentColour = new PDFColor(c.getRed(), c.getGreen(),
  -                                         c.getBlue());
  -            currentStream.write(currentColour.getColorSpaceOut(fill));
  -        } else if (c.getColorSpace().getType()
  -                   == java.awt.color.ColorSpace.TYPE_CMYK) {
  -            float[] cComps = c.getColorComponents(new float[3]);
  -            double[] cmyk = new double[3];
  -            for (int i = 0; i < 3; i++) {
  -                // convert the float elements to doubles for pdf
  -                cmyk[i] = cComps[i];
  -            }
  -            currentColour = new PDFColor(cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
  -            currentStream.write(currentColour.getColorSpaceOut(fill));
  -        } else if (c.getColorSpace().getType()
  -                   == java.awt.color.ColorSpace.TYPE_2CLR) {
  -            // used for black/magenta
  -            float[] cComps = c.getColorComponents(new float[1]);
  -            double[] blackMagenta = new double[1];
  -            for (int i = 0; i < 1; i++) {
  -                blackMagenta[i] = cComps[i];
  -            }
  -            // currentColour = new PDFColor(blackMagenta[0], blackMagenta[1]);
  -            currentStream.write(currentColour.getColorSpaceOut(fill));
  -        } else {
  -            System.err.println("Color Space not supported by PDFGraphics2D");
  -        }
  -    }
  -
  -    protected void applyPaint(Paint paint, boolean fill) {
  -        if (paint instanceof GradientPaint) {
  -            GradientPaint gp = (GradientPaint)paint;
  -            Color c1 = gp.getColor1();
  -            Color c2 = gp.getColor2();
  -            Point2D p1 = gp.getPoint1();
  -            Point2D p2 = gp.getPoint2();
  -            boolean cyclic = gp.isCyclic();
  -
  -            ArrayList theCoords = new ArrayList();
  -            theCoords.add(new Double(p1.getX()));
  -            theCoords.add(new Double(p1.getY()));
  -            theCoords.add(new Double(p2.getX()));
  -            theCoords.add(new Double(p2.getY()));
  -
  -            ArrayList theExtend = new ArrayList();
  -            theExtend.add(new Boolean(true));
  -            theExtend.add(new Boolean(true));
  -
  -            ArrayList theDomain = new ArrayList();
  -            theDomain.add(new Double(0));
  -            theDomain.add(new Double(1));
  -
  -            ArrayList theEncode = new ArrayList();
  -            theEncode.add(new Double(0));
  -            theEncode.add(new Double(1));
  -            theEncode.add(new Double(0));
  -            theEncode.add(new Double(1));
  -
  -            ArrayList theBounds = new ArrayList();
  -            theBounds.add(new Double(0));
  -            theBounds.add(new Double(1));
  -
  -            ArrayList theFunctions = new ArrayList();
  -
  -            ArrayList someColors = new ArrayList();
  -
  -            PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(),
  -                                           c1.getBlue());
  -            someColors.add(color1);
  -            PDFColor color2 = new PDFColor(c2.getRed(), c2.getGreen(),
  -                                           c2.getBlue());
  -            someColors.add(color2);
  -
  -            PDFFunction myfunc = this.pdfDoc.makeFunction(2, theDomain, null,
  -                    color1.getVector(), color2.getVector(), 1.0);
  -
  -            ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
  -            PDFPattern myPat = this.pdfDoc.createGradient(false, aColorSpace,
  -                    someColors, null, theCoords);
  -            currentStream.write(myPat.getColorSpaceOut(fill));
  -
  -        } else if (paint instanceof TexturePaint) {}
  -    }
  -
  -    protected void applyStroke(Stroke stroke) {
  -        if (stroke instanceof BasicStroke) {
  -            BasicStroke bs = (BasicStroke)stroke;
  -
  -            float[] da = bs.getDashArray();
  -            if (da != null) {
  -                currentStream.write("[");
  -                for (int count = 0; count < da.length; count++) {
  -                    if(((int)da[count]) == 0) {
  -                        // the dasharray units in pdf are (whole) numbers
  -                        // in user space units, cannot be 0
  -                        currentStream.write("1");
  -                    } else {
  -                        currentStream.write("" + ((int)da[count]));
  -                    }
  -                    if (count < da.length - 1) {
  -                        currentStream.write(" ");
  -                    }
  -                }
  -                currentStream.write("] ");
  -                float offset = bs.getDashPhase();
  -                currentStream.write(((int)offset) + " d\n");
  -            }
  -            int ec = bs.getEndCap();
  -            switch (ec) {
  -            case BasicStroke.CAP_BUTT:
  -                currentStream.write(0 + " J\n");
  -                break;
  -            case BasicStroke.CAP_ROUND:
  -                currentStream.write(1 + " J\n");
  -                break;
  -            case BasicStroke.CAP_SQUARE:
  -                currentStream.write(2 + " J\n");
  -                break;
  -            }
  -
  -            int lj = bs.getLineJoin();
  -            switch (lj) {
  -            case BasicStroke.JOIN_MITER:
  -                currentStream.write(0 + " j\n");
  -                break;
  -            case BasicStroke.JOIN_ROUND:
  -                currentStream.write(1 + " j\n");
  -                break;
  -            case BasicStroke.JOIN_BEVEL:
  -                currentStream.write(2 + " j\n");
  -                break;
  -            }
  -            float lw = bs.getLineWidth();
  -            currentStream.write(PDFNumber.doubleOut(lw) + " w\n");
  -
  -            float ml = bs.getMiterLimit();
  -            currentStream.write(PDFNumber.doubleOut(ml) + " M\n");
  -        }
  -    }
  -
  -    /**
  -     * Renders a {@link RenderedImage},
  -     * applying a transform from image
  -     * space into user space before drawing.
  -     * The transformation from user space into device space is done with
  -     * the current <code>Transform</code> in the <code>Graphics2D</code>.
  -     * The specified transformation is applied to the image before the
  -     * transform attribute in the <code>Graphics2D</code> context is applied.
  -     * The rendering attributes applied include the <code>Clip</code>,
  -     * <code>Transform</code>, and <code>Composite</code> attributes. Note
  -     * that no rendering is done if the specified transform is
  -     * noninvertible.
  -     * @param img the image to be rendered
  -     * @param xform the transformation from image space into user space
  -     * @see #transform
  -     * @see #setTransform
  -     * @see #setComposite
  -     * @see #clip
  -     * @see #setClip
  -     */
  -    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
  -        System.out.println("drawRenderedImage");
  -    }
  -
  -
  -    /**
  -     * Renders a
  -     * {@link RenderableImage},
  -     * applying a transform from image space into user space before drawing.
  -     * The transformation from user space into device space is done with
  -     * the current <code>Transform</code> in the <code>Graphics2D</code>.
  -     * The specified transformation is applied to the image before the
  -     * transform attribute in the <code>Graphics2D</code> context is applied.
  -     * The rendering attributes applied include the <code>Clip</code>,
  -     * <code>Transform</code>, and <code>Composite</code> attributes. Note
  -     * that no rendering is done if the specified transform is
  -     * noninvertible.
  -     * <p>
  -     * Rendering hints set on the <code>Graphics2D</code> object might
  -     * be used in rendering the <code>RenderableImage</code>.
  -     * If explicit control is required over specific hints recognized by a
  -     * specific <code>RenderableImage</code>, or if knowledge of which hints
  -     * are used is required, then a <code>RenderedImage</code> should be
  -     * obtained directly from the <code>RenderableImage</code>
  -     * and rendered using
  -     * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.
  -     * @param img the image to be rendered
  -     * @param xform the transformation from image space into user space
  -     * @see #transform
  -     * @see #setTransform
  -     * @see #setComposite
  -     * @see #clip
  -     * @see #setClip
  -     * @see #drawRenderedImage
  -     */
  -    public void drawRenderableImage(RenderableImage img,
  -                                    AffineTransform xform) {
  -        System.out.println("drawRenderableImage");
  -    }
  -
  -    /**
  -     * Renders the text specified by the specified <code>String</code>,
  -     * using the current <code>Font</code> and <code>Paint</code> attributes
  -     * in the <code>Graphics2D</code> context.
  -     * The baseline of the first character is at position
  -     * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
  -     * The rendering attributes applied include the <code>Clip</code>,
  -     * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
  -     * <code>Composite</code> attributes. For characters in script systems
  -     * such as Hebrew and Arabic, the glyphs can be rendered from right to
  -     * left, in which case the coordinate supplied is the location of the
  -     * leftmost character on the baseline.
  -     * @param s the <code>String</code> to be rendered
  -     * @param x,&nbsp;y the coordinates where the <code>String</code>
  -     * should be rendered
  -     * @see #setPaint
  -     * @see java.awt.Graphics#setColor
  -     * @see java.awt.Graphics#setFont
  -     * @see #setTransform
  -     * @see #setComposite
  -     * @see #setClip
  -     */
  -    public void drawString(String s, float x, float y) {
  -        // System.out.println("drawString(String)");
  -
  -        if(ovFontState == null) {
  -            Font gFont = getFont();
  -            String n = gFont.getFamily();
  -            if (n.equals("sanserif")) {
  -                n = "sans-serif";
  -            }
  -            int siz = gFont.getSize();
  -            String style = gFont.isItalic() ? "italic" : "normal";
  -            String weight = gFont.isBold() ? "bold" : "normal";
  -            try {
  -                fontState = new FontState(fontState.getFontInfo(), n, style,
  -                                          weight, siz * 1000, 0);
  -            } catch (org.apache.fop.apps.FOPException fope) {
  -                fope.printStackTrace();
  -            }
  -        } else {
  -            fontState = ovFontState;
  -            ovFontState = null;
  -        }       
  -        String name;
  -        int size;
  -        name = fontState.getFontName();
  -        size = fontState.getFontSize() / 1000;
  -    
  -        if ((!name.equals(this.currentFontName))
  -                || (size != this.currentFontSize)) {
  -            this.currentFontName = name; 
  -            this.currentFontSize = size;
  -            currentStream.write("/" + name + " " + size + " Tf\n");
  -
  -        }
  -
  -        currentStream.write("q\n");
  -
  -        Shape imclip = getClip();
  -        writeClip(imclip);
  -        Color c = getColor();
  -        applyColor(c, true);
  -        c = getBackground();
  -        applyColor(c, false);
  -
  -        currentStream.write("BT\n");
  -
  -        HashMap kerning = null;
  -        boolean kerningAvailable = false;
  -
  -        kerning = fontState.getKerning();
  -        if (kerning != null &&!kerning.isEmpty()) {
  -            kerningAvailable = true;
  -        }
  -
  -        // This assumes that *all* CIDFonts use a /ToUnicode mapping
  -        boolean useMultiByte = false;
  -        org.apache.fop.render.pdf.Font f =
  -            (org.apache.fop.render.pdf.Font)fontState.getFontInfo().getFonts().get(name);
  -        if (f instanceof LazyFont){
  -            if(((LazyFont) f).getRealFont() instanceof CIDFont){
  -                useMultiByte = true;
  -            }
  -        } else if (f instanceof CIDFont){
  -            useMultiByte = true;
  -        }
  -
  -        // String startText = useMultiByte ? "<FEFF" : "(";
  -        String startText = useMultiByte ? "<" : "(";
  -        String endText = useMultiByte ? "> " : ") ";
  -
  -        AffineTransform trans = getTransform();
  -        trans.translate(x, y);
  -        double[] vals = new double[6];
  -        trans.getMatrix(vals);
  -
  -        currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                            + PDFNumber.doubleOut(vals[1]) + " "
  -                            + PDFNumber.doubleOut(vals[2]) + " "
  -                            + PDFNumber.doubleOut(vals[3]) + " "
  -                            + PDFNumber.doubleOut(vals[4]) + " "
  -                            + PDFNumber.doubleOut(vals[5]) + " cm\n");
  -        currentStream.write("1 0 0 -1 0 0 Tm [" + startText);
  -
  -        int l = s.length();
  -
  -        for (int i = 0; i < l; i++) {
  -            char ch = fontState.mapChar(s.charAt(i));
  -
  -            if (!useMultiByte) {
  -                if (ch > 127) {
  -                    currentStream.write("\\");
  -                    currentStream.write(Integer.toOctalString((int)ch));
  -                } else {
  -                    switch (ch) {
  -                    case '(':
  -                    case ')':
  -                    case '\\':
  -                        currentStream.write("\\");
  -                        break;
  -                    }
  -                    currentStream.write(ch);
  -                }
  -            } else {
  -                currentStream.write(getUnicodeString(ch));
  -            }
  -
  -            if (kerningAvailable && (i + 1) < l) {
  -                addKerning(currentStream, (new Integer((int)ch)),
  -                           (new Integer((int)fontState.mapChar(s.charAt(i + 1)))),
  -                           kerning, startText, endText);
  -            }
  -
  -        }
  -        currentStream.write(endText);
  -
  -
  -        currentStream.write("] TJ\n");
  -
  -        currentStream.write("ET\n");
  -        currentStream.write("Q\n");
  -    }
  -
  -    private void addKerning(StringWriter buf, Integer ch1, Integer ch2,
  -                            HashMap kerning, String startText,
  -                            String endText) {
  -        HashMap kernPair = (HashMap)kerning.get(ch1);
  -
  -        if (kernPair != null) {
  -            Integer width = (Integer)kernPair.get(ch2);
  -            if (width != null) {
  -                currentStream.write(endText + (-width.intValue()) + " " + startText);
  -            }
  -        }
  -    }
  -
  -    /**
  -     * Convert a char to a multibyte hex representation
  -     */
  -    private String getUnicodeString(char c) {
  -
  -        StringBuffer buf = new StringBuffer(4);
  -        byte[] uniBytes = null;
  -        try {
  -            char[] a = {
  -                c
  -            };
  -            uniBytes = new String(a).getBytes("UnicodeBigUnmarked");
  -        } catch (Exception e) {
  -            // This should never fail
  -        }
  -
  -        for (int i = 0; i < uniBytes.length; i++) {
  -            int b = (uniBytes[i] < 0) ? (int)(256 + uniBytes[i])
  -                    : (int)uniBytes[i];
  -
  -            String hexString = Integer.toHexString(b);
  -            if (hexString.length() == 1)
  -                buf = buf.append("0" + hexString);
  -            else
  -                buf = buf.append(hexString);
  -        }
  -
  -        return buf.toString();
  -    }
  -
  -    /**
  -     * Renders the text of the specified iterator, using the
  -     * <code>Graphics2D</code> context's current <code>Paint</code>. The
  -     * iterator must specify a font
  -     * for each character. The baseline of the
  -     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the
  -     * User Space.
  -     * The rendering attributes applied include the <code>Clip</code>,
  -     * <code>Transform</code>, <code>Paint</code>, and
  -     * <code>Composite</code> attributes.
  -     * For characters in script systems such as Hebrew and Arabic,
  -     * the glyphs can be rendered from right to left, in which case the
  -     * coordinate supplied is the location of the leftmost character
  -     * on the baseline.
  -     * @param iterator the iterator whose text is to be rendered
  -     * @param x,&nbsp;y the coordinates where the iterator's text is to be
  -     * rendered
  -     * @see #setPaint
  -     * @see java.awt.Graphics#setColor
  -     * @see #setTransform
  -     * @see #setComposite
  -     * @see #setClip
  -     */
  -    public void drawString(AttributedCharacterIterator iterator, float x,
  -                           float y) {
  -        System.err.println("drawString(AttributedCharacterIterator)");
  -
  -        Shape imclip = getClip();
  -        writeClip(imclip);
  -        Color c = getColor();
  -        applyColor(c, true);
  -        c = getBackground();
  -        applyColor(c, false);
  -
  -        currentStream.write("BT\n");
  -
  -        AffineTransform trans = getTransform();
  -        trans.translate(x, y);
  -        double[] vals = new double[6];
  -        trans.getMatrix(vals);
  -
  -        for (char ch = iterator.first(); ch != CharacterIterator.DONE;
  -                ch = iterator.next()) {
  -            Map attr = iterator.getAttributes();
  -
  -            String name = fontState.getFontName();
  -            int size = fontState.getFontSize();
  -            if ((!name.equals(this.currentFontName))
  -                    || (size != this.currentFontSize)) {
  -                this.currentFontName = name;
  -                this.currentFontSize = size;
  -                currentStream.write("/" + name + " " + (size / 1000)
  -                                    + " Tf\n");
  -
  -            }
  -
  -            currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                + PDFNumber.doubleOut(vals[1]) + " "
  -                                + PDFNumber.doubleOut(vals[2]) + " "
  -                                + PDFNumber.doubleOut(vals[3]) + " "
  -                                + PDFNumber.doubleOut(vals[4]) + " "
  -                                + PDFNumber.doubleOut(vals[5]) + " Tm (" + ch
  -                                + ") Tj\n");
  -        }
  -
  -        currentStream.write("ET\n");
  -    }
  -
  -    /**
  -     * Fills the interior of a <code>Shape</code> using the settings of the
  -     * <code>Graphics2D</code> context. The rendering attributes applied
  -     * include the <code>Clip</code>, <code>Transform</code>,
  -     * <code>Paint</code>, and <code>Composite</code>.
  -     * @param s the <code>Shape</code> to be filled
  -     * @see #setPaint
  -     * @see java.awt.Graphics#setColor
  -     * @see #transform
  -     * @see #setTransform
  -     * @see #setComposite
  -     * @see #clip
  -     * @see #setClip
  -     */
  -    public void fill(Shape s) {
  -        // System.err.println("fill");
  -        Color c;
  -        c = getBackground();
  -        if(c.getAlpha() == 0) {
  -            c = getColor();
  -            if(c.getAlpha() == 0) {
  -                return;
  -            }
  -        }
  -        currentStream.write("q\n");
  -        Shape imclip = getClip();
  -        writeClip(imclip);
  -        c = getColor();
  -        applyColor(c, true);
  -        c = getBackground();
  -        applyColor(c, false);
  -
  -        applyPaint(getPaint(), true);
  -
  -        PathIterator iter = s.getPathIterator(getTransform());
  -        while (!iter.isDone()) {
  -            double vals[] = new double[6];
  -            int type = iter.currentSegment(vals);
  -            switch (type) {
  -            case PathIterator.SEG_CUBICTO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " "
  -                                    + PDFNumber.doubleOut(vals[2]) + " "
  -                                    + PDFNumber.doubleOut(vals[3]) + " "
  -                                    + PDFNumber.doubleOut(vals[4]) + " "
  -                                    + PDFNumber.doubleOut(vals[5]) + " c\n");
  -                break;
  -            case PathIterator.SEG_LINETO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " l\n");
  -                break;
  -            case PathIterator.SEG_MOVETO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " m\n");
  -                break;
  -            case PathIterator.SEG_QUADTO:
  -                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  -                                    + PDFNumber.doubleOut(vals[1]) + " "
  -                                    + PDFNumber.doubleOut(vals[2]) + " "
  -                                    + PDFNumber.doubleOut(vals[3]) + " y\n");
  -                break;
  -            case PathIterator.SEG_CLOSE:
  -                currentStream.write("h\n");
  -                break;
  -            default:
  -                break;
  -            }
  -            iter.next();
  -        }
  -        doDrawing(true, false,
  -                  iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
  -        currentStream.write("Q\n");
  -    }
  -
  -    protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) {
  -        if (fill) {
  -            if (stroke) {
  -                if (nonzero)
  -                    currentStream.write("B*\n");
  -                else
  -                    currentStream.write("B\n");
  -            } else {
  -                if (nonzero)
  -                    currentStream.write("f*\n");
  -                else
  -                    currentStream.write("f\n");
  -            }
  -        } else {
  -            // if(stroke)
  -            currentStream.write("S\n");
  -        }
  -    }
  -
  -    /**
  -     * Returns the device configuration associated with this
  -     * <code>Graphics2D</code>.
  -     */
  -    public GraphicsConfiguration getDeviceConfiguration() {
  -        return new PDFGraphicsConfiguration();
  -    }
  -
  -    /**
  -     * Our implementation of the class that returns information about
  -     * roughly what we can handle and want to see (alpha for example).
  -     */
  -    static class PDFGraphicsConfiguration extends GraphicsConfiguration {
  -        // We use this to get a good colormodel..
  -        static BufferedImage BIWithAlpha = new BufferedImage(1, 1,
  -                BufferedImage.TYPE_INT_ARGB);
  -        // We use this to get a good colormodel..
  -        static BufferedImage BIWithOutAlpha = new BufferedImage(1, 1,
  -                BufferedImage.TYPE_INT_RGB);
  -
  -        /**
  -         * Construct a buffered image with an alpha channel, unless
  -         * transparencty is OPAQUE (no alpha at all).
  -         */
  -        public BufferedImage createCompatibleImage(int width, int height,
  -                                                   int transparency) {
  -            if (transparency == Transparency.OPAQUE)
  -                return new BufferedImage(width, height,
  -                                         BufferedImage.TYPE_INT_RGB);
  -            else
  -                return new BufferedImage(width, height,
  -                                         BufferedImage.TYPE_INT_ARGB);
  -        }
  -
  -        /**
  -         * Construct a buffered image with an alpha channel.
  -         */
  -        public BufferedImage createCompatibleImage(int width, int height) {
  -            return new BufferedImage(width, height,
  -                                     BufferedImage.TYPE_INT_ARGB);
  -        }
  -
  -        /**
  -         * FIXX ME: This should return the page bounds in Pts,
  -         * I couldn't figure out how to get this for the current
  -         * page from the PDFDocument (this still works for now,
  -         * but it should be fixed...).
  -         */
  -        public Rectangle getBounds() {
  -System.out.println("getting getBounds");
  -            return null;
  -        }
  -
  -        /**
  -         * Return a good default color model for this 'device'.
  -         */
  -        public ColorModel getColorModel() {
  -            return BIWithAlpha.getColorModel();
  -        }
  -
  -        /**
  -         * Return a good color model given <tt>transparency</tt>
  -         */
  -        public ColorModel getColorModel(int transparency) {
  -            if (transparency == Transparency.OPAQUE)
  -                return BIWithOutAlpha.getColorModel();
  -            else
  -                return BIWithAlpha.getColorModel();
  -        }
  -
  -        /**
  -         * The default transform (1:1).
  -         */
  -        public AffineTransform getDefaultTransform() {
  -System.out.println("getting getDefaultTransform");
  -            return new AffineTransform();
  -        }
  -
  -        /**
  -         * The normalizing transform (1:1) (since we currently
  -         * render images at 72dpi, which we might want to change
  -         * in the future).
  -         */
  -        public AffineTransform getNormalizingTransform() {
  -System.out.println("getting getNormalizingTransform");
  -            return new AffineTransform(2, 0, 0, 2, 0, 0);
  -        }
  -
  -        /**
  -         * Return our dummy instance of GraphicsDevice
  -         */
  -        public GraphicsDevice getDevice() {
  -            return new PDFGraphicsDevice(this);
  -        }
  -
  -        // needed for compiling under jdk1.4
  -        //public java.awt.image.VolatileImage createCompatibleVolatileImage(int width, int height) {
  -        //    return null;
  -        //}
  -
  -    }
  -
  -    /**
  -     * This implements the GraphicsDevice interface as appropriate for
  -     * a PDFGraphics2D.  This is quite simple since we only have one
  -     * GraphicsConfiguration for now (this might change in the future
  -     * I suppose).
  -     */
  -    static class PDFGraphicsDevice extends GraphicsDevice {
  -
  -        /**
  -         * The Graphics Config that created us...
  -         */
  -        GraphicsConfiguration gc;
  -
  -        /**
  -         * @param The gc we should reference
  -         */
  -        PDFGraphicsDevice(PDFGraphicsConfiguration gc) {
  -            this.gc = gc;
  -        }
  -
  -        /**
  -         * Ignore template and return the only config we have
  -         */
  -        public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) {
  -            return gc;
  -        }
  -
  -        /**
  -         * Return an array of our one GraphicsConfig
  -         */
  -        public GraphicsConfiguration[] getConfigurations() {
  -            return new GraphicsConfiguration[] {
  -                gc
  -            };
  -        }
  -
  -        /**
  -         * Return out sole GraphicsConfig.
  -         */
  -        public GraphicsConfiguration getDefaultConfiguration() {
  -            return gc;
  -        }
  -
  -        /**
  -         * Generate an IdString..
  -         */
  -        public String getIDstring() {
  -            return toString();
  -        }
  -
  -        /**
  -         * Let the caller know that we are "a printer"
  -         */
  -        public int getType() {
  -            return GraphicsDevice.TYPE_PRINTER;
  -        }
  -
  -    }
  -
  -    /**
  -     * Used to create proper font metrics
  -     */
  -    private Graphics2D fmg;
  -
  -    {
  -        BufferedImage bi = new BufferedImage(1, 1,
  -                                             BufferedImage.TYPE_INT_ARGB);
  -
  -        fmg = bi.createGraphics();
  -    }
  -
  -    /**
  -     * Gets the font metrics for the specified font.
  -     * @return    the font metrics for the specified font.
  -     * @param     f the specified font
  -     * @see       java.awt.Graphics#getFont
  -     * @see       java.awt.FontMetrics
  -     * @see       java.awt.Graphics#getFontMetrics()
  -     */
  -    public FontMetrics getFontMetrics(Font f) {
  -        return fmg.getFontMetrics(f);
  -    }
  -
  -    /**
  -     * Sets the paint mode of this graphics context to alternate between
  -     * this graphics context's current color and the new specified color.
  -     * This specifies that logical pixel operations are performed in the
  -     * XOR mode, which alternates pixels between the current color and
  -     * a specified XOR color.
  -     * <p>
  -     * When drawing operations are performed, pixels which are the
  -     * current color are changed to the specified color, and vice versa.
  -     * <p>
  -     * Pixels that are of colors other than those two colors are changed
  -     * in an unpredictable but reversible manner; if the same figure is
  -     * drawn twice, then all pixels are restored to their original values.
  -     * @param     c1 the XOR alternation color
  -     */
  -    public void setXORMode(Color c1) {
  -        System.out.println("setXORMode");
  -    }
  -
  -
  -    /**
  -     * Copies an area of the component by a distance specified by
  -     * <code>dx</code> and <code>dy</code>. From the point specified
  -     * by <code>x</code> and <code>y</code>, this method
  -     * copies downwards and to the right.  To copy an area of the
  -     * component to the left or upwards, specify a negative value for
  -     * <code>dx</code> or <code>dy</code>.
  -     * If a portion of the source rectangle lies outside the bounds
  -     * of the component, or is obscured by another window or component,
  -     * <code>copyArea</code> will be unable to copy the associated
  -     * pixels. The area that is omitted can be refreshed by calling
  -     * the component's <code>paint</code> method.
  -     * @param       x the <i>x</i> coordinate of the source rectangle.
  -     * @param       y the <i>y</i> coordinate of the source rectangle.
  -     * @param       width the width of the source rectangle.
  -     * @param       height the height of the source rectangle.
  -     * @param       dx the horizontal distance to copy the pixels.
  -     * @param       dy the vertical distance to copy the pixels.
  -     */
  -    public void copyArea(int x, int y, int width, int height, int dx,
  -                         int dy) {
  -        System.out.println("copyArea");
  -    }
  -
  -}
  +/*
  + * $Id$
  + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  + * For details on use and redistribution please refer to the
  + * LICENSE file included with these sources.
  + */
  +
  +package org.apache.fop.svg;
  +
  +import org.apache.fop.apps.FOPException;
  +import org.apache.fop.datatypes.ColorSpace;
  +import org.apache.fop.fonts.*;
  +import org.apache.fop.image.*;
  +import org.apache.fop.layout.*;
  +import org.apache.fop.pdf.*;
  +import org.apache.fop.render.pdf.*;
  +import org.apache.fop.render.pdf.CIDFont;
  +import org.apache.fop.render.pdf.fonts.LazyFont;
  +
  +import org.apache.batik.ext.awt.g2d.*;
  +import org.apache.batik.ext.awt.image.GraphicsUtil;
  +
  +import java.awt.*;
  +import java.awt.Font;
  +import java.awt.Image;
  +import java.awt.font.*;
  +import java.awt.geom.*;
  +import java.awt.image.*;
  +import java.awt.image.renderable.*;
  +import java.io.*;
  +import java.text.AttributedCharacterIterator;
  +import java.text.CharacterIterator;
  +import java.util.ArrayList;
  +import java.util.HashMap;
  +import java.util.Map;
  +
  +/**
  + * This concrete implementation of <tt>AbstractGraphics2D</tt> is a
  + * simple help to programmers to get started with their own
  + * implementation of <tt>Graphics2D</tt>.
  + * <tt>DefaultGraphics2D</tt> implements all the abstract methods
  + * is <tt>AbstractGraphics2D</tt> and makes it easy to start
  + * implementing a <tt>Graphic2D</tt> piece-meal.
  + *
  + * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
  + * @version $Id$
  + * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D
  + */
  +public class PDFGraphics2D extends AbstractGraphics2D {
  +    boolean standalone = false;
  +
  +    /**
  +     * the PDF Document being created
  +     */
  +    protected PDFDocument pdfDoc;
  +
  +    /**
  +     * the current annotation list to add annotations to
  +     */
  +    PDFAnnotList currentAnnotList = null;
  +
  +    protected FontState fontState;
  +    protected FontState ovFontState = null;
  +
  +    /**
  +     * the current stream to add PDF commands to
  +     */
  +    StringWriter currentStream = new StringWriter();
  +
  +    /**
  +     * the current (internal) font name
  +     */
  +    protected String currentFontName;
  +
  +    /**
  +     * the current font size in millipoints
  +     */
  +    protected int currentFontSize;
  +
  +    /**
  +     * the current vertical position in millipoints from bottom
  +     */
  +    protected int currentYPosition = 0;
  +
  +    /**
  +     * the current horizontal position in millipoints from left
  +     */
  +    protected int currentXPosition = 0;
  +
  +    /**
  +     * the current colour for use in svg
  +     */
  +    PDFColor currentColour = new PDFColor(0, 0, 0);
  +
  +    /**
  +     * A registry of images that have already been drawn. They are mapped to 
  +     * a structure with the PDF xObjectNum, width and height. This
  +     * prevents multiple copies from being stored, which can greatly
  +     * reduce the size of a PDF graphic that uses the same image over and over
  +     * (e.g. graphic bullets, map icons, etc.).
  +     */
  +    private HashMap imageInfos = new HashMap();
  +    private static class ImageInfo {
  +        public int width;
  +        public int height;
  +        public int xObjectNum;
  +    }
  +
  +    /**
  +     * Create a new PDFGraphics2D with the given pdf document info.
  +     * This is used to create a Graphics object for use inside an already
  +     * existing document.
  +     */
  +    public PDFGraphics2D(boolean textAsShapes, FontState fs, PDFDocument doc,
  +                         String font, int size, int xpos, int ypos) {
  +        super(textAsShapes);
  +        pdfDoc = doc;
  +        currentFontName = font;
  +        currentFontSize = size;
  +        currentYPosition = ypos;
  +        currentXPosition = xpos;
  +        fontState = fs;
  +    }
  +
  +    public PDFGraphics2D(boolean textAsShapes) {
  +        super(textAsShapes);
  +    }
  +
  +    public String getString() {
  +        return currentStream.toString();
  +    }
  +
  +    public void setGraphicContext(GraphicContext c) {
  +        gc = c;
  +    }
  +
  +    public void setOverrideFontState(FontState infont) {
  +        ovFontState = infont;
  +    }
  +
  +    /**
  +     * This constructor supports the create method
  +     */
  +    public PDFGraphics2D(PDFGraphics2D g) {
  +        super(g);
  +    }
  +
  +    /**
  +     * Creates a new <code>Graphics</code> object that is
  +     * a copy of this <code>Graphics</code> object.
  +     * @return     a new graphics context that is a copy of
  +     * this graphics context.
  +     */
  +    public Graphics create() {
  +        return new PDFGraphics2D(this);
  +    }
  +
  +    /**
  +     * This is a pdf specific method used to add a link to the
  +     * pdf document.
  +     */
  +    public void addLink(Shape bounds, AffineTransform trans, String dest, int linkType) {
  +        if(currentAnnotList == null) {
  +            currentAnnotList = pdfDoc.makeAnnotList();
  +        }
  +        AffineTransform at = getTransform();
  +        Shape b = at.createTransformedShape(bounds);
  +        b = trans.createTransformedShape(b);
  +        Rectangle rect = b.getBounds();
  +        // this handles the / 1000 in PDFLink
  +        rect.x = rect.x * 1000;
  +        rect.y = rect.y * 1000;
  +        rect.height = -rect.height * 1000;
  +        rect.width = rect.width * 1000;
  +        if(linkType != LinkSet.EXTERNAL) {
  +            String pdfdest = "/XYZ " + dest;
  +            currentAnnotList.addLink(pdfDoc.makeLinkCurrentPage(rect, pdfdest));
  +        } else {
  +            currentAnnotList.addLink(pdfDoc.makeLink(rect,
  +                                                 dest, linkType));
  +        }
  +    }
  +
  +    public PDFAnnotList getAnnotList() {
  +        return currentAnnotList;
  +    }
  +
  +    public void addJpegImage(JpegImage jpeg, float x, float y, float width, float height) {
  +        int xObjectNum = this.pdfDoc.addImage(jpeg);
  +
  +        AffineTransform at = getTransform();
  +        double[] matrix = new double[6];
  +        at.getMatrix(matrix);
  +        currentStream.write("q\n");
  +        Shape imclip = getClip();
  +        writeClip(imclip);
  +        currentStream.write("" + matrix[0] + " " + matrix[1] + " "
  +                            + matrix[2] + " " + matrix[3] + " "
  +                            + matrix[4] + " " + matrix[5] + " cm\n");
  +
  +        currentStream.write("" + width + " 0 0 "
  +                          + (-height) + " "
  +                          + x + " "
  +                          + (y + height) + " cm\n" + "/Im"
  +                          + xObjectNum + " Do\nQ\n");
  +    }
  +
  +    /**
  +     * Draws as much of the specified image as is currently available.
  +     * The image is drawn with its top-left corner at
  +     * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
  +     * space. Transparent pixels in the image do not affect whatever
  +     * pixels are already there.
  +     * <p>
  +     * This method returns immediately in all cases, even if the
  +     * complete image has not yet been loaded, and it has not been dithered
  +     * and converted for the current output device.
  +     * <p>
  +     * If the image has not yet been completely loaded, then
  +     * <code>drawImage</code> returns <code>false</code>. As more of
  +     * the image becomes available, the process that draws the image notifies
  +     * the specified image observer.
  +     * @param    img the specified image to be drawn.
  +     * @param    x   the <i>x</i> coordinate.
  +     * @param    y   the <i>y</i> coordinate.
  +     * @param    observer    object to be notified as more of
  +     * the image is converted.
  +     * @see      java.awt.Image
  +     * @see      java.awt.image.ImageObserver
  +     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  +     */
  +    public boolean drawImage(Image img, int x, int y,
  +                             ImageObserver observer) {
  +        // System.err.println("drawImage:x, y");
  +
  +        // first we look to see if we've already added this image to 
  +        // the pdf document. If so, we just reuse the reference;
  +        // otherwise we have to build a FopImage and add it to the pdf
  +        // document
  +        ImageInfo imageInfo = (ImageInfo)imageInfos.get(img);
  +        if (imageInfo == null) {
  +            // OK, have to build and add a PDF image
  +            imageInfo = new ImageInfo();
  +            imageInfo.width = img.getWidth(observer);
  +            imageInfo.height = img.getHeight(observer);
  +            
  +            if (imageInfo.width == -1 || imageInfo.height == -1) {
  +                return false;
  +            }
  +            
  +            Dimension size = new Dimension(imageInfo.width * 3, imageInfo.height * 3);
  +            BufferedImage buf = buildBufferedImage(size);
  +            
  +            java.awt.Graphics2D g = buf.createGraphics();
  +            g.setComposite(AlphaComposite.SrcOver);
  +            g.setBackground(new Color(1, 1, 1, 0));
  +            g.setPaint(new Color(1, 1, 1, 0));
  +            g.fillRect(0, 0, imageInfo.width * 3, imageInfo.height * 3);
  +            g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
  +            
  +            if (!g.drawImage(img, 0, 0, buf.getWidth(), buf.getHeight(), observer)) {
  +                return false;
  +            }
  +            g.dispose();
  +            
  +            final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3];
  +            final byte[] mask = new byte[buf.getWidth() * buf.getHeight()];
  +            
  +            Raster raster = buf.getData();
  +            DataBuffer bd = raster.getDataBuffer();
  +                
  +            int count = 0;
  +            int maskpos = 0;
  +            int[] iarray;
  +            int i, j, val, alpha, add, mult;
  +            switch (bd.getDataType()) {
  +            case DataBuffer.TYPE_INT:
  +                int[][] idata = ((DataBufferInt)bd).getBankData();
  +                for (i = 0; i < idata.length; i++) {
  +                    iarray = idata[i];
  +                    for (j = 0; j < iarray.length; j++) {
  +                        val = iarray[j];
  +                        alpha = val >>> 24;
  +                        // mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF);
  +                        if (alpha != 255) {
  +                            // System.out.println("Alpha: " + alpha);
  +                            // Composite with opaque white...
  +                            add = (255 - alpha);
  +                            mult = (alpha << 16) / 255;
  +                            result[count++] =
  +                                (byte)(add
  +                                       + ((((val >> 16) & 0xFF) * mult) >> 16));
  +                            result[count++] =
  +                                (byte)(add
  +                                       + ((((val >> 8) & 0xFF) * mult) >> 16));
  +                            result[count++] = (byte)(add
  +                                                     + ((((val) & 0xFF) * mult)
  +                                                        >> 16));
  +                        } else {
  +                            result[count++] = (byte)((val >> 16) & 0xFF);
  +                            result[count++] = (byte)((val >> 8) & 0xFF);
  +                            result[count++] = (byte)((val) & 0xFF);
  +                        }
  +                    }
  +                }
  +                break;
  +            default:
  +                // error
  +                break;
  +                }
  +            
  +            try {
  +                FopImage fopimg = new TempImage("TempImage:" + img.toString(), buf.getWidth(), buf.getHeight(), result, mask);
  +                imageInfo.xObjectNum = this.pdfDoc.addImage(fopimg);
  +                imageInfos.put(img, imageInfo);
  +            } catch (Exception e) {
  +                e.printStackTrace();
  +            }
  +        }
  +
  +        // now do any transformation required and add the actual image
  +        // placement instance
  +        AffineTransform at = getTransform();
  +        double[] matrix = new double[6];
  +        at.getMatrix(matrix);
  +        currentStream.write("q\n");
  +        Shape imclip = getClip();
  +        writeClip(imclip);
  +        currentStream.write("" + matrix[0] + " " + matrix[1] + " "
  +                            + matrix[2] + " " + matrix[3] + " "
  +                            + matrix[4] + " " + matrix[5] + " cm\n");
  +        currentStream.write("" + imageInfo.width + " 0 0 " + (-imageInfo.height) + " " + x
  +                            + " " + (y + imageInfo.height) + " cm\n" + "/Im"
  +                            + imageInfo.xObjectNum + " Do\nQ\n");
  +        return true;
  +    }
  +
  +    public BufferedImage buildBufferedImage(Dimension size) {
  +        return new BufferedImage(size.width, size.height,
  +                                 BufferedImage.TYPE_INT_ARGB);
  +    }
  +
  +    class TempImage implements FopImage {
  +        int m_height;
  +        int m_width;
  +        int m_bitsPerPixel;
  +        ColorSpace m_colorSpace;
  +        int m_bitmapSiye;
  +        byte[] m_bitmaps;
  +        byte[] m_mask;
  +        PDFColor transparent = new PDFColor(255, 255, 255);
  +        String url;
  +
  +        TempImage(String url, int width, int height, byte[] result,
  +                  byte[] mask) throws FopImageException {
  +            this.url = url;
  +            this.m_height = height;
  +            this.m_width = width;
  +            this.m_bitsPerPixel = 8;
  +            this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
  +            // this.m_isTransparent = false;
  +            // this.m_bitmapsSize = this.m_width * this.m_height * 3;
  +            this.m_bitmaps = result;
  +            this.m_mask = mask;
  +        }
  +
  +        public boolean invertImage() {
  +            return false;
  +        }
  +
  +        public String getURL() {
  +            return url;
  +        }
  +
  +        // image size
  +        public int getWidth() throws FopImageException {
  +            return m_width;
  +        }
  +
  +        public int getHeight() throws FopImageException {
  +            return m_height;
  +        }
  +
  +        // DeviceGray, DeviceRGB, or DeviceCMYK
  +        public ColorSpace getColorSpace() throws FopImageException {
  +            return m_colorSpace;
  +        }
  +
  +        // bits per pixel
  +        public int getBitsPerPixel() throws FopImageException {
  +            return m_bitsPerPixel;
  +        }
  +
  +        // For transparent images
  +        public boolean isTransparent() throws FopImageException {
  +            return transparent != null;
  +        }
  +
  +        public PDFColor getTransparentColor() throws FopImageException {
  +            return transparent;
  +        }
  +
  +        public byte[] getMask() throws FopImageException {
  +            return m_mask;
  +        }
  +
  +        // get the image bytes, and bytes properties
  +
  +        // get uncompressed image bytes
  +        public byte[] getBitmaps() throws FopImageException {
  +            return m_bitmaps;
  +        }
  +
  +        // width * (bitsPerPixel / 8) * height, no ?
  +        public int getBitmapsSize() throws FopImageException {
  +            return m_width * m_height * 3;
  +        }
  +
  +        // get compressed image bytes
  +        // I don't know if we really need it, nor if it
  +        // should be changed...
  +        public byte[] getRessourceBytes() throws FopImageException {
  +            return null;
  +        }
  +
  +        public int getRessourceBytesSize() throws FopImageException {
  +            return 0;
  +        }
  +
  +        // return null if no corresponding PDFFilter
  +        public PDFFilter getPDFFilter() throws FopImageException {
  +            return null;
  +        }
  +
  +        // release memory
  +        public void close() {}
  +
  +    }
  +
  +
  +    /**
  +     * Draws as much of the specified image as has already been scaled
  +     * to fit inside the specified rectangle.
  +     * <p>
  +     * The image is drawn inside the specified rectangle of this
  +     * graphics context's coordinate space, and is scaled if
  +     * necessary. Transparent pixels do not affect whatever pixels
  +     * are already there.
  +     * <p>
  +     * This method returns immediately in all cases, even if the
  +     * entire image has not yet been scaled, dithered, and converted
  +     * for the current output device.
  +     * If the current output representation is not yet complete, then
  +     * <code>drawImage</code> returns <code>false</code>. As more of
  +     * the image becomes available, the process that draws the image notifies
  +     * the image observer by calling its <code>imageUpdate</code> method.
  +     * <p>
  +     * A scaled version of an image will not necessarily be
  +     * available immediately just because an unscaled version of the
  +     * image has been constructed for this output device.  Each size of
  +     * the image may be cached separately and generated from the original
  +     * data in a separate image production sequence.
  +     * @param    img    the specified image to be drawn.
  +     * @param    x      the <i>x</i> coordinate.
  +     * @param    y      the <i>y</i> coordinate.
  +     * @param    width  the width of the rectangle.
  +     * @param    height the height of the rectangle.
  +     * @param    observer    object to be notified as more of
  +     * the image is converted.
  +     * @see      java.awt.Image
  +     * @see      java.awt.image.ImageObserver
  +     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
  +     */
  +    public boolean drawImage(Image img, int x, int y, int width, int height,
  +                             ImageObserver observer) {
  +        System.out.println("drawImage");
  +        return true;
  +    }
  +
  +    /**
  +     * Disposes of this graphics context and releases
  +     * any system resources that it is using.
  +     * A <code>Graphics</code> object cannot be used after
  +     * <code>dispose</code>has been called.
  +     * <p>
  +     * When a Java program runs, a large number of <code>Graphics</code>
  +     * objects can be created within a short time frame.
  +     * Although the finalization process of the garbage collector
  +     * also disposes of the same system resources, it is preferable
  +     * to manually free the associated resources by calling this
  +     * method rather than to rely on a finalization process which
  +     * may not run to completion for a long period of time.
  +     * <p>
  +     * Graphics objects which are provided as arguments to the
  +     * <code>paint</code> and <code>update</code> methods
  +     * of components are automatically released by the system when
  +     * those methods return. For efficiency, programmers should
  +     * call <code>dispose</code> when finished using
  +     * a <code>Graphics</code> object only if it was created
  +     * directly from a component or another <code>Graphics</code> object.
  +     * @see         java.awt.Graphics#finalize
  +     * @see         java.awt.Component#paint
  +     * @see         java.awt.Component#update
  +     * @see         java.awt.Component#getGraphics
  +     * @see         java.awt.Graphics#create
  +     */
  +    public void dispose() {
  +        // System.out.println("dispose");
  +        pdfDoc = null;
  +        fontState = null;
  +        currentStream = null;
  +        currentFontName = null;
  +        currentColour = null;
  +    }
  +
  +    /**
  +     * Strokes the outline of a <code>Shape</code> using the settings of the
  +     * current <code>Graphics2D</code> context.  The rendering attributes
  +     * applied include the <code>Clip</code>, <code>Transform</code>,
  +     * <code>Paint</code>, <code>Composite</code> and
  +     * <code>Stroke</code> attributes.
  +     * @param s the <code>Shape</code> to be rendered
  +     * @see #setStroke
  +     * @see #setPaint
  +     * @see java.awt.Graphics#setColor
  +     * @see #transform
  +     * @see #setTransform
  +     * @see #clip
  +     * @see #setClip
  +     * @see #setComposite
  +     */
  +    public void draw(Shape s) {
  +        // System.out.println("draw(Shape)");
  +        Color c;
  +        c = getColor();
  +        if(c.getAlpha() == 0) {
  +            return;
  +        }
  +
  +        currentStream.write("q\n");
  +        Shape imclip = getClip();
  +        writeClip(imclip);
  +        applyColor(c, false);
  +
  +        applyPaint(getPaint(), false);
  +        applyStroke(getStroke());
  +
  +        AffineTransform trans = getTransform();
  +        double[] tranvals = new double[6];
  +        trans.getMatrix(tranvals);
  +        currentStream.write(PDFNumber.doubleOut(tranvals[0]) + " "
  +                            + PDFNumber.doubleOut(tranvals[1]) + " "
  +                            + PDFNumber.doubleOut(tranvals[2]) + " "
  +                            + PDFNumber.doubleOut(tranvals[3]) + " "
  +                            + PDFNumber.doubleOut(tranvals[4]) + " "
  +                            + PDFNumber.doubleOut(tranvals[5]) + " cm\n");
  +
  +        PathIterator iter = s.getPathIterator(new AffineTransform());
  +        while (!iter.isDone()) {
  +            double vals[] = new double[6];
  +            int type = iter.currentSegment(vals);
  +            switch (type) {
  +            case PathIterator.SEG_CUBICTO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " "
  +                                    + PDFNumber.doubleOut(vals[2]) + " "
  +                                    + PDFNumber.doubleOut(vals[3]) + " "
  +                                    + PDFNumber.doubleOut(vals[4]) + " "
  +                                    + PDFNumber.doubleOut(vals[5]) + " c\n");
  +                break;
  +            case PathIterator.SEG_LINETO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " l\n");
  +                break;
  +            case PathIterator.SEG_MOVETO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " m\n");
  +                break;
  +            case PathIterator.SEG_QUADTO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " "
  +                                    + PDFNumber.doubleOut(vals[2]) + " "
  +                                    + PDFNumber.doubleOut(vals[3]) + " y\n");
  +                break;
  +            case PathIterator.SEG_CLOSE:
  +                currentStream.write("h\n");
  +                break;
  +            default:
  +                break;
  +            }
  +            iter.next();
  +        }
  +        doDrawing(false, true, false);
  +        currentStream.write("Q\n");
  +    }
  +
  +    protected void writeClip(Shape s) {
  +        if (s == null) {
  +            return;
  +        }
  +        PathIterator iter = s.getPathIterator(getTransform());
  +        while (!iter.isDone()) {
  +            double vals[] = new double[6];
  +            int type = iter.currentSegment(vals);
  +            switch (type) {
  +            case PathIterator.SEG_CUBICTO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " "
  +                                    + PDFNumber.doubleOut(vals[2]) + " "
  +                                    + PDFNumber.doubleOut(vals[3]) + " "
  +                                    + PDFNumber.doubleOut(vals[4]) + " "
  +                                    + PDFNumber.doubleOut(vals[5]) + " c\n");
  +                break;
  +            case PathIterator.SEG_LINETO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " l\n");
  +                break;
  +            case PathIterator.SEG_MOVETO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " m\n");
  +                break;
  +            case PathIterator.SEG_QUADTO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " "
  +                                    + PDFNumber.doubleOut(vals[2]) + " "
  +                                    + PDFNumber.doubleOut(vals[3]) + " y\n");
  +                break;
  +            case PathIterator.SEG_CLOSE:
  +                currentStream.write("h\n");
  +                break;
  +            default:
  +                break;
  +            }
  +            iter.next();
  +        }
  +        // clip area
  +        currentStream.write("W\n");
  +        currentStream.write("n\n");
  +    }
  +
  +    protected void applyColor(Color col, boolean fill) {
  +        Color c = col;
  +        if (c.getColorSpace().getType()
  +                == java.awt.color.ColorSpace.TYPE_RGB) {
  +            currentColour = new PDFColor(c.getRed(), c.getGreen(),
  +                                         c.getBlue());
  +            currentStream.write(currentColour.getColorSpaceOut(fill));
  +        } else if (c.getColorSpace().getType()
  +                   == java.awt.color.ColorSpace.TYPE_CMYK) {
  +            float[] cComps = c.getColorComponents(new float[3]);
  +            double[] cmyk = new double[3];
  +            for (int i = 0; i < 3; i++) {
  +                // convert the float elements to doubles for pdf
  +                cmyk[i] = cComps[i];
  +            }
  +            currentColour = new PDFColor(cmyk[0], cmyk[1], cmyk[2], cmyk[3]);
  +            currentStream.write(currentColour.getColorSpaceOut(fill));
  +        } else if (c.getColorSpace().getType()
  +                   == java.awt.color.ColorSpace.TYPE_2CLR) {
  +            // used for black/magenta
  +            float[] cComps = c.getColorComponents(new float[1]);
  +            double[] blackMagenta = new double[1];
  +            for (int i = 0; i < 1; i++) {
  +                blackMagenta[i] = cComps[i];
  +            }
  +            // currentColour = new PDFColor(blackMagenta[0], blackMagenta[1]);
  +            currentStream.write(currentColour.getColorSpaceOut(fill));
  +        } else {
  +            System.err.println("Color Space not supported by PDFGraphics2D");
  +        }
  +    }
  +
  +    protected void applyPaint(Paint paint, boolean fill) {
  +        if (paint instanceof GradientPaint) {
  +            GradientPaint gp = (GradientPaint)paint;
  +            Color c1 = gp.getColor1();
  +            Color c2 = gp.getColor2();
  +            Point2D p1 = gp.getPoint1();
  +            Point2D p2 = gp.getPoint2();
  +            boolean cyclic = gp.isCyclic();
  +
  +            ArrayList theCoords = new ArrayList();
  +            theCoords.add(new Double(p1.getX()));
  +            theCoords.add(new Double(p1.getY()));
  +            theCoords.add(new Double(p2.getX()));
  +            theCoords.add(new Double(p2.getY()));
  +
  +            ArrayList theExtend = new ArrayList();
  +            theExtend.add(new Boolean(true));
  +            theExtend.add(new Boolean(true));
  +
  +            ArrayList theDomain = new ArrayList();
  +            theDomain.add(new Double(0));
  +            theDomain.add(new Double(1));
  +
  +            ArrayList theEncode = new ArrayList();
  +            theEncode.add(new Double(0));
  +            theEncode.add(new Double(1));
  +            theEncode.add(new Double(0));
  +            theEncode.add(new Double(1));
  +
  +            ArrayList theBounds = new ArrayList();
  +            theBounds.add(new Double(0));
  +            theBounds.add(new Double(1));
  +
  +            ArrayList theFunctions = new ArrayList();
  +
  +            ArrayList someColors = new ArrayList();
  +
  +            PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(),
  +                                           c1.getBlue());
  +            someColors.add(color1);
  +            PDFColor color2 = new PDFColor(c2.getRed(), c2.getGreen(),
  +                                           c2.getBlue());
  +            someColors.add(color2);
  +
  +            PDFFunction myfunc = this.pdfDoc.makeFunction(2, theDomain, null,
  +                    color1.getVector(), color2.getVector(), 1.0);
  +
  +            ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB);
  +            PDFPattern myPat = this.pdfDoc.createGradient(false, aColorSpace,
  +                    someColors, null, theCoords);
  +            currentStream.write(myPat.getColorSpaceOut(fill));
  +
  +        } else if (paint instanceof TexturePaint) {}
  +    }
  +
  +    protected void applyStroke(Stroke stroke) {
  +        if (stroke instanceof BasicStroke) {
  +            BasicStroke bs = (BasicStroke)stroke;
  +
  +            float[] da = bs.getDashArray();
  +            if (da != null) {
  +                currentStream.write("[");
  +                for (int count = 0; count < da.length; count++) {
  +                    if(((int)da[count]) == 0) {
  +                        // the dasharray units in pdf are (whole) numbers
  +                        // in user space units, cannot be 0
  +                        currentStream.write("1");
  +                    } else {
  +                        currentStream.write("" + ((int)da[count]));
  +                    }
  +                    if (count < da.length - 1) {
  +                        currentStream.write(" ");
  +                    }
  +                }
  +                currentStream.write("] ");
  +                float offset = bs.getDashPhase();
  +                currentStream.write(((int)offset) + " d\n");
  +            }
  +            int ec = bs.getEndCap();
  +            switch (ec) {
  +            case BasicStroke.CAP_BUTT:
  +                currentStream.write(0 + " J\n");
  +                break;
  +            case BasicStroke.CAP_ROUND:
  +                currentStream.write(1 + " J\n");
  +                break;
  +            case BasicStroke.CAP_SQUARE:
  +                currentStream.write(2 + " J\n");
  +                break;
  +            }
  +
  +            int lj = bs.getLineJoin();
  +            switch (lj) {
  +            case BasicStroke.JOIN_MITER:
  +                currentStream.write(0 + " j\n");
  +                break;
  +            case BasicStroke.JOIN_ROUND:
  +                currentStream.write(1 + " j\n");
  +                break;
  +            case BasicStroke.JOIN_BEVEL:
  +                currentStream.write(2 + " j\n");
  +                break;
  +            }
  +            float lw = bs.getLineWidth();
  +            currentStream.write(PDFNumber.doubleOut(lw) + " w\n");
  +
  +            float ml = bs.getMiterLimit();
  +            currentStream.write(PDFNumber.doubleOut(ml) + " M\n");
  +        }
  +    }
  +
  +    /**
  +     * Renders a {@link RenderedImage},
  +     * applying a transform from image
  +     * space into user space before drawing.
  +     * The transformation from user space into device space is done with
  +     * the current <code>Transform</code> in the <code>Graphics2D</code>.
  +     * The specified transformation is applied to the image before the
  +     * transform attribute in the <code>Graphics2D</code> context is applied.
  +     * The rendering attributes applied include the <code>Clip</code>,
  +     * <code>Transform</code>, and <code>Composite</code> attributes. Note
  +     * that no rendering is done if the specified transform is
  +     * noninvertible.
  +     * @param img the image to be rendered
  +     * @param xform the transformation from image space into user space
  +     * @see #transform
  +     * @see #setTransform
  +     * @see #setComposite
  +     * @see #clip
  +     * @see #setClip
  +     */
  +    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
  +        System.out.println("drawRenderedImage");
  +    }
  +
  +
  +    /**
  +     * Renders a
  +     * {@link RenderableImage},
  +     * applying a transform from image space into user space before drawing.
  +     * The transformation from user space into device space is done with
  +     * the current <code>Transform</code> in the <code>Graphics2D</code>.
  +     * The specified transformation is applied to the image before the
  +     * transform attribute in the <code>Graphics2D</code> context is applied.
  +     * The rendering attributes applied include the <code>Clip</code>,
  +     * <code>Transform</code>, and <code>Composite</code> attributes. Note
  +     * that no rendering is done if the specified transform is
  +     * noninvertible.
  +     * <p>
  +     * Rendering hints set on the <code>Graphics2D</code> object might
  +     * be used in rendering the <code>RenderableImage</code>.
  +     * If explicit control is required over specific hints recognized by a
  +     * specific <code>RenderableImage</code>, or if knowledge of which hints
  +     * are used is required, then a <code>RenderedImage</code> should be
  +     * obtained directly from the <code>RenderableImage</code>
  +     * and rendered using
  +     * {@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.
  +     * @param img the image to be rendered
  +     * @param xform the transformation from image space into user space
  +     * @see #transform
  +     * @see #setTransform
  +     * @see #setComposite
  +     * @see #clip
  +     * @see #setClip
  +     * @see #drawRenderedImage
  +     */
  +    public void drawRenderableImage(RenderableImage img,
  +                                    AffineTransform xform) {
  +        System.out.println("drawRenderableImage");
  +    }
  +
  +    /**
  +     * Renders the text specified by the specified <code>String</code>,
  +     * using the current <code>Font</code> and <code>Paint</code> attributes
  +     * in the <code>Graphics2D</code> context.
  +     * The baseline of the first character is at position
  +     * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
  +     * The rendering attributes applied include the <code>Clip</code>,
  +     * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
  +     * <code>Composite</code> attributes. For characters in script systems
  +     * such as Hebrew and Arabic, the glyphs can be rendered from right to
  +     * left, in which case the coordinate supplied is the location of the
  +     * leftmost character on the baseline.
  +     * @param s the <code>String</code> to be rendered
  +     * @param x,&nbsp;y the coordinates where the <code>String</code>
  +     * should be rendered
  +     * @see #setPaint
  +     * @see java.awt.Graphics#setColor
  +     * @see java.awt.Graphics#setFont
  +     * @see #setTransform
  +     * @see #setComposite
  +     * @see #setClip
  +     */
  +    public void drawString(String s, float x, float y) {
  +        // System.out.println("drawString(String)");
  +
  +        if(ovFontState == null) {
  +            Font gFont = getFont();
  +            String n = gFont.getFamily();
  +            if (n.equals("sanserif")) {
  +                n = "sans-serif";
  +            }
  +            int siz = gFont.getSize();
  +            String style = gFont.isItalic() ? "italic" : "normal";
  +            String weight = gFont.isBold() ? "bold" : "normal";
  +            try {
  +                fontState = new FontState(fontState.getFontInfo(), n, style,
  +                                          weight, siz * 1000, 0);
  +            } catch (org.apache.fop.apps.FOPException fope) {
  +                fope.printStackTrace();
  +            }
  +        } else {
  +            fontState = ovFontState;
  +            ovFontState = null;
  +        }       
  +        String name;
  +        int size;
  +        name = fontState.getFontName();
  +        size = fontState.getFontSize() / 1000;
  +    
  +        if ((!name.equals(this.currentFontName))
  +                || (size != this.currentFontSize)) {
  +            this.currentFontName = name; 
  +            this.currentFontSize = size;
  +            currentStream.write("/" + name + " " + size + " Tf\n");
  +
  +        }
  +
  +        currentStream.write("q\n");
  +
  +        Shape imclip = getClip();
  +        writeClip(imclip);
  +        Color c = getColor();
  +        applyColor(c, true);
  +        c = getBackground();
  +        applyColor(c, false);
  +
  +        currentStream.write("BT\n");
  +
  +        HashMap kerning = null;
  +        boolean kerningAvailable = false;
  +
  +        kerning = fontState.getKerning();
  +        if (kerning != null &&!kerning.isEmpty()) {
  +            kerningAvailable = true;
  +        }
  +
  +        // This assumes that *all* CIDFonts use a /ToUnicode mapping
  +        boolean useMultiByte = false;
  +        org.apache.fop.render.pdf.Font f =
  +            (org.apache.fop.render.pdf.Font)fontState.getFontInfo().getFonts().get(name);
  +        if (f instanceof LazyFont){
  +            if(((LazyFont) f).getRealFont() instanceof CIDFont){
  +                useMultiByte = true;
  +            }
  +        } else if (f instanceof CIDFont){
  +            useMultiByte = true;
  +        }
  +
  +        // String startText = useMultiByte ? "<FEFF" : "(";
  +        String startText = useMultiByte ? "<" : "(";
  +        String endText = useMultiByte ? "> " : ") ";
  +
  +        AffineTransform trans = getTransform();
  +        trans.translate(x, y);
  +        double[] vals = new double[6];
  +        trans.getMatrix(vals);
  +
  +        currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                            + PDFNumber.doubleOut(vals[1]) + " "
  +                            + PDFNumber.doubleOut(vals[2]) + " "
  +                            + PDFNumber.doubleOut(vals[3]) + " "
  +                            + PDFNumber.doubleOut(vals[4]) + " "
  +                            + PDFNumber.doubleOut(vals[5]) + " cm\n");
  +        currentStream.write("1 0 0 -1 0 0 Tm [" + startText);
  +
  +        int l = s.length();
  +
  +        for (int i = 0; i < l; i++) {
  +            char ch = fontState.mapChar(s.charAt(i));
  +
  +            if (!useMultiByte) {
  +                if (ch > 127) {
  +                    currentStream.write("\\");
  +                    currentStream.write(Integer.toOctalString((int)ch));
  +                } else {
  +                    switch (ch) {
  +                    case '(':
  +                    case ')':
  +                    case '\\':
  +                        currentStream.write("\\");
  +                        break;
  +                    }
  +                    currentStream.write(ch);
  +                }
  +            } else {
  +                currentStream.write(getUnicodeString(ch));
  +            }
  +
  +            if (kerningAvailable && (i + 1) < l) {
  +                addKerning(currentStream, (new Integer((int)ch)),
  +                           (new Integer((int)fontState.mapChar(s.charAt(i + 1)))),
  +                           kerning, startText, endText);
  +            }
  +
  +        }
  +        currentStream.write(endText);
  +
  +
  +        currentStream.write("] TJ\n");
  +
  +        currentStream.write("ET\n");
  +        currentStream.write("Q\n");
  +    }
  +
  +    private void addKerning(StringWriter buf, Integer ch1, Integer ch2,
  +                            HashMap kerning, String startText,
  +                            String endText) {
  +        HashMap kernPair = (HashMap)kerning.get(ch1);
  +
  +        if (kernPair != null) {
  +            Integer width = (Integer)kernPair.get(ch2);
  +            if (width != null) {
  +                currentStream.write(endText + (-width.intValue()) + " " + startText);
  +            }
  +        }
  +    }
  +
  +    /**
  +     * Convert a char to a multibyte hex representation
  +     */
  +    private String getUnicodeString(char c) {
  +
  +        StringBuffer buf = new StringBuffer(4);
  +        byte[] uniBytes = null;
  +        try {
  +            char[] a = {
  +                c
  +            };
  +            uniBytes = new String(a).getBytes("UnicodeBigUnmarked");
  +        } catch (Exception e) {
  +            // This should never fail
  +        }
  +
  +        for (int i = 0; i < uniBytes.length; i++) {
  +            int b = (uniBytes[i] < 0) ? (int)(256 + uniBytes[i])
  +                    : (int)uniBytes[i];
  +
  +            String hexString = Integer.toHexString(b);
  +            if (hexString.length() == 1)
  +                buf = buf.append("0" + hexString);
  +            else
  +                buf = buf.append(hexString);
  +        }
  +
  +        return buf.toString();
  +    }
  +
  +    /**
  +     * Renders the text of the specified iterator, using the
  +     * <code>Graphics2D</code> context's current <code>Paint</code>. The
  +     * iterator must specify a font
  +     * for each character. The baseline of the
  +     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the
  +     * User Space.
  +     * The rendering attributes applied include the <code>Clip</code>,
  +     * <code>Transform</code>, <code>Paint</code>, and
  +     * <code>Composite</code> attributes.
  +     * For characters in script systems such as Hebrew and Arabic,
  +     * the glyphs can be rendered from right to left, in which case the
  +     * coordinate supplied is the location of the leftmost character
  +     * on the baseline.
  +     * @param iterator the iterator whose text is to be rendered
  +     * @param x,&nbsp;y the coordinates where the iterator's text is to be
  +     * rendered
  +     * @see #setPaint
  +     * @see java.awt.Graphics#setColor
  +     * @see #setTransform
  +     * @see #setComposite
  +     * @see #setClip
  +     */
  +    public void drawString(AttributedCharacterIterator iterator, float x,
  +                           float y) {
  +        System.err.println("drawString(AttributedCharacterIterator)");
  +
  +        Shape imclip = getClip();
  +        writeClip(imclip);
  +        Color c = getColor();
  +        applyColor(c, true);
  +        c = getBackground();
  +        applyColor(c, false);
  +
  +        currentStream.write("BT\n");
  +
  +        AffineTransform trans = getTransform();
  +        trans.translate(x, y);
  +        double[] vals = new double[6];
  +        trans.getMatrix(vals);
  +
  +        for (char ch = iterator.first(); ch != CharacterIterator.DONE;
  +                ch = iterator.next()) {
  +            Map attr = iterator.getAttributes();
  +
  +            String name = fontState.getFontName();
  +            int size = fontState.getFontSize();
  +            if ((!name.equals(this.currentFontName))
  +                    || (size != this.currentFontSize)) {
  +                this.currentFontName = name;
  +                this.currentFontSize = size;
  +                currentStream.write("/" + name + " " + (size / 1000)
  +                                    + " Tf\n");
  +
  +            }
  +
  +            currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                + PDFNumber.doubleOut(vals[1]) + " "
  +                                + PDFNumber.doubleOut(vals[2]) + " "
  +                                + PDFNumber.doubleOut(vals[3]) + " "
  +                                + PDFNumber.doubleOut(vals[4]) + " "
  +                                + PDFNumber.doubleOut(vals[5]) + " Tm (" + ch
  +                                + ") Tj\n");
  +        }
  +
  +        currentStream.write("ET\n");
  +    }
  +
  +    /**
  +     * Fills the interior of a <code>Shape</code> using the settings of the
  +     * <code>Graphics2D</code> context. The rendering attributes applied
  +     * include the <code>Clip</code>, <code>Transform</code>,
  +     * <code>Paint</code>, and <code>Composite</code>.
  +     * @param s the <code>Shape</code> to be filled
  +     * @see #setPaint
  +     * @see java.awt.Graphics#setColor
  +     * @see #transform
  +     * @see #setTransform
  +     * @see #setComposite
  +     * @see #clip
  +     * @see #setClip
  +     */
  +    public void fill(Shape s) {
  +        // System.err.println("fill");
  +        Color c;
  +        c = getBackground();
  +        if(c.getAlpha() == 0) {
  +            c = getColor();
  +            if(c.getAlpha() == 0) {
  +                return;
  +            }
  +        }
  +        currentStream.write("q\n");
  +        Shape imclip = getClip();
  +        writeClip(imclip);
  +        c = getColor();
  +        applyColor(c, true);
  +        c = getBackground();
  +        applyColor(c, false);
  +
  +        applyPaint(getPaint(), true);
  +
  +        PathIterator iter = s.getPathIterator(getTransform());
  +        while (!iter.isDone()) {
  +            double vals[] = new double[6];
  +            int type = iter.currentSegment(vals);
  +            switch (type) {
  +            case PathIterator.SEG_CUBICTO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " "
  +                                    + PDFNumber.doubleOut(vals[2]) + " "
  +                                    + PDFNumber.doubleOut(vals[3]) + " "
  +                                    + PDFNumber.doubleOut(vals[4]) + " "
  +                                    + PDFNumber.doubleOut(vals[5]) + " c\n");
  +                break;
  +            case PathIterator.SEG_LINETO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " l\n");
  +                break;
  +            case PathIterator.SEG_MOVETO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " m\n");
  +                break;
  +            case PathIterator.SEG_QUADTO:
  +                currentStream.write(PDFNumber.doubleOut(vals[0]) + " "
  +                                    + PDFNumber.doubleOut(vals[1]) + " "
  +                                    + PDFNumber.doubleOut(vals[2]) + " "
  +                                    + PDFNumber.doubleOut(vals[3]) + " y\n");
  +                break;
  +            case PathIterator.SEG_CLOSE:
  +                currentStream.write("h\n");
  +                break;
  +            default:
  +                break;
  +            }
  +            iter.next();
  +        }
  +        doDrawing(true, false,
  +                  iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
  +        currentStream.write("Q\n");
  +    }
  +
  +    protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) {
  +        if (fill) {
  +            if (stroke) {
  +                if (nonzero)
  +                    currentStream.write("B*\n");
  +                else
  +                    currentStream.write("B\n");
  +            } else {
  +                if (nonzero)
  +                    currentStream.write("f*\n");
  +                else
  +                    currentStream.write("f\n");
  +            }
  +        } else {
  +            // if(stroke)
  +            currentStream.write("S\n");
  +        }
  +    }
  +
  +    /**
  +     * Returns the device configuration associated with this
  +     * <code>Graphics2D</code>.
  +     */
  +    public GraphicsConfiguration getDeviceConfiguration() {
  +        return new PDFGraphicsConfiguration();
  +    }
  +
  +    /**
  +     * Our implementation of the class that returns information about
  +     * roughly what we can handle and want to see (alpha for example).
  +     */
  +    static class PDFGraphicsConfiguration extends GraphicsConfiguration {
  +        // We use this to get a good colormodel..
  +        static BufferedImage BIWithAlpha = new BufferedImage(1, 1,
  +                BufferedImage.TYPE_INT_ARGB);
  +        // We use this to get a good colormodel..
  +        static BufferedImage BIWithOutAlpha = new BufferedImage(1, 1,
  +                BufferedImage.TYPE_INT_RGB);
  +
  +        /**
  +         * Construct a buffered image with an alpha channel, unless
  +         * transparencty is OPAQUE (no alpha at all).
  +         */
  +        public BufferedImage createCompatibleImage(int width, int height,
  +                                                   int transparency) {
  +            if (transparency == Transparency.OPAQUE)
  +                return new BufferedImage(width, height,
  +                                         BufferedImage.TYPE_INT_RGB);
  +            else
  +                return new BufferedImage(width, height,
  +                                         BufferedImage.TYPE_INT_ARGB);
  +        }
  +
  +        /**
  +         * Construct a buffered image with an alpha channel.
  +         */
  +        public BufferedImage createCompatibleImage(int width, int height) {
  +            return new BufferedImage(width, height,
  +                                     BufferedImage.TYPE_INT_ARGB);
  +        }
  +
  +        /**
  +         * FIXX ME: This should return the page bounds in Pts,
  +         * I couldn't figure out how to get this for the current
  +         * page from the PDFDocument (this still works for now,
  +         * but it should be fixed...).
  +         */
  +        public Rectangle getBounds() {
  +System.out.println("getting getBounds");
  +            return null;
  +        }
  +
  +        /**
  +         * Return a good default color model for this 'device'.
  +         */
  +        public ColorModel getColorModel() {
  +            return BIWithAlpha.getColorModel();
  +        }
  +
  +        /**
  +         * Return a good color model given <tt>transparency</tt>
  +         */
  +        public ColorModel getColorModel(int transparency) {
  +            if (transparency == Transparency.OPAQUE)
  +                return BIWithOutAlpha.getColorModel();
  +            else
  +                return BIWithAlpha.getColorModel();
  +        }
  +
  +        /**
  +         * The default transform (1:1).
  +         */
  +        public AffineTransform getDefaultTransform() {
  +System.out.println("getting getDefaultTransform");
  +            return new AffineTransform();
  +        }
  +
  +        /**
  +         * The normalizing transform (1:1) (since we currently
  +         * render images at 72dpi, which we might want to change
  +         * in the future).
  +         */
  +        public AffineTransform getNormalizingTransform() {
  +System.out.println("getting getNormalizingTransform");
  +            return new AffineTransform(2, 0, 0, 2, 0, 0);
  +        }
  +
  +        /**
  +         * Return our dummy instance of GraphicsDevice
  +         */
  +        public GraphicsDevice getDevice() {
  +            return new PDFGraphicsDevice(this);
  +        }
  +
  +        // needed for compiling under jdk1.4
  +        //public java.awt.image.VolatileImage createCompatibleVolatileImage(int width, int height) {
  +        //    return null;
  +        //}
  +
  +    }
  +
  +    /**
  +     * This implements the GraphicsDevice interface as appropriate for
  +     * a PDFGraphics2D.  This is quite simple since we only have one
  +     * GraphicsConfiguration for now (this might change in the future
  +     * I suppose).
  +     */
  +    static class PDFGraphicsDevice extends GraphicsDevice {
  +
  +        /**
  +         * The Graphics Config that created us...
  +         */
  +        GraphicsConfiguration gc;
  +
  +        /**
  +         * @param The gc we should reference
  +         */
  +        PDFGraphicsDevice(PDFGraphicsConfiguration gc) {
  +            this.gc = gc;
  +        }
  +
  +        /**
  +         * Ignore template and return the only config we have
  +         */
  +        public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) {
  +            return gc;
  +        }
  +
  +        /**
  +         * Return an array of our one GraphicsConfig
  +         */
  +        public GraphicsConfiguration[] getConfigurations() {
  +            return new GraphicsConfiguration[] {
  +                gc
  +            };
  +        }
  +
  +        /**
  +         * Return out sole GraphicsConfig.
  +         */
  +        public GraphicsConfiguration getDefaultConfiguration() {
  +            return gc;
  +        }
  +
  +        /**
  +         * Generate an IdString..
  +         */
  +        public String getIDstring() {
  +            return toString();
  +        }
  +
  +        /**
  +         * Let the caller know that we are "a printer"
  +         */
  +        public int getType() {
  +            return GraphicsDevice.TYPE_PRINTER;
  +        }
  +
  +    }
  +
  +    /**
  +     * Used to create proper font metrics
  +     */
  +    private Graphics2D fmg;
  +
  +    {
  +        BufferedImage bi = new BufferedImage(1, 1,
  +                                             BufferedImage.TYPE_INT_ARGB);
  +
  +        fmg = bi.createGraphics();
  +    }
  +
  +    /**
  +     * Gets the font metrics for the specified font.
  +     * @return    the font metrics for the specified font.
  +     * @param     f the specified font
  +     * @see       java.awt.Graphics#getFont
  +     * @see       java.awt.FontMetrics
  +     * @see       java.awt.Graphics#getFontMetrics()
  +     */
  +    public FontMetrics getFontMetrics(Font f) {
  +        return fmg.getFontMetrics(f);
  +    }
  +
  +    /**
  +     * Sets the paint mode of this graphics context to alternate between
  +     * this graphics context's current color and the new specified color.
  +     * This specifies that logical pixel operations are performed in the
  +     * XOR mode, which alternates pixels between the current color and
  +     * a specified XOR color.
  +     * <p>
  +     * When drawing operations are performed, pixels which are the
  +     * current color are changed to the specified color, and vice versa.
  +     * <p>
  +     * Pixels that are of colors other than those two colors are changed
  +     * in an unpredictable but reversible manner; if the same figure is
  +     * drawn twice, then all pixels are restored to their original values.
  +     * @param     c1 the XOR alternation color
  +     */
  +    public void setXORMode(Color c1) {
  +        System.out.println("setXORMode");
  +    }
  +
  +
  +    /**
  +     * Copies an area of the component by a distance specified by
  +     * <code>dx</code> and <code>dy</code>. From the point specified
  +     * by <code>x</code> and <code>y</code>, this method
  +     * copies downwards and to the right.  To copy an area of the
  +     * component to the left or upwards, specify a negative value for
  +     * <code>dx</code> or <code>dy</code>.
  +     * If a portion of the source rectangle lies outside the bounds
  +     * of the component, or is obscured by another window or component,
  +     * <code>copyArea</code> will be unable to copy the associated
  +     * pixels. The area that is omitted can be refreshed by calling
  +     * the component's <code>paint</code> method.
  +     * @param       x the <i>x</i> coordinate of the source rectangle.
  +     * @param       y the <i>y</i> coordinate of the source rectangle.
  +     * @param       width the width of the source rectangle.
  +     * @param       height the height of the source rectangle.
  +     * @param       dx the horizontal distance to copy the pixels.
  +     * @param       dy the vertical distance to copy the pixels.
  +     */
  +    public void copyArea(int x, int y, int width, int height, int dx,
  +                         int dy) {
  +        System.out.println("copyArea");
  +    }
  +
  +}
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: fop-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: fop-cvs-help@xml.apache.org