]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Promoting the PCL renderer from sandbox to the main source tree.
authorJeremias Maerki <jeremias@apache.org>
Mon, 24 Jul 2006 13:16:23 +0000 (13:16 +0000)
committerJeremias Maerki <jeremias@apache.org>
Mon, 24 Jul 2006 13:16:23 +0000 (13:16 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@425038 13f79535-47bb-0310-9956-ffa450edef68

26 files changed:
src/java/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/MonochromeBitmapConverter.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLGenerator.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLGraphics2D.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLPageDefinition.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLRenderer.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLRendererContext.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLRendererMaker.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/PCLSVGHandler.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/extensions/PCLElementMapping.java [new file with mode: 0644]
src/java/org/apache/fop/render/pcl/package.html [new file with mode: 0644]
src/sandbox/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/MonochromeBitmapConverter.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLPageDefinition.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLRendererContext.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLRendererMaker.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/PCLSVGHandler.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/extensions/PCLElementMapping.java [deleted file]
src/sandbox/org/apache/fop/render/pcl/package.html [deleted file]

diff --git a/src/java/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java b/src/java/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java
new file mode 100644 (file)
index 0000000..4358044
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.RenderedImage;
+
+/**
+ * Default implementation of the MonochromeBitmapConverter which uses the Java Class Library
+ * to convert grayscale bitmaps to monochrome bitmaps.
+ */
+public class DefaultMonochromeBitmapConverter implements
+        MonochromeBitmapConverter {
+
+    /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
+    public void setHint(String name, String value) {
+        //ignore, not supported
+    }
+    
+    /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
+    public RenderedImage convertToMonochrome(BufferedImage img) {
+        BufferedImage buf = new BufferedImage(img.getWidth(), img.getHeight(), 
+                BufferedImage.TYPE_BYTE_BINARY);
+        RenderingHints hints = new RenderingHints(null);
+        //This hint doesn't seem to make a difference :-(
+        hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
+        ColorConvertOp op = new ColorConvertOp(
+                ColorSpace.getInstance(ColorSpace.CS_GRAY), hints);
+        op.filter(img, buf);
+        return buf;
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java b/src/java/org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java
new file mode 100644 (file)
index 0000000..4818b2b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.ParameterBlock;
+
+import javax.media.jai.ColorCube;
+import javax.media.jai.ImageLayout;
+import javax.media.jai.JAI;
+import javax.media.jai.KernelJAI;
+import javax.media.jai.LookupTableJAI;
+import javax.media.jai.PlanarImage;
+
+/**
+ * Implementation of the MonochromeBitmapConverter which uses Java Advanced Imaging (JAI)
+ * to convert grayscale bitmaps to monochrome bitmaps. JAI provides better dithering options
+ * including error diffusion dithering.
+ * <p>
+ * If you call setHint("quality", "true") on the instance you can enabled error diffusion
+ * dithering which produces a nicer result but is also a lot slower.
+ */
+public class JAIMonochromeBitmapConverter implements
+        MonochromeBitmapConverter {
+
+    private boolean isErrorDiffusion = false;
+    
+    /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
+    public void setHint(String name, String value) {
+        if ("quality".equalsIgnoreCase(name)) {
+            isErrorDiffusion = "true".equalsIgnoreCase(value);
+        }
+    }
+    
+    /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
+    public RenderedImage convertToMonochrome(BufferedImage img) {
+        if (img.getColorModel().getColorSpace().getNumComponents() != 1) {
+            throw new IllegalArgumentException("Source image must be a grayscale image!");
+        }
+        
+        // Load the ParameterBlock for the dithering operation
+        // and set the operation name.
+        ParameterBlock pb = new ParameterBlock();
+        pb.addSource(img);
+        String opName = null;
+        if (isErrorDiffusion) {
+            opName = "errordiffusion";
+            LookupTableJAI lut = new LookupTableJAI(new byte[] {(byte)0x00, (byte)0xff});
+            pb.add(lut);
+            pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);
+        } else {
+            opName = "ordereddither";
+            //Create the color cube.
+            ColorCube colorMap = ColorCube.createColorCube(DataBuffer.TYPE_BYTE,
+                    0, new int[] {2});
+            pb.add(colorMap);
+            pb.add(KernelJAI.DITHER_MASK_441);
+        }
+        
+        //Create an image layout for a monochrome b/w image
+        ImageLayout layout = new ImageLayout();
+        byte[] map = new byte[] {(byte)0x00, (byte)0xff};
+        ColorModel cm = new IndexColorModel(1, 2, map, map, map);
+        layout.setColorModel(cm);
+
+        // Create a hint containing the layout.
+        RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
+
+        // Dither the image.
+        PlanarImage dst = JAI.create(opName, pb, hints);        
+        
+        //Convert it to a BufferedImage
+        return dst.getAsBufferedImage();
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/MonochromeBitmapConverter.java b/src/java/org/apache/fop/render/pcl/MonochromeBitmapConverter.java
new file mode 100644 (file)
index 0000000..f2db9d7
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+
+/**
+ * Interface for converters that convert grayscale images to monochrome (1-bit) bitmap images.
+ */
+public interface MonochromeBitmapConverter {
+
+    /**
+     * Sets a hint to the implementation
+     * @param name the name of the hint
+     * @param value the value
+     */
+    void setHint(String name, String value);
+    
+    /**
+     * Converts a grayscale bitmap image to a monochrome (1-bit) b/w bitmap image. 
+     * @param img the grayscale image
+     * @return the converted monochrome image
+     */
+    RenderedImage convertToMonochrome(BufferedImage img);
+    
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLGenerator.java b/src/java/org/apache/fop/render/pcl/PCLGenerator.java
new file mode 100644 (file)
index 0000000..8612a51
--- /dev/null
@@ -0,0 +1,751 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ByteLookupTable;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
+import java.awt.image.LookupOp;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+import org.apache.fop.util.UnitConv;
+import org.apache.xmlgraphics.image.GraphicsUtil;
+
+/**
+ * This class provides methods for generating PCL print files.
+ */
+public class PCLGenerator {
+
+    /** The ESC (escape) character */
+    public static final char ESC = '\033';
+    
+    /** A list of all supported resolutions in PCL (values in dpi) */
+    public static final int[] PCL_RESOLUTIONS = new int[] {75, 100, 150, 200, 300, 600};
+    
+    private final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); 
+    private final DecimalFormat df2 = new DecimalFormat("0.##", symbols);
+    private final DecimalFormat df4 = new DecimalFormat("0.####", symbols);
+    
+    private OutputStream out;
+    
+    private boolean currentSourceTransparency = true;
+    private boolean currentPatternTransparency = true;
+    
+    private int maxBitmapResolution = PCL_RESOLUTIONS[PCL_RESOLUTIONS.length - 1];
+    
+    /**
+     * Main constructor.
+     * @param out the OutputStream to write the PCL stream to
+     */
+    public PCLGenerator(OutputStream out) {
+        this.out = out;
+    }
+    
+    /**
+     * Main constructor.
+     * @param out the OutputStream to write the PCL stream to
+     * @param maxResolution the maximum resolution to encode bitmap images at
+     */
+    public PCLGenerator(OutputStream out, int maxResolution) {
+        this(out);
+        boolean found = false;
+        for (int i = 0; i < PCL_RESOLUTIONS.length; i++) {
+            if (PCL_RESOLUTIONS[i] == maxResolution) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            throw new IllegalArgumentException("Illegal value for maximum resolution!");
+        }
+        this.maxBitmapResolution = maxResolution;
+    }
+    
+    /** @return the OutputStream that this generator writes to */
+    public OutputStream getOutputStream() {
+        return this.out;
+    }
+    
+    /** @return the maximum resolution to encode bitmap images at */
+    public int getMaximumBitmapResolution() {
+        return this.maxBitmapResolution;
+    }
+    
+    /**
+     * Writes a PCL escape command to the output stream.
+     * @param cmd the command (without the ESCAPE character)
+     * @throws IOException In case of an I/O error
+     */
+    public void writeCommand(String cmd) throws IOException {
+        out.write(27); //ESC
+        out.write(cmd.getBytes("US-ASCII"));
+    }
+    
+    /**
+     * Writes raw text (in ISO-8859-1 encoding) to the output stream.
+     * @param s the text
+     * @throws IOException In case of an I/O error
+     */
+    public void writeText(String s) throws IOException {
+        out.write(s.getBytes("ISO-8859-1"));
+    }
+
+    /**
+     * Formats a double value with two decimal positions for PCL output.
+     * 
+     * @param value value to format
+     * @return the formatted value
+     */
+    public final String formatDouble2(double value) {
+        return df2.format(value);
+    }
+
+    /**
+     * Formats a double value with four decimal positions for PCL output.
+     * 
+     * @param value value to format
+     * @return the formatted value
+     */
+    public final String formatDouble4(double value) {
+        return df4.format(value);
+    }
+
+    /**
+     * Sends the universal end of language command (UEL).
+     * @throws IOException In case of an I/O error
+     */
+    public void universalEndOfLanguage() throws IOException {
+        writeCommand("%-12345X");
+    }
+    
+    /**
+     * Resets the printer and restores the user default environment.
+     * @throws IOException In case of an I/O error
+     */
+    public void resetPrinter() throws IOException {
+        writeCommand("E");
+    }
+    
+    /**
+     * Sends the job separation command.
+     * @throws IOException In case of an I/O error
+     */
+    public void separateJobs() throws IOException {
+        writeCommand("&l1T");
+    }
+    
+    /**
+     * Sends the form feed character.
+     * @throws IOException In case of an I/O error
+     */
+    public void formFeed() throws IOException {
+        out.write(12); //=OC ("FF", Form feed)
+    }
+
+    /**
+     * Sets the unit of measure.
+     * @param value the resolution value (units per inch)
+     * @throws IOException In case of an I/O error
+     */
+    public void setUnitOfMeasure(int value) throws IOException {
+        writeCommand("&u" + value + "D");
+    }
+    
+    /**
+     * Sets the raster graphics resolution
+     * @param value the resolution value (units per inch)
+     * @throws IOException In case of an I/O error
+     */
+    public void setRasterGraphicsResolution(int value) throws IOException {
+        writeCommand("*t" + value + "R");
+    }
+    
+    /**
+     * Selects the page size.
+     * @param selector the integer representing the page size
+     * @throws IOException In case of an I/O error
+     */
+    public void selectPageSize(int selector) throws IOException {
+        writeCommand("&l" + selector + "A");
+    }
+
+    /**
+     * Selects the paper source. The parameter is usually printer-specific. Usually, "1" is the 
+     * default tray, "2" is the manual paper feed, "3" is the manual envelope feed, "4" is the
+     * "lower" tray and "7" is "auto-select". Consult the technical reference for your printer
+     * for all available values.
+     * @param selector the integer representing the paper source/tray
+     * @throws IOException In case of an I/O error
+     */
+    public void selectPaperSource(int selector) throws IOException {
+        writeCommand("&l" + selector + "H");
+    }
+
+    /**
+     * Clears the horizontal margins.
+     * @throws IOException In case of an I/O error
+     */
+    public void clearHorizontalMargins() throws IOException {
+        writeCommand("9");
+    }
+    
+    /**
+     * The Top Margin command designates the number of lines between
+     * the top of the logical page and the top of the text area.
+     * @param numberOfLines the number of lines (See PCL specification for details)
+     * @throws IOException In case of an I/O error
+     */
+    public void setTopMargin(int numberOfLines) throws IOException {
+        writeCommand("&l" + numberOfLines + "E");
+    }
+
+    /**
+     * The Text Length command can be used to define the bottom border. See the PCL specification
+     * for details.
+     * @param numberOfLines the number of lines
+     * @throws IOException In case of an I/O error
+     */
+    public void setTextLength(int numberOfLines) throws IOException {
+        writeCommand("&l" + numberOfLines + "F");
+    }
+
+    /**
+     * Sets the Vertical Motion Index (VMI).
+     * @param value the VMI value
+     * @throws IOException In case of an I/O error
+     */
+    public void setVMI(double value) throws IOException {
+        writeCommand("&l" + formatDouble4(value) + "C");
+    }
+
+    /**
+     * Sets the cursor to a new absolute coordinate.
+     * @param x the X coordinate (in millipoints)
+     * @param y the Y coordinate (in millipoints)
+     * @throws IOException In case of an I/O error
+     */
+    public void setCursorPos(double x, double y) throws IOException {
+        if (x < 0) {
+            //A negative x value will result in a relative movement so go to "0" first.
+            //But this will most probably have no effect anyway since you can't paint to the left
+            //of the logical page
+            writeCommand("&a0h" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
+        } else {
+            writeCommand("&a" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
+        }
+    }
+
+    /**
+     * Pushes the current cursor position on a stack (stack size: max 20 entries)
+     * @throws IOException In case of an I/O error
+     */
+    public void pushCursorPos() throws IOException {
+        writeCommand("&f0S");
+    }
+    
+    /**
+     * Pops the current cursor position from the stack.
+     * @throws IOException In case of an I/O error
+     */
+    public void popCursorPos() throws IOException {
+        writeCommand("&f1S");
+    }
+    
+    /**
+     * Changes the current print direction while maintaining the current cursor position.
+     * @param rotate the rotation angle (counterclockwise), one of 0, 90, 180 and 270.
+     * @throws IOException In case of an I/O error
+     */
+    public void changePrintDirection(int rotate) throws IOException {
+        writeCommand("&a" + rotate + "P");
+    }
+    
+    /**
+     * Enters the HP GL/2 mode.
+     * @param restorePreviousHPGL2Cursor true if the previous HP GL/2 pen position should be 
+     *                                   restored, false if the current position is maintained
+     * @throws IOException In case of an I/O error
+     */
+    public void enterHPGL2Mode(boolean restorePreviousHPGL2Cursor) throws IOException {
+        if (restorePreviousHPGL2Cursor) {
+            writeCommand("%0B");
+        } else {
+            writeCommand("%1B");
+        }
+    }
+    
+    /**
+     * Enters the PCL mode.
+     * @param restorePreviousPCLCursor true if the previous PCL cursor position should be restored,
+     *                                 false if the current position is maintained
+     * @throws IOException In case of an I/O error
+     */
+    public void enterPCLMode(boolean restorePreviousPCLCursor) throws IOException {
+        if (restorePreviousPCLCursor) {
+            writeCommand("%0A");
+        } else {
+            writeCommand("%1A");
+        }
+    }
+    
+    /**
+     * Generate a filled rectangle at the current cursor position.
+     *
+     * @param w the width in millipoints
+     * @param h the height in millipoints
+     * @param col the fill color
+     * @throws IOException In case of an I/O error
+     */
+    protected void fillRect(int w, int h, Color col) throws IOException {
+        if ((w == 0) || (h == 0)) {
+            return;
+        }
+        if (h < 0) {
+            h *= -1;
+        } else {
+            //y += h;
+        }
+
+        setPatternTransparencyMode(false);
+        writeCommand("*c" + formatDouble4(w / 100) + "h" 
+                          + formatDouble4(h / 100) + "V");
+        int lineshade = convertToPCLShade(col);
+        writeCommand("*c" + lineshade + "G");
+        writeCommand("*c2P");
+        // Reset pattern transparency mode.
+        setPatternTransparencyMode(true);
+    }
+
+    /**
+     * Sets the source transparency mode.
+     * @param transparent true if transparent, false for opaque
+     * @throws IOException In case of an I/O error
+     */
+    public void setSourceTransparencyMode(boolean transparent) throws IOException {
+        setTransparencyMode(transparent, currentPatternTransparency);
+    }
+
+    /**
+     * Sets the pattern transparency mode.
+     * @param transparent true if transparent, false for opaque
+     * @throws IOException In case of an I/O error
+     */
+    public void setPatternTransparencyMode(boolean transparent) throws IOException {
+        setTransparencyMode(currentSourceTransparency, transparent);
+    }
+
+    /**
+     * Sets the transparency modes.
+     * @param source source transparency: true if transparent, false for opaque
+     * @param pattern pattern transparency: true if transparent, false for opaque
+     * @throws IOException In case of an I/O error
+     */
+    public void setTransparencyMode(boolean source, boolean pattern) throws IOException {
+        if (source != currentSourceTransparency && pattern != currentPatternTransparency) {
+            writeCommand("*v" + (source ? '0' : '1') + "n" + (pattern ? '0' : '1') + "O");
+        } else if (source != currentSourceTransparency) {
+            writeCommand("*v" + (source ? '0' : '1') + "N");
+        } else if (pattern != currentPatternTransparency) {
+            writeCommand("*v" + (pattern ? '0' : '1') + "O");
+        }
+        this.currentSourceTransparency = source;
+        this.currentPatternTransparency = pattern;
+    }
+
+    /**
+     * Convert an RGB color value to a grayscale from 0 to 100.
+     * @param r the red component
+     * @param g the green component
+     * @param b the blue component
+     * @return the gray value
+     */
+    public final int convertToGray(int r, int g, int b) {
+        return (r * 30 + g * 59 + b * 11) / 100;
+    }
+    
+    /**
+     * Convert a Color value to a PCL shade value (0-100).
+     * @param col the color
+     * @return the PCL shade value (100=black)
+     */
+    public final int convertToPCLShade(Color col) {
+        float gray = convertToGray(col.getRed(), col.getGreen(), col.getBlue()) / 255f;
+        return (int)(100 - (gray * 100f));
+    }
+    
+    /**
+     * Select the current pattern
+     * @param patternID the pattern ID (<ESC>*c#G command)
+     * @param pattern the pattern type (<ESC>*v#T command)
+     * @throws IOException In case of an I/O error
+     */
+    public void selectCurrentPattern(int patternID, int pattern) throws IOException {
+        if (pattern > 1) {
+            writeCommand("*c" + patternID + "G");
+        }
+        writeCommand("*v" + pattern + "T");
+    }
+
+    /**
+     * Indicates whether an image is a monochrome (b/w) image.
+     * @param img the image
+     * @return true if it's a monochrome image
+     */
+    public static boolean isMonochromeImage(RenderedImage img) {
+        ColorModel cm = img.getColorModel();
+        if (cm instanceof IndexColorModel) {
+            IndexColorModel icm = (IndexColorModel)cm;
+            return icm.getMapSize() == 2;
+        } else {
+            return false;
+        }
+    }
+    
+    /**
+     * Indicates whether an image is a grayscale image.
+     * @param img the image
+     * @return true if it's a grayscale image
+     */
+    public static boolean isGrayscaleImage(RenderedImage img) {
+        return (img.getColorModel().getColorSpace().getNumComponents() == 1);
+    }
+    
+    private MonochromeBitmapConverter createMonochromeBitmapConverter() {
+        MonochromeBitmapConverter converter = null;
+        try {
+            String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
+            Class clazz = Class.forName(clName);
+            converter = (MonochromeBitmapConverter)clazz.newInstance();
+        } catch (ClassNotFoundException cnfe) {
+            // Class was not compiled so is not available. Simply ignore.
+        } catch (LinkageError le) {
+            // This can happen if fop was build with support for a
+            // particular provider (e.g. a binary fop distribution)
+            // but the required support files (i.e. JAI) are not
+            // available in the current runtime environment.
+            // Simply continue with the backup implementation.
+        } catch (InstantiationException e) {
+            // Problem instantiating the class, simply continue with the backup implementation
+        } catch (IllegalAccessException e) {
+            // Problem instantiating the class, simply continue with the backup implementation
+        }
+        if (converter == null) {
+            converter = new DefaultMonochromeBitmapConverter();
+        }
+        return converter;
+    }
+
+    private int calculatePCLResolution(int resolution) {
+        return calculatePCLResolution(resolution, false);
+    }
+    
+    /**
+     * Calculates the ideal PCL resolution for a given resolution.
+     * @param resolution the input resolution
+     * @param increased true if you want to go to a higher resolution, for example if you
+     *                  convert grayscale or color images to monochrome images so dithering has
+     *                  a chance to generate better quality.
+     * @return the resulting PCL resolution (one of 75, 100, 150, 200, 300, 600)
+     */
+    private int calculatePCLResolution(int resolution, boolean increased) {
+        int choice = -1;
+        for (int i = PCL_RESOLUTIONS.length - 2; i >= 0; i--) {
+            if (resolution > PCL_RESOLUTIONS[i]) {
+                int idx = i + 1;
+                if (idx < PCL_RESOLUTIONS.length - 2) {
+                    idx += increased ? 2 : 0;
+                } else if (idx < PCL_RESOLUTIONS.length - 1) {
+                    idx += increased ? 1 : 0;
+                }
+                choice = idx;
+                break;
+                //return PCL_RESOLUTIONS[idx];
+            }
+        }
+        if (choice < 0) {
+            choice = (increased ? 2 : 0);
+        }
+        while (choice > 0 && PCL_RESOLUTIONS[choice] > getMaximumBitmapResolution()) {
+            choice--;
+        }
+        return PCL_RESOLUTIONS[choice];
+    }
+    
+    private boolean isValidPCLResolution(int resolution) {
+        return resolution == calculatePCLResolution(resolution);
+    }
+    
+    private Dimension getAdjustedDimension(Dimension orgDim, double orgResolution, 
+            int pclResolution) {
+        if (orgResolution == pclResolution) {
+            return orgDim;
+        } else {
+            Dimension result = new Dimension();
+            result.width = (int)Math.round((double)orgDim.width * pclResolution / orgResolution); 
+            result.height = (int)Math.round((double)orgDim.height * pclResolution / orgResolution); 
+            return result;
+        }
+    }
+    
+    //Threshold table to convert an alpha channel (8-bit) into a clip mask (1-bit)
+    private static final byte[] THRESHOLD_TABLE = new byte[256];
+    static { // Initialize the arrays
+        for (int i = 0; i < 256; i++) {
+            THRESHOLD_TABLE[i] = (byte) ((i < 240) ? 255 : 0);
+        }
+    }    
+    
+    private RenderedImage getMask(RenderedImage img, Dimension targetDim) {
+        ColorModel cm = img.getColorModel(); 
+        if (cm.hasAlpha()) {
+            BufferedImage alpha = new BufferedImage(img.getWidth(), img.getHeight(), 
+                    BufferedImage.TYPE_BYTE_GRAY);
+            Raster raster = img.getData();
+            GraphicsUtil.copyBand(raster, cm.getNumColorComponents(), alpha.getRaster(), 0);
+
+            BufferedImageOp op1 = new LookupOp(new ByteLookupTable(0, THRESHOLD_TABLE), null);
+            BufferedImage alphat = op1.filter(alpha, null);
+
+            BufferedImage mask;
+            if (true) {
+                mask = new BufferedImage(targetDim.width, targetDim.height,
+                        BufferedImage.TYPE_BYTE_BINARY);
+            } else {
+                byte[] arr = {(byte)0, (byte)0xff};
+                ColorModel colorModel = new IndexColorModel(1, 2, arr, arr, arr);
+                WritableRaster wraster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
+                                                   targetDim.width, targetDim.height, 1, 1, null);
+                mask = new BufferedImage(colorModel, wraster, false, null);
+            }
+            
+            Graphics2D g2d = mask.createGraphics();
+            try {
+                AffineTransform at = new AffineTransform();
+                double sx = targetDim.getWidth() / img.getWidth();
+                double sy = targetDim.getHeight() / img.getHeight();
+                at.scale(sx, sy);
+                g2d.drawRenderedImage(alphat, at);
+            } finally {
+                g2d.dispose();
+            }
+            /*
+            try {
+                BatchDiffer.saveAsPNG(alpha, new java.io.File("D:/out-alpha.png"));
+                BatchDiffer.saveAsPNG(mask, new java.io.File("D:/out-mask.png"));
+            } catch (IOException e) {
+                e.printStackTrace();
+            }*/
+            return mask;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Paint a bitmap at the current cursor position. The bitmap is converted to a monochrome
+     * (1-bit) bitmap image.
+     * @param img the bitmap image
+     * @param targetDim the target Dimention (in mpt)
+     * @param sourceTransparency true if the background should not be erased
+     * @throws IOException In case of an I/O error
+     */
+    public void paintBitmap(RenderedImage img, Dimension targetDim, boolean sourceTransparency) 
+                throws IOException {
+        double targetResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width);
+        int resolution = (int)Math.round(targetResolution);
+        int effResolution = calculatePCLResolution(resolution, true);
+        Dimension orgDim = new Dimension(img.getWidth(), img.getHeight());
+        Dimension effDim = getAdjustedDimension(orgDim, targetResolution, effResolution);
+        boolean scaled = !orgDim.equals(effDim);
+
+        boolean monochrome = isMonochromeImage(img);
+        if (!monochrome) {
+            //Transparency mask disabled. Doesn't work reliably
+            final boolean transparencyDisabled = true;
+            RenderedImage mask = (transparencyDisabled ? null : getMask(img, effDim)); 
+            if (mask != null) {
+                pushCursorPos();
+                selectCurrentPattern(0, 1); //Solid white
+                setTransparencyMode(true, true);
+                paintMonochromeBitmap(mask, effResolution);
+                popCursorPos();
+            }
+            
+            BufferedImage src = null;
+            if (img instanceof BufferedImage && !scaled) {
+                if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) {
+                    src = new BufferedImage(effDim.width, effDim.height, 
+                            BufferedImage.TYPE_BYTE_GRAY);
+                    ColorConvertOp op = new ColorConvertOp(
+                            ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
+                    op.filter((BufferedImage)img, src);
+                } else {
+                    src = (BufferedImage)img;
+                }
+            }
+            if (src == null) {
+                src = new BufferedImage(effDim.width, effDim.height, 
+                        BufferedImage.TYPE_BYTE_GRAY);
+                Graphics2D g2d = src.createGraphics();
+                try {
+                    AffineTransform at = new AffineTransform();
+                    double sx = effDim.getWidth() / orgDim.getWidth();
+                    double sy = effDim.getHeight() / orgDim.getHeight();
+                    at.scale(sx, sy);
+                    g2d.drawRenderedImage(img, at);
+                } finally {
+                    g2d.dispose();
+                }
+            }
+            MonochromeBitmapConverter converter = createMonochromeBitmapConverter();
+            converter.setHint("quality", "false");
+
+            BufferedImage buf = (BufferedImage)converter.convertToMonochrome(src);
+            
+            RenderedImage red = buf;
+            selectCurrentPattern(0, 0); //Solid black
+            setTransparencyMode(sourceTransparency || mask != null, true);
+            paintMonochromeBitmap(red, effResolution);
+        } else {
+            //TODO untested!
+            RenderedImage effImg = img;
+            if (scaled) {
+                BufferedImage buf = new BufferedImage(effDim.width, effDim.height, 
+                        BufferedImage.TYPE_BYTE_BINARY);
+                Graphics2D g2d = buf.createGraphics();
+                try {
+                    AffineTransform at = new AffineTransform();
+                    double sx = effDim.getWidth() / orgDim.getWidth();
+                    double sy = effDim.getHeight() / orgDim.getHeight();
+                    at.scale(sx, sy);
+                    g2d.drawRenderedImage(img, at);
+                } finally {
+                    g2d.dispose();
+                }
+                effImg = buf;
+            }
+            setSourceTransparencyMode(sourceTransparency);
+            selectCurrentPattern(0, 0); //Solid black
+            paintMonochromeBitmap(effImg, effResolution);
+        }
+    }
+
+    /**
+     * Paint a bitmap at the current cursor position. The bitmap must be a monochrome
+     * (1-bit) bitmap image.
+     * @param img the bitmap image (must be 1-bit b/w)
+     * @param resolution the resolution of the image (must be a PCL resolution)
+     * @throws IOException In case of an I/O error
+     */
+    public void paintMonochromeBitmap(RenderedImage img, int resolution) throws IOException {
+        if (!isValidPCLResolution(resolution)) {
+            throw new IllegalArgumentException("Invalid PCL resolution: " + resolution);
+        }
+        setRasterGraphicsResolution(resolution);
+        writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
+        Raster raster = img.getData();
+        boolean monochrome = isMonochromeImage(img);
+        if (!monochrome) {
+            throw new IllegalArgumentException("img must be a monochrome image");
+        }
+        
+        int x = 0;
+        int y = 0;
+        int imgw = img.getWidth();
+        int imgh = img.getHeight();
+        int bytewidth = (imgw / 8);
+        if ((imgw % 8) != 0) {
+            bytewidth++;
+        }
+        byte ib;
+        byte[] rle = new byte[bytewidth * 2]; //compressed (RLE)
+        byte[] uncompressed = new byte[bytewidth]; //uncompressed
+        int lastcount = -1;
+        byte lastbyte = 0;
+        int rlewidth = 0;
+
+        // Transfer graphics data
+        for (y = 0; y < imgh; y++) {
+            ib = 0;
+            for (x = 0; x < imgw; x++) {
+                int sample = raster.getSample(x, y, 0);
+                //Set image bit for black
+                if ((sample == 0)) {
+                    ib |= (1 << (7 - (x % 8)));
+                }
+                    
+                //RLE encoding
+                if ((x % 8) == 7 || ((x + 1) == imgw)) {
+                    if (rlewidth < bytewidth) {
+                        if (lastcount >= 0) {
+                            if (ib == lastbyte) {
+                                lastcount++;
+                            } else {
+                                rle[rlewidth++] = (byte)(lastcount & 0xFF);
+                                rle[rlewidth++] = lastbyte;
+                                lastbyte = ib;
+                                lastcount = 0;
+                            }
+                        } else {
+                            lastbyte = ib;
+                            lastcount = 0;
+                        }
+                        if (lastcount == 255 || ((x + 1) == imgw)) {
+                            rle[rlewidth++] = (byte)(lastcount & 0xFF);
+                            rle[rlewidth++] = lastbyte;
+                            lastbyte = 0;
+                            lastcount = -1;
+                        }
+                    }
+                    uncompressed[x / 8] = ib;
+                    ib = 0;
+                }
+            }
+            if (rlewidth < bytewidth) {
+                writeCommand("*b1m" + rlewidth + "W");
+                this.out.write(rle, 0, rlewidth);
+            } else {
+                writeCommand("*b0m" + bytewidth + "W");
+                this.out.write(uncompressed);
+            }
+            lastcount = -1;
+            rlewidth = 0;
+        }
+
+        // End raster graphics
+        writeCommand("*rB");
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLGraphics2D.java b/src/java/org/apache/fop/render/pcl/PCLGraphics2D.java
new file mode 100644 (file)
index 0000000..0e27a8d
--- /dev/null
@@ -0,0 +1,615 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.io.IOException;
+import java.text.AttributedCharacterIterator;
+
+import org.apache.fop.util.UnitConv;
+import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+/**
+ * Graphics2D implementation implementing PCL and HP GL/2.
+ * Note: This class cannot be used stand-alone to create full PCL documents.
+ */
+public class PCLGraphics2D extends AbstractGraphics2D {
+
+    /** The PCL generator */
+    protected PCLGenerator gen;
+    
+    private boolean failOnUnsupportedFeature = true;
+    private boolean clippingDisabled = false;
+    
+    /**
+     * Create a new PCLGraphics2D.
+     * @param gen the PCL Generator to paint with
+     */
+    public PCLGraphics2D(PCLGenerator gen) {
+        super(true);
+        this.gen = gen;
+    }
+
+    /**
+     * Copy constructor
+     * @param g parent PCLGraphics2D
+     */
+    public PCLGraphics2D(PCLGraphics2D g) {
+        super(true);
+        this.gen = g.gen;
+    }
+
+    /** @see java.awt.Graphics#create() */
+    public Graphics create() {
+        PCLGraphics2D copy = new PCLGraphics2D(this);
+        copy.setGraphicContext((GraphicContext)getGraphicContext().clone());
+        return copy;
+    }
+
+    /** @see java.awt.Graphics#dispose() */
+    public void dispose() {
+        this.gen = null;
+    }
+
+    /**
+     * Sets the GraphicContext
+     * @param c GraphicContext to use
+     */
+    public void setGraphicContext(GraphicContext c) {
+        this.gc = c;
+    }
+
+    /**
+     * Allows to disable all clipping operations.
+     * @param value true if clipping should be disabled.
+     */
+    public void setClippingDisabled(boolean value) {
+        this.clippingDisabled = value;
+    }
+    
+    /**
+     * Central handler for IOExceptions for this class.
+     * @param ioe IOException to handle
+     */
+    public void handleIOException(IOException ioe) {
+        //TODO Surely, there's a better way to do this.
+        ioe.printStackTrace();
+    }
+
+    /**
+     * Raises an UnsupportedOperationException if this instance is configured to do so and an
+     * unsupported feature has been requested. Clients can make use of this to fall back to
+     * a more compatible way of painting a PCL graphic.
+     * @param msg the error message to be displayed
+     */
+    protected void handleUnsupportedFeature(String msg) {
+        if (this.failOnUnsupportedFeature) {
+            throw new UnsupportedOperationException(msg);
+        }
+    }
+    
+    /** @see java.awt.Graphics2D#getDeviceConfiguration() */
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return GraphicsEnvironment.getLocalGraphicsEnvironment().
+                getDefaultScreenDevice().getDefaultConfiguration();
+    }
+
+    /**
+     * Applies a new Stroke object.
+     * @param stroke Stroke object to use
+     * @throws IOException In case of an I/O problem
+     */
+    protected void applyStroke(Stroke stroke) throws IOException {
+        if (stroke instanceof BasicStroke) {
+            BasicStroke bs = (BasicStroke)stroke;
+
+            float[] da = bs.getDashArray();
+            if (da != null) {
+                
+                gen.writeText("UL1,");
+                int len = Math.min(20, da.length);
+                float patternLen = 0.0f;
+                for (int idx = 0; idx < len; idx++) {
+                    patternLen += da[idx];
+                }
+                if (len == 1) {
+                    patternLen *= 2;
+                }
+                for (int idx = 0; idx < len; idx++) {
+                    float perc = da[idx] * 100 / patternLen;
+                    gen.writeText(gen.formatDouble2(perc));
+                    if (idx < da.length - 1) {
+                        gen.writeText(",");
+                    }
+                }
+                if (len == 1) {
+                    gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
+                    
+                }
+                gen.writeText(";");
+                /* TODO Dash phase NYI
+                float offset = bs.getDashPhase();
+                gen.writeln(gen.formatDouble4(offset) + " setdash");
+                */
+                Point2D ptLen = new Point2D.Double(patternLen, 0);
+                //interpret as absolute length
+                getTransform().deltaTransform(ptLen, ptLen);
+                double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
+                gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
+            } else {
+                gen.writeText("LT;");
+            }
+
+            gen.writeText("LA1"); //line cap
+            int ec = bs.getEndCap();
+            switch (ec) {
+            case BasicStroke.CAP_BUTT:
+                gen.writeText(",1");
+                break;
+            case BasicStroke.CAP_ROUND:
+                gen.writeText(",4");
+                break;
+            case BasicStroke.CAP_SQUARE:
+                gen.writeText(",2");
+                break;
+            default: System.err.println("Unsupported line cap: " + ec);
+            }
+
+            gen.writeText(",2"); //line join
+            int lj = bs.getLineJoin();
+            switch (lj) {
+            case BasicStroke.JOIN_MITER:
+                gen.writeText(",1");
+                break;
+            case BasicStroke.JOIN_ROUND:
+                gen.writeText(",4");
+                break;
+            case BasicStroke.JOIN_BEVEL:
+                gen.writeText(",5");
+                break;
+            default: System.err.println("Unsupported line join: " + lj);
+            }
+
+            float ml = bs.getMiterLimit();
+            gen.writeText(",3"  + gen.formatDouble4(ml));
+            
+            float lw = bs.getLineWidth();
+            Point2D ptSrc = new Point2D.Double(lw, 0);
+            //Pen widths are set as absolute metric values (WU0;)
+            Point2D ptDest = getTransform().deltaTransform(ptSrc, null);
+            double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
+            //System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
+            gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
+            
+        } else {
+            handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
+        }
+    }
+
+    /**
+     * Applies a new Paint object.
+     * @param paint Paint object to use
+     * @throws IOException In case of an I/O problem
+     */
+    protected void applyPaint(Paint paint) throws IOException {
+        if (paint instanceof Color) {
+            Color col = (Color)paint;
+            int shade = gen.convertToPCLShade(col);
+            gen.writeText("TR0;FT10," + shade + ";");
+        } else {
+            handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
+        }
+    }
+
+    private void writeClip(Shape imclip) throws IOException {
+        if (clippingDisabled) {
+            return;
+        }
+        if (imclip == null) {
+            //gen.writeText("IW;");
+        } else {
+            handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
+            /* This is an attempt to clip using the "InputWindow" (IW) but this only allows to 
+             * clip a rectangular area. Force falling back to bitmap mode for now.
+            Rectangle2D bounds = imclip.getBounds2D();
+            Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
+            Point2D p2 = new Point2D.Double(
+                    bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
+            getTransform().transform(p1, p1);
+            getTransform().transform(p2, p2);
+            gen.writeText("IW" + gen.formatDouble4(p1.getX())
+                    + "," + gen.formatDouble4(p2.getY())
+                    + "," + gen.formatDouble4(p2.getX())
+                    + "," + gen.formatDouble4(p1.getY()) + ";");
+            */
+        }
+    }
+
+    /** @see java.awt.Graphics2D#draw(java.awt.Shape) */
+    public void draw(Shape s) {
+        try {
+            AffineTransform trans = getTransform();
+    
+            Shape imclip = getClip();
+            writeClip(imclip);
+    
+            if (!Color.black.equals(getColor())) {
+                //TODO PCL 5 doesn't support colored pens, PCL5c has a pen color (PC) command
+                handleUnsupportedFeature("Only black is supported as stroke color: " + getColor());
+            }
+            applyStroke(getStroke());
+    
+            PathIterator iter = s.getPathIterator(trans);
+            processPathIteratorStroke(iter);
+            writeClip(null);
+        } catch (IOException ioe) {
+            handleIOException(ioe);
+        }
+    }
+
+    /** @see java.awt.Graphics2D#fill(java.awt.Shape) */
+    public void fill(Shape s) {
+        try {
+            AffineTransform trans = getTransform();
+            Shape imclip = getClip();
+            writeClip(imclip);
+            
+            applyPaint(getPaint());
+
+            PathIterator iter = s.getPathIterator(trans);
+            processPathIteratorFill(iter);
+            writeClip(null);
+        } catch (IOException ioe) {
+            handleIOException(ioe);
+        }
+    }
+
+    /**
+     * Processes a path iterator generating the nexessary painting operations.
+     * @param iter PathIterator to process
+     * @throws IOException In case of an I/O problem.
+     */
+    public void processPathIteratorStroke(PathIterator iter) throws IOException {
+        gen.writeText("\n");
+        double[] vals = new double[6];
+        boolean penDown = false;
+        double x = 0;
+        double y = 0;
+        StringBuffer sb = new StringBuffer(256);
+        penUp(sb);
+        while (!iter.isDone()) {
+            int type = iter.currentSegment(vals);
+            if (type == PathIterator.SEG_CLOSE) {
+                gen.writeText("PM;");
+                gen.writeText(sb.toString());
+                gen.writeText("PM2;EP;");
+                sb.setLength(0);
+                iter.next();
+                continue;
+            } else if (type == PathIterator.SEG_MOVETO) {
+                gen.writeText(sb.toString());
+                sb.setLength(0);
+                if (penDown) {
+                    penUp(sb);
+                    penDown = false;
+                }
+            } else {
+                if (!penDown) {
+                    penDown(sb);
+                    penDown = true;
+                }
+            }
+            switch (type) {
+            case PathIterator.SEG_CLOSE:
+                break;
+            case PathIterator.SEG_MOVETO:
+                x = vals[0];
+                y = vals[1];
+                plotAbsolute(x, y, sb);
+                gen.writeText(sb.toString());
+                sb.setLength(0);
+                break;
+            case PathIterator.SEG_LINETO:
+                x = vals[0];
+                y = vals[1];
+                plotAbsolute(x, y, sb);
+                break;
+            case PathIterator.SEG_CUBICTO:
+                x = vals[4];
+                y = vals[5];
+                bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
+                break;
+            case PathIterator.SEG_QUADTO:
+                double originX = x;
+                double originY = y;
+                x = vals[2];
+                y = vals[3];
+                quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
+                break;
+            default:
+                break;
+            }
+            iter.next();
+        }
+        sb.append("\n");
+        gen.writeText(sb.toString());
+    }
+    
+    /**
+     * Processes a path iterator generating the nexessary painting operations.
+     * @param iter PathIterator to process
+     * @throws IOException In case of an I/O problem.
+     */
+    public void processPathIteratorFill(PathIterator iter) throws IOException {
+        gen.writeText("\n");
+        double[] vals = new double[6];
+        boolean penDown = false;
+        double x = 0;
+        double y = 0;
+        boolean pendingPM0 = true;
+        StringBuffer sb = new StringBuffer(256);
+        penUp(sb);
+        while (!iter.isDone()) {
+            int type = iter.currentSegment(vals);
+            if (type == PathIterator.SEG_CLOSE) {
+                sb.append("PM1;");
+                iter.next();
+                continue;
+            } else if (type == PathIterator.SEG_MOVETO) {
+                if (penDown) {
+                    penUp(sb);
+                    penDown = false;
+                }
+            } else {
+                if (!penDown) {
+                    penDown(sb);
+                    penDown = true;
+                }
+            }
+            switch (type) {
+            case PathIterator.SEG_MOVETO:
+                x = vals[0];
+                y = vals[1];
+                plotAbsolute(x, y, sb);
+                break;
+            case PathIterator.SEG_LINETO:
+                x = vals[0];
+                y = vals[1];
+                plotAbsolute(x, y, sb);
+                break;
+            case PathIterator.SEG_CUBICTO:
+                x = vals[4];
+                y = vals[5];
+                bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
+                break;
+            case PathIterator.SEG_QUADTO:
+                double originX = x;
+                double originY = y;
+                x = vals[2];
+                y = vals[3];
+                quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
+                break;
+            default:
+                throw new IllegalStateException("Must not get here");
+            }
+            if (pendingPM0) {
+                pendingPM0 = false;
+                sb.append("PM;");
+            }
+            iter.next();
+        }
+        sb.append("PM2;");
+        fillPolygon(iter.getWindingRule(), sb);
+        sb.append("\n");
+        gen.writeText(sb.toString());
+    }
+    
+    private void fillPolygon(int windingRule, StringBuffer sb) {
+        int fillMethod = (windingRule == PathIterator.WIND_EVEN_ODD ? 0 : 1);
+        sb.append("FP").append(fillMethod).append(";");
+    }
+
+    private void plotAbsolute(double x, double y, StringBuffer sb) {
+        sb.append("PA").append(gen.formatDouble4(x));
+        sb.append(",").append(gen.formatDouble4(y)).append(";");
+    }
+
+    private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3,
+            StringBuffer sb) {
+        sb.append("BZ").append(gen.formatDouble4(x1));
+        sb.append(",").append(gen.formatDouble4(y1));
+        sb.append(",").append(gen.formatDouble4(x2));
+        sb.append(",").append(gen.formatDouble4(y2));
+        sb.append(",").append(gen.formatDouble4(x3));
+        sb.append(",").append(gen.formatDouble4(y3)).append(";");
+    }
+
+    private void quadraticBezierAbsolute(double originX, double originY, 
+            double x1, double y1, double x2, double y2, StringBuffer sb) {
+        //Quadratic Bezier curve can be mapped to a normal bezier curve
+        //See http://pfaedit.sourceforge.net/bezier.html
+        double nx1 = originX + (2.0 / 3.0) * (x1 - originX);
+        double ny1 = originY + (2.0 / 3.0) * (y1 - originY);
+        
+        double nx2 = nx1 + (1.0 / 3.0) * (x2 - originX);
+        double ny2 = ny1 + (1.0 / 3.0) * (y2 - originY);
+        
+        bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2, sb);
+    }
+
+    private void penDown(StringBuffer sb) {
+        sb.append("PD;");
+    }
+
+    private void penUp(StringBuffer sb) {
+        sb.append("PU;");
+    }
+
+    /** @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */
+    public void drawString(String s, float x, float y) {
+        java.awt.Font awtFont = getFont();
+        FontRenderContext frc = getFontRenderContext();
+        GlyphVector gv = awtFont.createGlyphVector(frc, s);
+        Shape glyphOutline = gv.getOutline(x, y);
+        fill(glyphOutline);
+    }
+
+    /** @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */
+    public void drawString(AttributedCharacterIterator iterator, float x,
+            float y) {
+        // TODO Auto-generated method stub
+        handleUnsupportedFeature("drawString NYI");
+    }
+
+    /**
+     * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage, 
+     *          java.awt.geom.AffineTransform)
+     */
+    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+        handleUnsupportedFeature("Bitmap images are not supported");
+    }
+
+    /**
+     * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage, 
+     *          java.awt.geom.AffineTransform)
+     */
+    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+        handleUnsupportedFeature("Bitmap images are not supported");
+    }
+
+    /**
+     * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, 
+     *          java.awt.image.ImageObserver)
+     */
+    public boolean drawImage(Image img, int x, int y, int width, int height,
+            ImageObserver observer) {
+        handleUnsupportedFeature("Bitmap images are not supported");
+        return false;
+    }
+
+    /**
+     * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver)
+     */
+    public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
+        handleUnsupportedFeature("Bitmap images are not supported");
+        return false;
+        /*
+         * First attempt disabled.
+         * Reasons: Lack of transparency control, positioning and rotation issues
+        final int width = img.getWidth(observer);
+        final int height = img.getHeight(observer);
+        if (width == -1 || height == -1) {
+            return false;
+        }
+
+        Dimension size = new Dimension(width, height);
+        BufferedImage buf = buildBufferedImage(size);
+
+        java.awt.Graphics2D g = buf.createGraphics();
+        try {
+            g.setComposite(AlphaComposite.SrcOver);
+            g.setBackground(new Color(255, 255, 255));
+            g.setPaint(new Color(255, 255, 255));
+            g.fillRect(0, 0, width, height);
+            g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
+
+            if (!g.drawImage(img, 0, 0, observer)) {
+                return false;
+            }
+        } finally {
+            g.dispose();
+        }
+
+        try {
+            AffineTransform at = getTransform();
+            gen.enterPCLMode(false);
+            //Shape imclip = getClip(); Clipping is not available in PCL
+            Point2D p1 = new Point2D.Double(x, y);
+            at.transform(p1, p1);
+            pclContext.getTransform().transform(p1, p1);
+            gen.setCursorPos(p1.getX(), p1.getY());
+            gen.paintBitmap(buf, 72); 
+            gen.enterHPGL2Mode(false);
+        } catch (IOException ioe) {
+            handleIOException(ioe);
+        }
+
+        return true;*/
+    }
+
+    /** @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */
+    public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+        // TODO Auto-generated method stub
+        handleUnsupportedFeature("copyArea NYI");
+    }
+
+    /** @see java.awt.Graphics#setXORMode(java.awt.Color) */
+    public void setXORMode(Color c1) {
+        // TODO Auto-generated method stub
+        handleUnsupportedFeature("setXORMode NYI");
+    }
+
+    /**
+     * Used to create proper font metrics
+     */
+    private Graphics2D fmg;
+
+    {
+        BufferedImage bi = new BufferedImage(1, 1,
+                                             BufferedImage.TYPE_INT_ARGB);
+
+        fmg = bi.createGraphics();
+    }
+
+    /**
+     * Creates a buffered image.
+     * @param size dimensions of the image to be created
+     * @return the buffered image
+     */
+    protected BufferedImage buildBufferedImage(Dimension size) {
+        return new BufferedImage(size.width, size.height,
+                                 BufferedImage.TYPE_BYTE_GRAY);
+    }
+    
+    /** @see java.awt.Graphics#getFontMetrics(java.awt.Font) */
+    public java.awt.FontMetrics getFontMetrics(java.awt.Font f) {
+        return fmg.getFontMetrics(f);
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java b/src/java/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java
new file mode 100644 (file)
index 0000000..d2e91f8
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+package org.apache.fop.render.pcl;
+
+import java.awt.Dimension;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.render.AbstractGraphics2DAdapter;
+import org.apache.fop.render.Graphics2DImagePainter;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.util.UnitConv;
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+/**
+ * Graphics2DAdapter implementation for PCL and HP GL/2.
+ */
+public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter {
+
+    /** logging instance */
+    private static Log log = LogFactory.getLog(PCLGraphics2DAdapter.class);
+
+    /**
+     * Main constructor
+     */
+    public PCLGraphics2DAdapter() {
+    }
+    
+    /** @see org.apache.fop.render.Graphics2DAdapter */
+    public void paintImage(Graphics2DImagePainter painter, 
+            RendererContext context,
+            int x, int y, int width, int height) throws IOException {
+        PCLRendererContext pclContext = PCLRendererContext.wrapRendererContext(context);
+        PCLRenderer pcl = (PCLRenderer)context.getRenderer();
+        PCLGenerator gen = pcl.gen;
+        
+        // get the 'width' and 'height' attributes of the image/document
+        Dimension dim = painter.getImageSize();
+        float imw = (float)dim.getWidth();
+        float imh = (float)dim.getHeight();
+
+        boolean painted = false;
+        boolean paintAsBitmap = pclContext.paintAsBitmap();
+        if (!paintAsBitmap) {
+            ByteArrayOutputStream baout = new ByteArrayOutputStream();
+            PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution());
+            try {
+                GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone();
+
+                AffineTransform prepareHPGL2 = new AffineTransform();
+                prepareHPGL2.scale(0.001, 0.001);
+                ctx.setTransform(prepareHPGL2);
+
+                PCLGraphics2D graphics = new PCLGraphics2D(tempGen);
+                graphics.setGraphicContext(ctx);
+                graphics.setClippingDisabled(pclContext.isClippingDisabled());
+                Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
+                painter.paint(graphics, area);
+                
+                //If we arrive here, the graphic is natively paintable, so write the graphic
+                pcl.saveGraphicsState();
+                pcl.setCursorPos(x, y);
+                gen.writeCommand("*c" + gen.formatDouble4(width / 100f) + "x" 
+                        + gen.formatDouble4(height / 100f) + "Y");
+                gen.writeCommand("*c0T");
+                gen.enterHPGL2Mode(false);
+                gen.writeText("\nIN;");
+                gen.writeText("SP1;");
+                //One Plotter unit is 0.025mm!
+                double scale = imw / UnitConv.mm2pt(imw * 0.025);
+                gen.writeText("SC0," + gen.formatDouble4(scale) 
+                        + ",0,-" + gen.formatDouble4(scale) + ",2;");
+                gen.writeText("IR0,100,0,100;");
+                gen.writeText("PU;PA0,0;\n");
+                baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream
+                gen.writeText("\n");
+
+                gen.enterPCLMode(false);
+                pcl.restoreGraphicsState();
+                painted = true;
+            } catch (UnsupportedOperationException uoe) {
+                log.debug(
+                    "Cannot paint graphic natively. Falling back to bitmap painting. Reason: " 
+                        + uoe.getMessage());
+            }
+        }
+        
+        if (!painted) {
+            //Fallback solution: Paint to a BufferedImage
+            int resolution = (int)Math.round(context.getUserAgent().getTargetResolution());
+            BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true, false);
+
+            pcl.setCursorPos(x, y);
+            gen.paintBitmap(bi, new Dimension(width, height), pclContext.isSourceTransparency());
+        }
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLPageDefinition.java b/src/java/org/apache/fop/render/pcl/PCLPageDefinition.java
new file mode 100644 (file)
index 0000000..43978e9
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.fop.util.UnitConv;
+
+/**
+ * This class represents a page format with PCL-specific properties.
+ */
+public class PCLPageDefinition {
+
+    private static List pageDefinitions;
+    private static PCLPageDefinition defaultPageDefinition;
+    
+    private String name;
+    private int selector;
+    private Dimension physicalPageSize;
+    private Rectangle logicalPageRect;
+    private boolean landscape;
+    
+    static {
+        createPageDefinitions();
+    }
+    
+    /**
+     * Main constructor
+     * @param name the name of the page definition
+     * @param selector the selector used by the <ESC>&l#A command (page size)
+     * @param physicalPageSize the physical page size
+     * @param logicalPageRect the rectangle defining the logical page
+     * @param landscape true if it is a landscape format
+     */
+    public PCLPageDefinition(String name, int selector, Dimension physicalPageSize, 
+            Rectangle logicalPageRect, boolean landscape) {
+        this.name = name;
+        this.selector = selector;
+        this.physicalPageSize = physicalPageSize;
+        this.logicalPageRect = logicalPageRect;
+        this.landscape = landscape;
+    }
+    
+    /** @return the name of the page definition */
+    public String getName() {
+        return this.name;
+    }
+    
+    /** @return the selector used by the <ESC>&l#A command (page size) */
+    public int getSelector() {
+        return this.selector;
+    }
+    
+    /** @return true if it is a landscape format */
+    public boolean isLandscapeFormat() {
+        return this.landscape;
+    }
+
+    /** @return the physical page size */
+    public Dimension getPhysicalPageSize() {
+        return this.physicalPageSize;
+    }
+    
+    /** @return the rectangle defining the logical page */
+    public Rectangle getLogicalPageRect() {
+        return this.logicalPageRect;
+    }
+    
+    private boolean matches(long width, long height, int errorMargin) {
+        return (Math.abs(this.physicalPageSize.width - width) < errorMargin) 
+            && (Math.abs(this.physicalPageSize.height - height) < errorMargin);
+    }
+    
+    /** @see java.lang.Object#toString() */
+    public String toString() {
+        return getName();
+    }
+
+    /**
+     * Tries to determine a matching page definition.
+     * @param width the physical page width (in mpt)
+     * @param height the physical page height (in mpt)
+     * @param errorMargin the error margin for detecting the right page definition
+     * @return the page definition or null if no match was found
+     */
+    public static PCLPageDefinition getPageDefinition(long width, long height, int errorMargin) {
+        Iterator iter = pageDefinitions.iterator();
+        while (iter.hasNext()) {
+            PCLPageDefinition def = (PCLPageDefinition)iter.next();
+            if (def.matches(width, height, errorMargin)) {
+                return def;
+            }
+        }
+        return null;
+    }
+    
+    /** @return the default page definition (letter) */
+    public static PCLPageDefinition getDefaultPageDefinition() {
+        return defaultPageDefinition;
+    }
+    
+    /**
+     * Converts an offset values for logical pages to millipoints. The values are given as pixels
+     * in a 300dpi environment.
+     * @param offset the offset as given in the PCL 5 specification (under "Printable Area")
+     * @return the converted value in millipoints
+     */
+    private static int convert300dpiDotsToMpt(int offset) {
+        return (int)Math.round(((double)offset) * 72000 / 300);
+    }
+    
+    private static Dimension createPhysicalPageSizeInch(float width, float height) {
+        return new Dimension(
+                (int)Math.round(UnitConv.in2mpt(width)), 
+                (int)Math.round(UnitConv.in2mpt(height)));
+    }
+    
+    private static Dimension createPhysicalPageSizeMm(float width, float height) {
+        return new Dimension(
+                (int)Math.round(UnitConv.mm2mpt(width)), 
+                (int)Math.round(UnitConv.mm2mpt(height)));
+    }
+    
+    private static Rectangle createLogicalPageRect(int x, int y, int width, int height) {
+        return new Rectangle(convert300dpiDotsToMpt(x), convert300dpiDotsToMpt(y), 
+                convert300dpiDotsToMpt(width), convert300dpiDotsToMpt(height));
+    }
+    
+    private static void createPageDefinitions() {
+        pageDefinitions = new java.util.ArrayList();
+        pageDefinitions.add(new PCLPageDefinition("Letter", 2,
+                createPhysicalPageSizeInch(8.5f, 11),
+                createLogicalPageRect(75, 0, 2400, 3300), false));
+        defaultPageDefinition = new PCLPageDefinition("Legal", 3, 
+                createPhysicalPageSizeInch(8.5f, 14),
+                createLogicalPageRect(75, 0, 2400, 4200), false);
+        pageDefinitions.add(defaultPageDefinition);
+        pageDefinitions.add(new PCLPageDefinition("Executive", 1, 
+                createPhysicalPageSizeInch(7.25f, 10.5f),
+                createLogicalPageRect(75, 0, 2025, 3150), false));
+        pageDefinitions.add(new PCLPageDefinition("Ledger", 6,
+                createPhysicalPageSizeInch(11, 17),
+                createLogicalPageRect(75, 0, 3150, 5100), false));
+        pageDefinitions.add(new PCLPageDefinition("A4", 26,
+                createPhysicalPageSizeMm(210, 297),
+                createLogicalPageRect(71, 0, 2338, 3507), false));
+        pageDefinitions.add(new PCLPageDefinition("A3", 27, 
+                createPhysicalPageSizeMm(297, 420),
+                createLogicalPageRect(71, 0, 3365, 4960), false));
+
+        //TODO Add envelope definitions
+        
+        pageDefinitions.add(new PCLPageDefinition("LetterL", 2,
+                createPhysicalPageSizeInch(11, 8.5f),
+                createLogicalPageRect(60, 0, 3180, 2550), true));
+        pageDefinitions.add(new PCLPageDefinition("LegalL", 3,
+                createPhysicalPageSizeInch(14, 8.5f),
+                createLogicalPageRect(60, 0, 4080, 2550), true));
+        pageDefinitions.add(new PCLPageDefinition("ExecutiveL", 1, 
+                createPhysicalPageSizeInch(10.5f, 7.25f),
+                createLogicalPageRect(60, 0, 3030, 2175), true));
+        pageDefinitions.add(new PCLPageDefinition("LedgerL", 6,
+                createPhysicalPageSizeInch(17, 11),
+                createLogicalPageRect(60, 0, 4980, 3300), true));
+        pageDefinitions.add(new PCLPageDefinition("A4L", 26,
+                createPhysicalPageSizeMm(297, 210),
+                createLogicalPageRect(59, 0, 3389, 2480), true));
+        pageDefinitions.add(new PCLPageDefinition("A3L", 27,
+                createPhysicalPageSizeMm(420, 297),
+                createLogicalPageRect(59, 0, 4842, 3507), true));
+    }
+    
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderer.java b/src/java/org/apache/fop/render/pcl/PCLRenderer.java
new file mode 100644 (file)
index 0000000..05952d9
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ * Copyright 1999-2006 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+package org.apache.fop.render.pcl;
+
+//Java
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.w3c.dom.Document;
+
+import org.apache.xmlgraphics.java2d.GraphicContext;
+
+// FOP
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.MimeConstants;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.Block;
+import org.apache.fop.area.BlockViewport;
+import org.apache.fop.area.CTM;
+import org.apache.fop.area.PageViewport;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.AbstractTextArea;
+import org.apache.fop.area.inline.ForeignObject;
+import org.apache.fop.area.inline.Image;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.SpaceArea;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.area.inline.Viewport;
+import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.image.EPSImage;
+import org.apache.fop.image.FopImage;
+import org.apache.fop.image.ImageFactory;
+import org.apache.fop.image.XMLImage;
+import org.apache.fop.render.Graphics2DAdapter;
+import org.apache.fop.render.Graphics2DImagePainter;
+import org.apache.fop.render.PrintRenderer;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.render.RendererContextConstants;
+import org.apache.fop.render.java2d.FontMetricsMapper;
+import org.apache.fop.render.java2d.FontSetup;
+import org.apache.fop.render.java2d.Java2DRenderer;
+import org.apache.fop.render.pcl.extensions.PCLElementMapping;
+import org.apache.fop.traits.BorderProps;
+import org.apache.fop.util.QName;
+import org.apache.fop.util.UnitConv;
+
+/**
+ * Renderer for the PCL 5 printer language. It also uses HP GL/2 for certain graphic elements.
+ */
+public class PCLRenderer extends PrintRenderer {
+
+    /** logging instance */
+    private static Log log = LogFactory.getLog(PCLRenderer.class);
+
+    /** The MIME type for PCL */
+    public static final String MIME_TYPE = MimeConstants.MIME_PCL_ALT;
+
+    private static final QName CONV_MODE 
+            = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
+    private static final QName SRC_TRANSPARENCY 
+            = new QName(ExtensionElementMapping.URI, null, "source-transparency");
+    
+    /** The OutputStream to write the PCL stream to */
+    protected OutputStream out;
+    
+    /** The PCL generator */
+    protected PCLGenerator gen;
+    private boolean ioTrouble = false;
+
+    private Stack graphicContextStack = new Stack();
+    private GraphicContext graphicContext = new GraphicContext();
+
+    private PCLPageDefinition currentPageDefinition;
+    private int currentPrintDirection = 0;
+    private GeneralPath currentPath = null;
+    private java.awt.Color currentFillColor = null;
+    
+    /**
+     * Controls whether appearance is more important than speed. False can cause some FO feature
+     * to be ignored (like the advanced borders). 
+     */
+    private boolean qualityBeforeSpeed = false;
+    
+    /**
+     * Controls whether all text should be painted as text. This is a fallback setting in case
+     * the mixture of native and bitmapped text does not provide the necessary quality.
+     */
+    private boolean allTextAsBitmaps = false;
+    
+    /**
+     * Create the PCL renderer
+     */
+    public PCLRenderer() {
+    }
+
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(Configuration cfg) throws ConfigurationException {
+        super.configure(cfg);
+        String rendering = cfg.getChild("rendering").getValue(null);
+        if ("quality".equalsIgnoreCase(rendering)) {
+            this.qualityBeforeSpeed = true;
+        } else if ("speed".equalsIgnoreCase(rendering)) {
+            this.qualityBeforeSpeed = false;
+        } else if (rendering != null) {
+            throw new ConfigurationException(
+                    "Valid values for 'rendering' are 'quality' and 'speed'. Value found: " 
+                        + rendering);
+        }
+        String textRendering = cfg.getChild("text-rendering").getValue(null);
+        if ("bitmap".equalsIgnoreCase(textRendering)) {
+            this.allTextAsBitmaps = true;
+        } else if ("auto".equalsIgnoreCase(textRendering)) {
+            this.allTextAsBitmaps = false;
+        } else if (textRendering != null) {
+            throw new ConfigurationException(
+                    "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " 
+                        + textRendering);
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.Renderer#setupFontInfo(org.apache.fop.fonts.FontInfo)
+     */
+    public void setupFontInfo(FontInfo inFontInfo) {
+        //Don't call super.setupFontInfo() here!
+        //The PCLRenderer uses the Java2D FontSetup which needs a special font setup
+        //create a temp Image to test font metrics on
+        fontInfo = inFontInfo;
+        BufferedImage fontImage = new BufferedImage(100, 100,
+                BufferedImage.TYPE_INT_RGB);
+        Graphics2D g = fontImage.createGraphics();
+        //The next line is important to get accurate font metrics!
+        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 
+                RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+        FontSetup.setup(fontInfo, g);
+    }
+
+    /**
+     * Central exception handler for I/O exceptions.
+     * @param ioe IOException to handle
+     */
+    protected void handleIOTrouble(IOException ioe) {
+        if (!ioTrouble) {
+            log.error("Error while writing to target file", ioe);
+            ioTrouble = true;
+        }
+    }
+
+    /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
+    public Graphics2DAdapter getGraphics2DAdapter() {
+        return new PCLGraphics2DAdapter();
+    }
+
+    /** @return the GraphicContext used to track coordinate system transformations */
+    public GraphicContext getGraphicContext() {
+        return this.graphicContext;
+    }
+    
+    /** @return the target resolution */
+    protected int getResolution() {
+        int resolution = (int)Math.round(userAgent.getTargetResolution());
+        if (resolution <= 300) {
+            return 300;
+        } else {
+            return 600;
+        }
+    }
+    
+    /**
+     * Sets the current font (NOTE: Hard-coded font mappings ATM!)
+     * @param name the font name (internal F* names for now)
+     * @param size the font size
+     * @param text the text to be rendered (used to determine if there are non-printable chars)
+     * @return true if the font can be mapped to PCL
+     * @throws IOException if an I/O problem occurs
+     */
+    public boolean setFont(String name, float size, String text) throws IOException {
+        byte[] encoded = text.getBytes("ISO-8859-1");
+        for (int i = 0, c = encoded.length; i < c; i++) {
+            if (encoded[i] == 0x3F && text.charAt(i) != '?') {
+                return false;
+            }
+        }
+        int fontcode = 0;
+        if (name.length() > 1 && name.charAt(0) == 'F') {
+            try {
+                fontcode = Integer.parseInt(name.substring(1));
+            } catch (Exception e) {
+                log.error(e);
+            }
+        }
+        //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
+        String formattedSize = gen.formatDouble2(size / 1000);
+        switch (fontcode) {
+        case 1:     // F1 = Helvetica
+            // gen.writeCommand("(8U");
+            // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
+            // Arial is more common among PCL5 printers than Helvetica - so use Arial
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
+            break;
+        case 2:     // F2 = Helvetica Oblique
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
+            break;
+        case 3:     // F3 = Helvetica Bold
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
+            break;
+        case 4:     // F4 = Helvetica Bold Oblique
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
+            break;
+        case 5:     // F5 = Times Roman
+            // gen.writeCommand("(8U");
+            // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
+            // Times New is more common among PCL5 printers than Times - so use Times New
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
+            break;
+        case 6:     // F6 = Times Italic
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
+            break;
+        case 7:     // F7 = Times Bold
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
+            break;
+        case 8:     // F8 = Times Bold Italic
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
+            break;
+        case 9:     // F9 = Courier
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
+                    + "h0s0b4099T");
+            break;
+        case 10:    // F10 = Courier Oblique
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
+                    + "h1s0b4099T");
+            break;
+        case 11:    // F11 = Courier Bold
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
+                    + "h0s3b4099T");
+            break;
+        case 12:    // F12 = Courier Bold Oblique
+
+            gen.writeCommand("(0N");
+            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
+                    + "h1s3b4099T");
+            break;
+        case 13:    // F13 = Symbol
+
+            return false;
+            //gen.writeCommand("(19M");
+            //gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
+            // ECMA Latin 1 Symbol Set in Times Roman???
+            // gen.writeCommand("(9U");
+            // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
+            //break;
+        case 14:    // F14 = Zapf Dingbats
+
+            return false;
+            //gen.writeCommand("(14L");
+            //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
+            //break;
+        default:
+            //gen.writeCommand("(0N");
+            //gen.writeCommand("(s" + formattedSize + "V");
+            return false;
+        }
+        return true;
+    }
+
+    /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
+    public void startRenderer(OutputStream outputStream) throws IOException {
+        log.debug("Rendering areas to PCL...");
+        this.out = outputStream;
+        this.gen = new PCLGenerator(out, getResolution());
+
+        gen.universalEndOfLanguage();
+        gen.writeText("@PJL COMMENT Produced by " + userAgent.getProducer() + "\n");
+        if (userAgent.getTitle() != null) {
+            gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n");
+        }
+        gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n");
+        gen.writeText("@PJL ENTER LANGUAGE = PCL\n");
+        gen.resetPrinter();
+        gen.setUnitOfMeasure(getResolution());
+        gen.setRasterGraphicsResolution(getResolution());
+    }
+
+    /** @see org.apache.fop.render.Renderer#stopRenderer() */
+    public void stopRenderer() throws IOException {
+        gen.separateJobs();
+        gen.resetPrinter();
+        gen.universalEndOfLanguage();
+    }
+
+    /** @see org.apache.fop.render.AbstractRenderer */
+    public String getMimeType() {
+        return MIME_TYPE;
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderPage(org.apache.fop.area.PageViewport)
+     */
+    public void renderPage(PageViewport page) throws IOException, FOPException {
+        saveGraphicsState();
+        
+        //Paper source
+        String paperSource = page.getForeignAttributeValue(
+                new QName(PCLElementMapping.NAMESPACE, null, "paper-source"));
+        if (paperSource != null) {
+            gen.selectPaperSource(Integer.parseInt(paperSource));
+        }
+        
+        //Page size
+        final long pagewidth = Math.round(page.getViewArea().getWidth());
+        final long pageheight = Math.round(page.getViewArea().getHeight());
+        selectPageFormat(pagewidth, pageheight);
+        
+        super.renderPage(page);
+        
+        //Eject page
+        gen.formFeed();
+        restoreGraphicsState();
+    }
+
+    private void selectPageFormat(long pagewidth, long pageheight) throws IOException {
+        this.currentPageDefinition = PCLPageDefinition.getPageDefinition(
+                pagewidth, pageheight, 1000);
+        
+        if (this.currentPageDefinition == null) {
+            this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition();
+            log.warn("Paper type could not be determined. Falling back to: " 
+                    + this.currentPageDefinition.getName());
+        }
+        log.debug("page size: " + currentPageDefinition.getPhysicalPageSize());
+        log.debug("logical page: " + currentPageDefinition.getLogicalPageRect());
+        if (this.currentPageDefinition.isLandscapeFormat()) {
+            gen.writeCommand("&l1O"); //Orientation
+        } else {
+            gen.writeCommand("&l0O"); //Orientation
+        }
+        gen.selectPageSize(this.currentPageDefinition.getSelector());
+        
+        gen.clearHorizontalMargins();
+        gen.setTopMargin(0);
+    }
+
+    /** Saves the current graphics state on the stack. */
+    protected void saveGraphicsState() {
+        graphicContextStack.push(graphicContext);
+        graphicContext = (GraphicContext)graphicContext.clone();
+    }
+
+    /** Restores the last graphics state from the stack. */
+    protected void restoreGraphicsState() {
+        graphicContext = (GraphicContext)graphicContextStack.pop();
+    }
+    
+    /**
+     * Clip an area. write a clipping operation given coordinates in the current
+     * transform. Coordinates are in points.
+     *
+     * @param x the x coordinate
+     * @param y the y coordinate
+     * @param width the width of the area
+     * @param height the height of the area
+     */
+    protected void clipRect(float x, float y, float width, float height) {
+        //PCL cannot clip (only HP GL/2 can)
+    }
+
+    private Point2D transformedPoint(float x, float y) {
+        return transformedPoint(Math.round(x), Math.round(y));
+    }
+    
+    private Point2D transformedPoint(int x, int y) {
+        AffineTransform at = graphicContext.getTransform();
+        if (log.isTraceEnabled()) {
+            log.trace("Current transform: " + at);
+        }
+        Point2D.Float orgPoint = new Point2D.Float(x, y);
+        Point2D.Float transPoint = new Point2D.Float();
+        at.transform(orgPoint, transPoint);
+        //At this point we have the absolute position in FOP's coordinate system
+        
+        //Now get PCL coordinates taking the current print direction and the logical page
+        //into account.
+        Dimension pageSize = currentPageDefinition.getPhysicalPageSize();
+        Rectangle logRect = currentPageDefinition.getLogicalPageRect();
+        switch (currentPrintDirection) {
+        case 0:
+            transPoint.x -= logRect.x;
+            transPoint.y -= logRect.y;
+            break;
+        case 90:
+            float ty = transPoint.x;
+            transPoint.x = pageSize.height - transPoint.y;
+            transPoint.y = ty;
+            transPoint.x -= logRect.y;
+            transPoint.y -= logRect.x;
+            break;
+        case 180:
+            transPoint.x = pageSize.width - transPoint.x;
+            transPoint.y = pageSize.height - transPoint.y;
+            transPoint.x -= pageSize.width - logRect.x - logRect.width;
+            transPoint.y -= pageSize.height - logRect.y - logRect.height;
+            //The next line is odd and is probably necessary due to the default value of the
+            //Text Length command: "1/2 inch less than maximum text length"
+            //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
+            transPoint.y -= UnitConv.in2mpt(0.5);
+            break;
+        case 270:
+            float tx = transPoint.y;
+            transPoint.y = pageSize.width - transPoint.x;
+            transPoint.x = tx;
+            transPoint.x -= pageSize.height - logRect.y - logRect.height;
+            transPoint.y -= pageSize.width - logRect.x - logRect.width;
+            break;
+        default:
+            throw new IllegalStateException("Illegal print direction: " + currentPrintDirection);
+        }
+        return transPoint;
+    }
+    
+    private void changePrintDirection() {
+        AffineTransform at = graphicContext.getTransform();
+        int newDir;
+        try {
+            if (at.getScaleX() == 0 && at.getScaleY() == 0 
+                    && at.getShearX() == 1 && at.getShearY() == -1) {
+                newDir = 90;
+            } else if (at.getScaleX() == -1 && at.getScaleY() == -1 
+                    && at.getShearX() == 0 && at.getShearY() == 0) {
+                newDir = 180;
+            } else if (at.getScaleX() == 0 && at.getScaleY() == 0 
+                    && at.getShearX() == -1 && at.getShearY() == 1) {
+                newDir = 270;
+            } else {
+                newDir = 0;
+            }
+            if (newDir != this.currentPrintDirection) {
+                this.currentPrintDirection = newDir;
+                gen.changePrintDirection(this.currentPrintDirection);
+            }
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
+     */
+    protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
+        saveGraphicsState();
+        AffineTransform at = new AffineTransform(ctm.toArray());
+        graphicContext.transform(at);
+        changePrintDirection();
+        if (log.isDebugEnabled()) {
+            log.debug("startVPArea: " + at + " --> " + graphicContext.getTransform());
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#endVParea()
+     */
+    protected void endVParea() {
+        restoreGraphicsState();
+        changePrintDirection();
+        if (log.isDebugEnabled()) {
+            log.debug("endVPArea() --> " + graphicContext.getTransform());
+        }
+    }
+
+    /**
+     * Handle block traits.
+     * The block could be any sort of block with any positioning
+     * so this should render the traits such as border and background
+     * in its position.
+     *
+     * @param block the block to render the traits
+     */
+    protected void handleBlockTraits(Block block) {
+        int borderPaddingStart = block.getBorderAndPaddingWidthStart();
+        int borderPaddingBefore = block.getBorderAndPaddingWidthBefore();
+        
+        float startx = currentIPPosition / 1000f;
+        float starty = currentBPPosition / 1000f;
+        float width = block.getIPD() / 1000f;
+        float height = block.getBPD() / 1000f;
+
+        startx += block.getStartIndent() / 1000f;
+        startx -= block.getBorderAndPaddingWidthStart() / 1000f;
+
+        width += borderPaddingStart / 1000f;
+        width += block.getBorderAndPaddingWidthEnd() / 1000f;
+        height += borderPaddingBefore / 1000f;
+        height += block.getBorderAndPaddingWidthAfter() / 1000f;
+
+        drawBackAndBorders(block, startx, starty, width, height);
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
+     */
+    protected void renderText(final TextArea text) {
+        renderInlineAreaBackAndBorders(text);
+        
+        String fontname = getInternalFontNameForArea(text);
+        int fontsize = text.getTraitAsInteger(Trait.FONT_SIZE);
+
+        //Determine position
+        int saveIP = currentIPPosition;
+        int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
+        int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
+
+        try {
+            final Color col = (Color)text.getTrait(Trait.COLOR);
+            boolean pclFont = allTextAsBitmaps 
+                    ? false
+                    : setFont(fontname, fontsize, text.getText()); 
+            if (pclFont) {
+                //this.currentFill = col;
+                if (col != null) {
+                    //useColor(ct);
+                    gen.setTransparencyMode(true, false);
+                    gen.selectCurrentPattern(gen.convertToPCLShade(col), 2);
+                }
+                
+                saveGraphicsState();
+                graphicContext.translate(rx, bl);
+                setCursorPos(0, 0);
+                gen.setTransparencyMode(true, true);
+                
+                super.renderText(text); //Updates IPD and renders words and spaces
+                restoreGraphicsState();
+            } else {
+                //Use Java2D to paint different fonts via bitmap
+                final Font font = getFontFromArea(text);
+                final int baseline = text.getBaselineOffset();
+                
+                //for cursive fonts, so the text isn't clipped
+                int extraWidth = font.getFontSize() / 3;
+                final FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
+                        font.getFontName());
+                int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
+                final int additionalBPD = maxAscent - baseline;
+                
+                Graphics2DAdapter g2a = getGraphics2DAdapter();
+                final Rectangle paintRect = new Rectangle(
+                        rx, currentBPPosition + text.getOffset() - additionalBPD,
+                        text.getIPD() + extraWidth, text.getBPD() + additionalBPD);
+                RendererContext rc = createRendererContext(paintRect.x, paintRect.y, 
+                        paintRect.width, paintRect.height, null);
+                Map atts = new java.util.HashMap();
+                atts.put(CONV_MODE, "bitmap");
+                atts.put(SRC_TRANSPARENCY, "true");
+                rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
+                
+                Graphics2DImagePainter painter = new Graphics2DImagePainter() {
+
+                    public void paint(Graphics2D g2d, Rectangle2D area) {
+                        g2d.setFont(mapper.getFont(font.getFontSize()));
+                        g2d.translate(0, baseline + additionalBPD);
+                        g2d.scale(1000, 1000);
+                        g2d.setColor(col);
+                        Java2DRenderer.renderText(text, g2d, font);
+                    }
+                    
+                    public Dimension getImageSize() {
+                        return paintRect.getSize();
+                    }
+                    
+                };
+                g2a.paintImage(painter, rc, 
+                        paintRect.x, paintRect.y, paintRect.width, paintRect.height);
+                currentIPPosition = saveIP + text.getAllocIPD();
+            }
+        
+            //renderTextDecoration(tf, fontsize, area, bl, rx);
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+    }
+
+    /**
+     * Sets the current cursor position. The coordinates are transformed to the absolute position
+     * on the logical PCL page and then passed on to the PCLGenerator.
+     * @param x the x coordinate (in millipoints)
+     * @param y the y coordinate (in millipoints)
+     */
+    void setCursorPos(float x, float y) {
+        try {
+            Point2D transPoint = transformedPoint(x, y);
+            gen.setCursorPos(transPoint.getX(), transPoint.getY());
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractPathOrientedRenderer#clip()
+     */
+    protected void clip() {
+        if (currentPath == null) {
+            throw new IllegalStateException("No current path available!");
+        }
+        //TODO Find a good way to do clipping. PCL itself cannot clip.
+        currentPath = null;
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractPathOrientedRenderer#closePath()
+     */
+    protected void closePath() {
+        currentPath.closePath();
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float)
+     */
+    protected void lineTo(float x, float y) {
+        if (currentPath == null) {
+            currentPath = new GeneralPath();
+        }
+        currentPath.lineTo(x, y);
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractPathOrientedRenderer#moveTo(float, float)
+     */
+    protected void moveTo(float x, float y) {
+        if (currentPath == null) {
+            currentPath = new GeneralPath();
+        }
+        currentPath.moveTo(x, y);
+    }
+    
+    /**
+     * Fill a rectangular area.
+     * @param x the x coordinate (in pt)
+     * @param y the y coordinate (in pt)
+     * @param width the width of the rectangle
+     * @param height the height of the rectangle
+     */
+    protected void fillRect(float x, float y, float width, float height) {
+        try {
+            setCursorPos(x * 1000, y * 1000);
+            gen.fillRect((int)(width * 1000), (int)(height * 1000), 
+                    this.currentFillColor);
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+    }
+    
+    /**
+     * Sets the new current fill color.
+     * @param color the color
+     */
+    protected void updateFillColor(java.awt.Color color) {
+        this.currentFillColor = color;
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderWord(org.apache.fop.area.inline.WordArea)
+     */
+    protected void renderWord(WordArea word) {
+        //Font font = getFontFromArea(word.getParentArea());
+
+        String s = word.getWord();
+
+        try {
+            gen.writeText(s);
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+
+        super.renderWord(word);
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderSpace(org.apache.fop.area.inline.SpaceArea)
+     */
+    protected void renderSpace(SpaceArea space) {
+        AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
+        String s = space.getSpace();
+        char sp = s.charAt(0);
+        Font font = getFontFromArea(textArea);
+        
+        int tws = (space.isAdjustable() 
+                ? textArea.getTextWordSpaceAdjust() 
+                        + 2 * textArea.getTextLetterSpaceAdjust()
+                : 0);
+
+        double dx = (font.getCharWidth(sp) + tws) / 100f;
+        try {
+            gen.writeCommand("&a+" + gen.formatDouble2(dx) + "H");
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+        super.renderSpace(space);
+    }
+
+    /**
+     * Render an inline viewport.
+     * This renders an inline viewport by clipping if necessary.
+     * @param viewport the viewport to handle
+     * @todo Copied from AbstractPathOrientedRenderer
+     */
+    public void renderViewport(Viewport viewport) {
+
+        float x = currentIPPosition / 1000f;
+        float y = (currentBPPosition + viewport.getOffset()) / 1000f;
+        float width = viewport.getIPD() / 1000f;
+        float height = viewport.getBPD() / 1000f;
+        // TODO: Calculate the border rect correctly. 
+        float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f;
+        float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f;
+        float bpwidth = borderPaddingStart 
+                + (viewport.getBorderAndPaddingWidthEnd() / 1000f);
+        float bpheight = borderPaddingBefore
+                + (viewport.getBorderAndPaddingWidthAfter() / 1000f);
+
+        drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight);
+
+        if (viewport.getClip()) {
+            saveGraphicsState();
+
+            clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height);
+        }
+        super.renderViewport(viewport);
+
+        if (viewport.getClip()) {
+            restoreGraphicsState();
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
+     */
+    protected void renderBlockViewport(BlockViewport bv, List children) {
+        // clip and position viewport if necessary
+
+        // save positions
+        int saveIP = currentIPPosition;
+        int saveBP = currentBPPosition;
+        //String saveFontName = currentFontName;
+
+        CTM ctm = bv.getCTM();
+        int borderPaddingStart = bv.getBorderAndPaddingWidthStart();
+        int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore();
+        float x, y;
+        x = (float)(bv.getXOffset() + containingIPPosition) / 1000f;
+        y = (float)(bv.getYOffset() + containingBPPosition) / 1000f;
+        //This is the content-rect
+        float width = (float)bv.getIPD() / 1000f;
+        float height = (float)bv.getBPD() / 1000f;
+        
+
+        if (bv.getPositioning() == Block.ABSOLUTE
+                || bv.getPositioning() == Block.FIXED) {
+
+            currentIPPosition = bv.getXOffset();
+            currentBPPosition = bv.getYOffset();
+
+            //For FIXED, we need to break out of the current viewports to the
+            //one established by the page. We save the state stack for restoration
+            //after the block-container has been painted. See below.
+            List breakOutList = null;
+            if (bv.getPositioning() == Block.FIXED) {
+                breakOutList = breakOutOfStateStack();
+            }
+            
+            CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
+            ctm = tempctm.multiply(ctm);
+
+            //Adjust for spaces (from margin or indirectly by start-indent etc.
+            x += bv.getSpaceStart() / 1000f;
+            currentIPPosition += bv.getSpaceStart();
+            
+            y += bv.getSpaceBefore() / 1000f;
+            currentBPPosition += bv.getSpaceBefore(); 
+
+            float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f;
+            float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f;
+
+            drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight);
+
+            //Now adjust for border/padding
+            currentIPPosition += borderPaddingStart;
+            currentBPPosition += borderPaddingBefore;
+            
+            Rectangle2D clippingRect = null;
+            if (bv.getClip()) {
+                clippingRect = new Rectangle(currentIPPosition, currentBPPosition, 
+                        bv.getIPD(), bv.getBPD());
+            }
+
+            startVParea(ctm, clippingRect);
+            currentIPPosition = 0;
+            currentBPPosition = 0;
+            renderBlocks(bv, children);
+            endVParea();
+
+            if (breakOutList != null) {
+                restoreStateStackAfterBreakOut(breakOutList);
+            }
+            
+            currentIPPosition = saveIP;
+            currentBPPosition = saveBP;
+        } else {
+
+            currentBPPosition += bv.getSpaceBefore();
+
+            //borders and background in the old coordinate system
+            handleBlockTraits(bv);
+
+            //Advance to start of content area
+            currentIPPosition += bv.getStartIndent();
+
+            CTM tempctm = new CTM(containingIPPosition, currentBPPosition);
+            ctm = tempctm.multiply(ctm);
+            
+            //Now adjust for border/padding
+            currentBPPosition += borderPaddingBefore;
+
+            Rectangle2D clippingRect = null;
+            if (bv.getClip()) {
+                clippingRect = new Rectangle(currentIPPosition, currentBPPosition, 
+                        bv.getIPD(), bv.getBPD());
+            }
+            
+            startVParea(ctm, clippingRect);
+            currentIPPosition = 0;
+            currentBPPosition = 0;
+            renderBlocks(bv, children);
+            endVParea();
+
+            currentIPPosition = saveIP;
+            currentBPPosition = saveBP;
+            
+            currentBPPosition += (int)(bv.getAllocBPD());
+        }
+        //currentFontName = saveFontName;
+    }
+
+    private List breakOutOfStateStack() {
+        log.debug("Block.FIXED --> break out");
+        List breakOutList = new java.util.ArrayList();
+        while (!this.graphicContextStack.empty()) {
+            breakOutList.add(0, this.graphicContext);
+            restoreGraphicsState();
+        }
+        return breakOutList;
+    }
+
+    private void restoreStateStackAfterBreakOut(List breakOutList) {
+        log.debug("Block.FIXED --> restoring context after break-out");
+        for (int i = 0, c = breakOutList.size(); i < c; i++) {
+            saveGraphicsState();
+            this.graphicContext = (GraphicContext)breakOutList.get(i);
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
+     */
+    public void renderImage(Image image, Rectangle2D pos) {
+        drawImage(image.getURL(), pos, image.getForeignAttributes());
+    }
+
+    /**
+     * Draw an image at the indicated location.
+     * @param url the URI/URL of the image
+     * @param pos the position of the image
+     * @param foreignAttributes an optional Map with foreign attributes, may be null
+     */
+    protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
+        url = ImageFactory.getURL(url);
+        ImageFactory fact = userAgent.getFactory().getImageFactory();
+        FopImage fopimage = fact.getImage(url, userAgent);
+        if (fopimage == null) {
+            return;
+        }
+        if (!fopimage.load(FopImage.DIMENSIONS)) {
+            return;
+        }
+        String mime = fopimage.getMimeType();
+        if ("text/xml".equals(mime)) {
+            if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
+                return;
+            }
+            Document doc = ((XMLImage) fopimage).getDocument();
+            String ns = ((XMLImage) fopimage).getNameSpace();
+
+            renderDocument(doc, ns, pos, foreignAttributes);
+        } else if ("image/svg+xml".equals(mime)) {
+            if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
+                return;
+            }
+            Document doc = ((XMLImage) fopimage).getDocument();
+            String ns = ((XMLImage) fopimage).getNameSpace();
+
+            renderDocument(doc, ns, pos, foreignAttributes);
+        } else if (fopimage instanceof EPSImage) {
+            log.warn("EPS images are not supported by this renderer");
+        } else {
+            if (!fopimage.load(FopImage.BITMAP)) {
+                log.error("Bitmap image could not be processed: " + fopimage);
+                return;
+            }
+            byte[] imgmap = fopimage.getBitmaps();
+            
+            ColorModel cm = new ComponentColorModel(
+                    ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), 
+                    new int[] {8, 8, 8},
+                    false, false,
+                    ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
+            int imgw = fopimage.getWidth();
+            int imgh = fopimage.getHeight();
+            SampleModel sampleModel = new PixelInterleavedSampleModel(
+                    DataBuffer.TYPE_BYTE, imgw, imgh, 3, imgw * 3, new int[] {0, 1, 2});
+            DataBuffer dbuf = new DataBufferByte(imgmap, imgw * imgh * 3);
+
+            WritableRaster raster = Raster.createWritableRaster(sampleModel,
+                    dbuf, null);
+
+            // Combine the color model and raster into a buffered image
+            RenderedImage img = new BufferedImage(cm, raster, false, null);
+
+            try {
+                setCursorPos(this.currentIPPosition + (int)pos.getX(),
+                        this.currentBPPosition + (int)pos.getY());
+                gen.paintBitmap(img, 
+                        new Dimension((int)pos.getWidth(), (int)pos.getHeight()), 
+                        false);
+            } catch (IOException ioe) {
+                handleIOTrouble(ioe);
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
+     */
+    public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
+        Document doc = fo.getDocument();
+        String ns = fo.getNameSpace();
+        renderDocument(doc, ns, pos, fo.getForeignAttributes());
+    }
+
+    /** 
+     * Common method to render the background and borders for any inline area.
+     * The all borders and padding are drawn outside the specified area.
+     * @param area the inline area for which the background, border and padding is to be
+     * rendered
+     * @todo Copied from AbstractPathOrientedRenderer
+     */
+    protected void renderInlineAreaBackAndBorders(InlineArea area) {
+        float x = currentIPPosition / 1000f;
+        float y = (currentBPPosition + area.getOffset()) / 1000f;
+        float width = area.getIPD() / 1000f;
+        float height = area.getBPD() / 1000f;
+        float borderPaddingStart = area.getBorderAndPaddingWidthStart() / 1000f;
+        float borderPaddingBefore = area.getBorderAndPaddingWidthBefore() / 1000f;
+        float bpwidth = borderPaddingStart 
+                + (area.getBorderAndPaddingWidthEnd() / 1000f);
+        float bpheight = borderPaddingBefore
+                + (area.getBorderAndPaddingWidthAfter() / 1000f);
+        
+        if (height != 0.0f || bpheight != 0.0f && bpwidth != 0.0f) {
+            drawBackAndBorders(area, x, y - borderPaddingBefore
+                                , width + bpwidth
+                                , height + bpheight);
+        }
+    }
+    
+    /**
+     * Draw the background and borders. This draws the background and border
+     * traits for an area given the position.
+     *
+     * @param area the area whose traits are used
+     * @param startx the start x position
+     * @param starty the start y position
+     * @param width the width of the area
+     * @param height the height of the area
+     */
+    protected void drawBackAndBorders(Area area, float startx, float starty,
+            float width, float height) {
+        BorderProps bpsBefore = (BorderProps) area.getTrait(Trait.BORDER_BEFORE);
+        BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
+        BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
+        BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
+    
+        // draw background
+        Trait.Background back;
+        back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
+        if (back != null) {
+    
+            // Calculate padding rectangle
+            float sx = startx;
+            float sy = starty;
+            float paddRectWidth = width;
+            float paddRectHeight = height;
+    
+            if (bpsStart != null) {
+                sx += bpsStart.width / 1000f;
+                paddRectWidth -= bpsStart.width / 1000f;
+            }
+            if (bpsBefore != null) {
+                sy += bpsBefore.width / 1000f;
+                paddRectHeight -= bpsBefore.width / 1000f;
+            }
+            if (bpsEnd != null) {
+                paddRectWidth -= bpsEnd.width / 1000f;
+            }
+            if (bpsAfter != null) {
+                paddRectHeight -= bpsAfter.width / 1000f;
+            }
+    
+            if (back.getColor() != null) {
+                updateFillColor(back.getColor());
+                fillRect(sx, sy, paddRectWidth, paddRectHeight);
+            }
+    
+            // background image
+            if (back.getFopImage() != null) {
+                FopImage fopimage = back.getFopImage();
+                if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
+                    saveGraphicsState();
+                    clipRect(sx, sy, paddRectWidth, paddRectHeight);
+                    int horzCount = (int) ((paddRectWidth * 1000 / fopimage
+                            .getIntrinsicWidth()) + 1.0f);
+                    int vertCount = (int) ((paddRectHeight * 1000 / fopimage
+                            .getIntrinsicHeight()) + 1.0f);
+                    if (back.getRepeat() == EN_NOREPEAT) {
+                        horzCount = 1;
+                        vertCount = 1;
+                    } else if (back.getRepeat() == EN_REPEATX) {
+                        vertCount = 1;
+                    } else if (back.getRepeat() == EN_REPEATY) {
+                        horzCount = 1;
+                    }
+                    // change from points to millipoints
+                    sx *= 1000;
+                    sy *= 1000;
+                    if (horzCount == 1) {
+                        sx += back.getHoriz();
+                    }
+                    if (vertCount == 1) {
+                        sy += back.getVertical();
+                    }
+                    for (int x = 0; x < horzCount; x++) {
+                        for (int y = 0; y < vertCount; y++) {
+                            // place once
+                            Rectangle2D pos;
+                            // Image positions are relative to the currentIP/BP
+                            pos = new Rectangle2D.Float(
+                                    sx - currentIPPosition 
+                                        + (x * fopimage.getIntrinsicWidth()),
+                                    sy - currentBPPosition
+                                        + (y * fopimage.getIntrinsicHeight()),
+                                    fopimage.getIntrinsicWidth(),
+                                    fopimage.getIntrinsicHeight());
+                            drawImage(back.getURL(), pos, null);
+                        }
+                    }
+                    restoreGraphicsState();
+                } else {
+                    log.warn(
+                            "Can't find background image: " + back.getURL());
+                }
+            }
+        }
+        
+        Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
+        drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
+    }
+
+    /**
+     * Draws borders.
+     * @param borderRect the border rectangle
+     * @param bpsBefore the border specification on the before side
+     * @param bpsAfter the border specification on the after side
+     * @param bpsStart the border specification on the start side
+     * @param bpsEnd the border specification on the end side
+     */
+    protected void drawBorders(Rectangle2D.Float borderRect, 
+            final BorderProps bpsBefore, final BorderProps bpsAfter, 
+            final BorderProps bpsStart, final BorderProps bpsEnd) {
+        if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
+            return; //no borders to paint
+        }
+        if (qualityBeforeSpeed) {
+            drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
+        } else {
+            drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
+        }
+    }
+    
+    /**
+     * Draws borders. Borders are drawn as shaded rectangles with no clipping.
+     * @param borderRect the border rectangle
+     * @param bpsBefore the border specification on the before side
+     * @param bpsAfter the border specification on the after side
+     * @param bpsStart the border specification on the start side
+     * @param bpsEnd the border specification on the end side
+     */
+    protected void drawFastBorders(Rectangle2D.Float borderRect, 
+            final BorderProps bpsBefore, final BorderProps bpsAfter, 
+            final BorderProps bpsStart, final BorderProps bpsEnd) {
+        float startx = borderRect.x;
+        float starty = borderRect.y;
+        float width = borderRect.width;
+        float height = borderRect.height;
+        if (bpsBefore != null) {
+            float borderWidth = bpsBefore.width / 1000f;
+            updateFillColor(bpsBefore.color);
+            fillRect(startx, starty, width, borderWidth);
+        }
+        if (bpsAfter != null) {
+            float borderWidth = bpsAfter.width / 1000f;
+            updateFillColor(bpsAfter.color);
+            fillRect(startx, (starty + height - borderWidth), 
+                    width, borderWidth);
+        }
+        if (bpsStart != null) {
+            float borderWidth = bpsStart.width / 1000f;
+            updateFillColor(bpsStart.color);
+            fillRect(startx, starty, borderWidth, height);
+        }
+        if (bpsEnd != null) {
+            float borderWidth = bpsEnd.width / 1000f;
+            updateFillColor(bpsEnd.color);
+            fillRect((startx + width - borderWidth), starty, borderWidth, height);
+        }
+    }
+    
+    /**
+     * Draws borders. Borders are drawn in-memory and painted as a bitmap.
+     * @param borderRect the border rectangle
+     * @param bpsBefore the border specification on the before side
+     * @param bpsAfter the border specification on the after side
+     * @param bpsStart the border specification on the start side
+     * @param bpsEnd the border specification on the end side
+     */
+    protected void drawQualityBorders(Rectangle2D.Float borderRect, 
+            final BorderProps bpsBefore, final BorderProps bpsAfter, 
+            final BorderProps bpsStart, final BorderProps bpsEnd) {
+        Graphics2DAdapter g2a = getGraphics2DAdapter();
+        final Rectangle.Float effBorderRect = new Rectangle2D.Float(
+                 borderRect.x - (currentIPPosition / 1000f),
+                 borderRect.y - (currentBPPosition / 1000f),
+                 borderRect.width,
+                 borderRect.height);
+        final Rectangle paintRect = new Rectangle(
+                (int)Math.round(borderRect.x * 1000f),
+                (int)Math.round(borderRect.y * 1000f), 
+                (int)Math.floor(borderRect.width * 1000f) + 1,
+                (int)Math.floor(borderRect.height * 1000f) + 1);
+        //Add one pixel wide safety margin around the paint area
+        int pixelWidth = (int)Math.round(UnitConv.in2mpt(1) / userAgent.getTargetResolution());
+        final int xoffset = (int)Math.round(-effBorderRect.x * 1000f) + pixelWidth;
+        final int yoffset = pixelWidth;
+        paintRect.x += xoffset;
+        paintRect.y += yoffset;
+        paintRect.width += 2 * pixelWidth;
+        paintRect.height += 2 * pixelWidth;
+        
+        RendererContext rc = createRendererContext(paintRect.x, paintRect.y, 
+                paintRect.width, paintRect.height, null);
+        Map atts = new java.util.HashMap();
+        atts.put(CONV_MODE, "bitmap");
+        atts.put(SRC_TRANSPARENCY, "true");
+        rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
+        
+        Graphics2DImagePainter painter = new Graphics2DImagePainter() {
+
+            public void paint(Graphics2D g2d, Rectangle2D area) {
+                g2d.translate(xoffset, yoffset);
+                g2d.scale(1000, 1000);
+                float startx = effBorderRect.x;
+                float starty = effBorderRect.y;
+                float width = effBorderRect.width;
+                float height = effBorderRect.height;
+                boolean[] b = new boolean[] {
+                    (bpsBefore != null), (bpsEnd != null), 
+                    (bpsAfter != null), (bpsStart != null)};
+                if (!b[0] && !b[1] && !b[2] && !b[3]) {
+                    return;
+                }
+                float[] bw = new float[] {
+                    (b[0] ? bpsBefore.width / 1000f : 0.0f),
+                    (b[1] ? bpsEnd.width / 1000f : 0.0f),
+                    (b[2] ? bpsAfter.width / 1000f : 0.0f),
+                    (b[3] ? bpsStart.width / 1000f : 0.0f)};
+                float[] clipw = new float[] {
+                    BorderProps.getClippedWidth(bpsBefore) / 1000f,    
+                    BorderProps.getClippedWidth(bpsEnd) / 1000f,    
+                    BorderProps.getClippedWidth(bpsAfter) / 1000f,    
+                    BorderProps.getClippedWidth(bpsStart) / 1000f};
+                starty += clipw[0];
+                height -= clipw[0];
+                height -= clipw[2];
+                startx += clipw[3];
+                width -= clipw[3];
+                width -= clipw[1];
+                
+                boolean[] slant = new boolean[] {
+                    (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
+                if (bpsBefore != null) {
+                    //endTextObject();
+
+                    float sx1 = startx;
+                    float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
+                    float ex1 = startx + width;
+                    float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
+                    float outery = starty - clipw[0];
+                    float clipy = outery + clipw[0];
+                    float innery = outery + bw[0];
+
+                    //saveGraphicsState();
+                    Graphics2D g = (Graphics2D)g2d.create();
+                    moveTo(sx1, clipy);
+                    float sx1a = sx1;
+                    float ex1a = ex1;
+                    if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
+                        if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
+                            sx1a -= clipw[3];
+                        }
+                        if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
+                            ex1a += clipw[1];
+                        }
+                        lineTo(sx1a, outery);
+                        lineTo(ex1a, outery);
+                    }
+                    lineTo(ex1, clipy);
+                    lineTo(ex2, innery);
+                    lineTo(sx2, innery);
+                    closePath();
+                    //clip();
+                    g.clip(currentPath);
+                    currentPath = null;
+                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
+                            sx1a, outery, ex1a - sx1a, innery - outery);
+                    Java2DRenderer.drawBorderLine(lineRect, true, true, 
+                            bpsBefore.style, bpsBefore.color, g);
+                    //restoreGraphicsState();
+                }
+                if (bpsEnd != null) {
+                    //endTextObject();
+
+                    float sy1 = starty;
+                    float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
+                    float ey1 = starty + height;
+                    float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
+                    float outerx = startx + width + clipw[1];
+                    float clipx = outerx - clipw[1];
+                    float innerx = outerx - bw[1];
+                    
+                    //saveGraphicsState();
+                    Graphics2D g = (Graphics2D)g2d.create();
+                    moveTo(clipx, sy1);
+                    float sy1a = sy1;
+                    float ey1a = ey1;
+                    if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
+                        if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
+                            sy1a -= clipw[0];
+                        }
+                        if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
+                            ey1a += clipw[2];
+                        }
+                        lineTo(outerx, sy1a);
+                        lineTo(outerx, ey1a);
+                    }
+                    lineTo(clipx, ey1);
+                    lineTo(innerx, ey2);
+                    lineTo(innerx, sy2);
+                    closePath();
+                    //clip();
+                    g.setClip(currentPath);
+                    currentPath = null;
+                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
+                            innerx, sy1a, outerx - innerx, ey1a - sy1a);
+                    Java2DRenderer.drawBorderLine(lineRect, false, false, 
+                            bpsEnd.style, bpsEnd.color, g);
+                    //restoreGraphicsState();
+                }
+                if (bpsAfter != null) {
+                    //endTextObject();
+
+                    float sx1 = startx;
+                    float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
+                    float ex1 = startx + width;
+                    float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
+                    float outery = starty + height + clipw[2];
+                    float clipy = outery - clipw[2];
+                    float innery = outery - bw[2];
+
+                    //saveGraphicsState();
+                    Graphics2D g = (Graphics2D)g2d.create();
+                    moveTo(ex1, clipy);
+                    float sx1a = sx1;
+                    float ex1a = ex1;
+                    if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
+                        if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
+                            sx1a -= clipw[3];
+                        }
+                        if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
+                            ex1a += clipw[1];
+                        }
+                        lineTo(ex1a, outery);
+                        lineTo(sx1a, outery);
+                    }
+                    lineTo(sx1, clipy);
+                    lineTo(sx2, innery);
+                    lineTo(ex2, innery);
+                    closePath();
+                    //clip();
+                    g.setClip(currentPath);
+                    currentPath = null;
+                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
+                            sx1a, innery, ex1a - sx1a, outery - innery);
+                    Java2DRenderer.drawBorderLine(lineRect, true, false, 
+                            bpsAfter.style, bpsAfter.color, g);
+                    //restoreGraphicsState();
+                }
+                if (bpsStart != null) {
+                    //endTextObject();
+
+                    float sy1 = starty;
+                    float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
+                    float ey1 = sy1 + height;
+                    float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
+                    float outerx = startx - clipw[3];
+                    float clipx = outerx + clipw[3];
+                    float innerx = outerx + bw[3];
+
+                    //saveGraphicsState();
+                    Graphics2D g = (Graphics2D)g2d.create();
+                    moveTo(clipx, ey1);
+                    float sy1a = sy1;
+                    float ey1a = ey1;
+                    if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
+                        if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
+                            sy1a -= clipw[0];
+                        }
+                        if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
+                            ey1a += clipw[2];
+                        }
+                        lineTo(outerx, ey1a);
+                        lineTo(outerx, sy1a);
+                    }
+                    lineTo(clipx, sy1);
+                    lineTo(innerx, sy2);
+                    lineTo(innerx, ey2);
+                    closePath();
+                    //clip();
+                    g.setClip(currentPath);
+                    currentPath = null;
+                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
+                            outerx, sy1a, innerx - outerx, ey1a - sy1a);
+                    Java2DRenderer.drawBorderLine(lineRect, false, false, 
+                            bpsStart.style, bpsStart.color, g);
+                    //restoreGraphicsState();
+                }
+            }
+
+            public Dimension getImageSize() {
+                return paintRect.getSize();
+            }
+            
+        };
+        try {
+            g2a.paintImage(painter, rc, 
+                    paintRect.x - xoffset, paintRect.y, paintRect.width, paintRect.height);
+        } catch (IOException ioe) {
+            handleIOTrouble(ioe);
+        }
+    }
+    
+    
+    
+}
diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererContext.java b/src/java/org/apache/fop/render/pcl/PCLRendererContext.java
new file mode 100644 (file)
index 0000000..ae5646d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.render.RendererContext;
+import org.apache.fop.util.QName;
+
+/**
+ * Wrapper on the RendererContext to access the information structure for drawing 
+ * the XML document.
+ */
+public class PCLRendererContext extends RendererContext.RendererContextWrapper {
+
+    /**
+     * Wrap the render context to allow easier access to its values.
+     *
+     * @param context the renderer context
+     * @return the PCL-specific renderer context wrapper
+     */
+    public static PCLRendererContext wrapRendererContext(RendererContext context) {
+        PCLRendererContext pcli = new PCLRendererContext(context);
+        return pcli;
+    }
+
+    /**
+     * Main constructor
+     * @param context the RendererContent instance
+     */
+    public PCLRendererContext(RendererContext context) {
+        super(context);
+    }
+    
+    /** @return true if the SVG image should be rendered as a bitmap */
+    public boolean paintAsBitmap() {
+        QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
+        return getForeignAttributes() != null 
+             && "bitmap".equalsIgnoreCase((String)getForeignAttributes().get(qName));
+    }
+    
+    /** @return true if clipping is disabled inside the PCLGraphics2D. */
+    public boolean isClippingDisabled() {
+        QName qName = new QName(ExtensionElementMapping.URI, null, "disable-clipping");
+        return getForeignAttributes() != null 
+             && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
+    }
+
+    public boolean isSourceTransparency() {
+        QName qName = new QName(ExtensionElementMapping.URI, null, "source-transparency");
+        return getForeignAttributes() != null 
+             && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
+    }
+    
+
+}
\ No newline at end of file
diff --git a/src/java/org/apache/fop/render/pcl/PCLRendererMaker.java b/src/java/org/apache/fop/render/pcl/PCLRendererMaker.java
new file mode 100644 (file)
index 0000000..2e39d35
--- /dev/null
@@ -0,0 +1,51 @@
+/*\r
+ * Copyright 2005 The Apache Software Foundation.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+package org.apache.fop.render.pcl;\r
+\r
+import org.apache.fop.apps.FOUserAgent;\r
+import org.apache.fop.apps.MimeConstants;\r
+import org.apache.fop.render.AbstractRendererMaker;\r
+import org.apache.fop.render.Renderer;\r
+\r
+/**\r
+ * RendererMaker for the PCL Renderer.\r
+ */\r
+public class PCLRendererMaker extends AbstractRendererMaker {\r
+\r
+    private static final String[] MIMES = new String[] {\r
+        MimeConstants.MIME_PCL,\r
+        MimeConstants.MIME_PCL_ALT};\r
+    \r
+    \r
+    /**@see org.apache.fop.render.AbstractRendererMaker */\r
+    public Renderer makeRenderer(FOUserAgent ua) {\r
+        return new PCLRenderer();\r
+    }\r
+\r
+    /** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */\r
+    public boolean needsOutputStream() {\r
+        return true;\r
+    }\r
+\r
+    /** @see org.apache.fop.render.AbstractRendererMaker#getSupportedMimeTypes() */\r
+    public String[] getSupportedMimeTypes() {\r
+        return MIMES;\r
+    }\r
+\r
+}\r
diff --git a/src/java/org/apache/fop/render/pcl/PCLSVGHandler.java b/src/java/org/apache/fop/render/pcl/PCLSVGHandler.java
new file mode 100644 (file)
index 0000000..7c1a45a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pcl;
+
+// FOP
+import org.apache.fop.render.AbstractGenericSVGHandler;
+import org.apache.fop.render.Renderer;
+
+/**
+ * PCL XML handler for SVG. Uses Apache Batik for SVG processing.
+ * This handler handles XML for foreign objects when rendering to HP GL/2.
+ * It renders SVG to HP GL/2 using the PCLGraphics2D.
+ * @see PCLGraphics2DAdapter
+ */
+public class PCLSVGHandler extends AbstractGenericSVGHandler {
+
+    /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */
+    public boolean supportsRenderer(Renderer renderer) {
+        return (renderer instanceof PCLRenderer);
+    }
+    
+}
+
diff --git a/src/java/org/apache/fop/render/pcl/extensions/PCLElementMapping.java b/src/java/org/apache/fop/render/pcl/extensions/PCLElementMapping.java
new file mode 100644 (file)
index 0000000..b25ab93
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: AFPElementMapping.java 397875 2006-04-28 11:58:33Z manuel $ */
+
+package org.apache.fop.render.pcl.extensions;
+
+import java.util.HashMap;
+
+import org.apache.fop.fo.ElementMapping;
+
+/**
+ * PCL-specific extensions for Apache FOP.
+ */
+public class PCLElementMapping extends ElementMapping {
+
+    /** The namespace used for PCL extensions */
+    public static final String NAMESPACE = "http://xmlgraphics.apache.org/fop/extensions/pcl";
+
+    /** The usual namespace prefix used for PCL extensions */
+    public static final String NAMESPACE_PREFIX = "pcl";
+
+    /** Main constructor */
+    public PCLElementMapping() {
+        this.namespaceURI = NAMESPACE;
+    }
+
+    /** @see org.apache.fop.fo.ElementMapping#initialize() */
+    protected void initialize() {
+
+        if (foObjs == null) {
+            foObjs = new HashMap();
+            //No extension elements, yet, only attributes
+        }
+
+    }
+
+}
diff --git a/src/java/org/apache/fop/render/pcl/package.html b/src/java/org/apache/fop/render/pcl/package.html
new file mode 100644 (file)
index 0000000..ba47bd2
--- /dev/null
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2005-2006 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- $Id$ -->
+<HTML>
+<TITLE>org.apache.fop.render.pcl Package</TITLE>
+<BODY>
+<P>PCL Renderer (Supports PCL5 and HP GL/2)</P>
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java b/src/sandbox/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java
deleted file mode 100644 (file)
index 4358044..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import java.awt.RenderingHints;
-import java.awt.color.ColorSpace;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorConvertOp;
-import java.awt.image.RenderedImage;
-
-/**
- * Default implementation of the MonochromeBitmapConverter which uses the Java Class Library
- * to convert grayscale bitmaps to monochrome bitmaps.
- */
-public class DefaultMonochromeBitmapConverter implements
-        MonochromeBitmapConverter {
-
-    /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
-    public void setHint(String name, String value) {
-        //ignore, not supported
-    }
-    
-    /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
-    public RenderedImage convertToMonochrome(BufferedImage img) {
-        BufferedImage buf = new BufferedImage(img.getWidth(), img.getHeight(), 
-                BufferedImage.TYPE_BYTE_BINARY);
-        RenderingHints hints = new RenderingHints(null);
-        //This hint doesn't seem to make a difference :-(
-        hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
-        ColorConvertOp op = new ColorConvertOp(
-                ColorSpace.getInstance(ColorSpace.CS_GRAY), hints);
-        op.filter(img, buf);
-        return buf;
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java b/src/sandbox/org/apache/fop/render/pcl/JAIMonochromeBitmapConverter.java
deleted file mode 100644 (file)
index 4818b2b..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import java.awt.RenderingHints;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.IndexColorModel;
-import java.awt.image.RenderedImage;
-import java.awt.image.renderable.ParameterBlock;
-
-import javax.media.jai.ColorCube;
-import javax.media.jai.ImageLayout;
-import javax.media.jai.JAI;
-import javax.media.jai.KernelJAI;
-import javax.media.jai.LookupTableJAI;
-import javax.media.jai.PlanarImage;
-
-/**
- * Implementation of the MonochromeBitmapConverter which uses Java Advanced Imaging (JAI)
- * to convert grayscale bitmaps to monochrome bitmaps. JAI provides better dithering options
- * including error diffusion dithering.
- * <p>
- * If you call setHint("quality", "true") on the instance you can enabled error diffusion
- * dithering which produces a nicer result but is also a lot slower.
- */
-public class JAIMonochromeBitmapConverter implements
-        MonochromeBitmapConverter {
-
-    private boolean isErrorDiffusion = false;
-    
-    /** @see MonochromeBitmapConverter#setHint(java.lang.String, java.lang.String) */
-    public void setHint(String name, String value) {
-        if ("quality".equalsIgnoreCase(name)) {
-            isErrorDiffusion = "true".equalsIgnoreCase(value);
-        }
-    }
-    
-    /** @see MonochromeBitmapConverter#convertToMonochrome(java.awt.image.BufferedImage) */
-    public RenderedImage convertToMonochrome(BufferedImage img) {
-        if (img.getColorModel().getColorSpace().getNumComponents() != 1) {
-            throw new IllegalArgumentException("Source image must be a grayscale image!");
-        }
-        
-        // Load the ParameterBlock for the dithering operation
-        // and set the operation name.
-        ParameterBlock pb = new ParameterBlock();
-        pb.addSource(img);
-        String opName = null;
-        if (isErrorDiffusion) {
-            opName = "errordiffusion";
-            LookupTableJAI lut = new LookupTableJAI(new byte[] {(byte)0x00, (byte)0xff});
-            pb.add(lut);
-            pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);
-        } else {
-            opName = "ordereddither";
-            //Create the color cube.
-            ColorCube colorMap = ColorCube.createColorCube(DataBuffer.TYPE_BYTE,
-                    0, new int[] {2});
-            pb.add(colorMap);
-            pb.add(KernelJAI.DITHER_MASK_441);
-        }
-        
-        //Create an image layout for a monochrome b/w image
-        ImageLayout layout = new ImageLayout();
-        byte[] map = new byte[] {(byte)0x00, (byte)0xff};
-        ColorModel cm = new IndexColorModel(1, 2, map, map, map);
-        layout.setColorModel(cm);
-
-        // Create a hint containing the layout.
-        RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout);
-
-        // Dither the image.
-        PlanarImage dst = JAI.create(opName, pb, hints);        
-        
-        //Convert it to a BufferedImage
-        return dst.getAsBufferedImage();
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/MonochromeBitmapConverter.java b/src/sandbox/org/apache/fop/render/pcl/MonochromeBitmapConverter.java
deleted file mode 100644 (file)
index f2db9d7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.RenderedImage;
-
-/**
- * Interface for converters that convert grayscale images to monochrome (1-bit) bitmap images.
- */
-public interface MonochromeBitmapConverter {
-
-    /**
-     * Sets a hint to the implementation
-     * @param name the name of the hint
-     * @param value the value
-     */
-    void setHint(String name, String value);
-    
-    /**
-     * Converts a grayscale bitmap image to a monochrome (1-bit) b/w bitmap image. 
-     * @param img the grayscale image
-     * @return the converted monochrome image
-     */
-    RenderedImage convertToMonochrome(BufferedImage img);
-    
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java b/src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java
deleted file mode 100644 (file)
index 8612a51..0000000
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.color.ColorSpace;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ByteLookupTable;
-import java.awt.image.ColorConvertOp;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.IndexColorModel;
-import java.awt.image.LookupOp;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.awt.image.WritableRaster;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.Locale;
-
-import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.image.GraphicsUtil;
-
-/**
- * This class provides methods for generating PCL print files.
- */
-public class PCLGenerator {
-
-    /** The ESC (escape) character */
-    public static final char ESC = '\033';
-    
-    /** A list of all supported resolutions in PCL (values in dpi) */
-    public static final int[] PCL_RESOLUTIONS = new int[] {75, 100, 150, 200, 300, 600};
-    
-    private final DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US); 
-    private final DecimalFormat df2 = new DecimalFormat("0.##", symbols);
-    private final DecimalFormat df4 = new DecimalFormat("0.####", symbols);
-    
-    private OutputStream out;
-    
-    private boolean currentSourceTransparency = true;
-    private boolean currentPatternTransparency = true;
-    
-    private int maxBitmapResolution = PCL_RESOLUTIONS[PCL_RESOLUTIONS.length - 1];
-    
-    /**
-     * Main constructor.
-     * @param out the OutputStream to write the PCL stream to
-     */
-    public PCLGenerator(OutputStream out) {
-        this.out = out;
-    }
-    
-    /**
-     * Main constructor.
-     * @param out the OutputStream to write the PCL stream to
-     * @param maxResolution the maximum resolution to encode bitmap images at
-     */
-    public PCLGenerator(OutputStream out, int maxResolution) {
-        this(out);
-        boolean found = false;
-        for (int i = 0; i < PCL_RESOLUTIONS.length; i++) {
-            if (PCL_RESOLUTIONS[i] == maxResolution) {
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            throw new IllegalArgumentException("Illegal value for maximum resolution!");
-        }
-        this.maxBitmapResolution = maxResolution;
-    }
-    
-    /** @return the OutputStream that this generator writes to */
-    public OutputStream getOutputStream() {
-        return this.out;
-    }
-    
-    /** @return the maximum resolution to encode bitmap images at */
-    public int getMaximumBitmapResolution() {
-        return this.maxBitmapResolution;
-    }
-    
-    /**
-     * Writes a PCL escape command to the output stream.
-     * @param cmd the command (without the ESCAPE character)
-     * @throws IOException In case of an I/O error
-     */
-    public void writeCommand(String cmd) throws IOException {
-        out.write(27); //ESC
-        out.write(cmd.getBytes("US-ASCII"));
-    }
-    
-    /**
-     * Writes raw text (in ISO-8859-1 encoding) to the output stream.
-     * @param s the text
-     * @throws IOException In case of an I/O error
-     */
-    public void writeText(String s) throws IOException {
-        out.write(s.getBytes("ISO-8859-1"));
-    }
-
-    /**
-     * Formats a double value with two decimal positions for PCL output.
-     * 
-     * @param value value to format
-     * @return the formatted value
-     */
-    public final String formatDouble2(double value) {
-        return df2.format(value);
-    }
-
-    /**
-     * Formats a double value with four decimal positions for PCL output.
-     * 
-     * @param value value to format
-     * @return the formatted value
-     */
-    public final String formatDouble4(double value) {
-        return df4.format(value);
-    }
-
-    /**
-     * Sends the universal end of language command (UEL).
-     * @throws IOException In case of an I/O error
-     */
-    public void universalEndOfLanguage() throws IOException {
-        writeCommand("%-12345X");
-    }
-    
-    /**
-     * Resets the printer and restores the user default environment.
-     * @throws IOException In case of an I/O error
-     */
-    public void resetPrinter() throws IOException {
-        writeCommand("E");
-    }
-    
-    /**
-     * Sends the job separation command.
-     * @throws IOException In case of an I/O error
-     */
-    public void separateJobs() throws IOException {
-        writeCommand("&l1T");
-    }
-    
-    /**
-     * Sends the form feed character.
-     * @throws IOException In case of an I/O error
-     */
-    public void formFeed() throws IOException {
-        out.write(12); //=OC ("FF", Form feed)
-    }
-
-    /**
-     * Sets the unit of measure.
-     * @param value the resolution value (units per inch)
-     * @throws IOException In case of an I/O error
-     */
-    public void setUnitOfMeasure(int value) throws IOException {
-        writeCommand("&u" + value + "D");
-    }
-    
-    /**
-     * Sets the raster graphics resolution
-     * @param value the resolution value (units per inch)
-     * @throws IOException In case of an I/O error
-     */
-    public void setRasterGraphicsResolution(int value) throws IOException {
-        writeCommand("*t" + value + "R");
-    }
-    
-    /**
-     * Selects the page size.
-     * @param selector the integer representing the page size
-     * @throws IOException In case of an I/O error
-     */
-    public void selectPageSize(int selector) throws IOException {
-        writeCommand("&l" + selector + "A");
-    }
-
-    /**
-     * Selects the paper source. The parameter is usually printer-specific. Usually, "1" is the 
-     * default tray, "2" is the manual paper feed, "3" is the manual envelope feed, "4" is the
-     * "lower" tray and "7" is "auto-select". Consult the technical reference for your printer
-     * for all available values.
-     * @param selector the integer representing the paper source/tray
-     * @throws IOException In case of an I/O error
-     */
-    public void selectPaperSource(int selector) throws IOException {
-        writeCommand("&l" + selector + "H");
-    }
-
-    /**
-     * Clears the horizontal margins.
-     * @throws IOException In case of an I/O error
-     */
-    public void clearHorizontalMargins() throws IOException {
-        writeCommand("9");
-    }
-    
-    /**
-     * The Top Margin command designates the number of lines between
-     * the top of the logical page and the top of the text area.
-     * @param numberOfLines the number of lines (See PCL specification for details)
-     * @throws IOException In case of an I/O error
-     */
-    public void setTopMargin(int numberOfLines) throws IOException {
-        writeCommand("&l" + numberOfLines + "E");
-    }
-
-    /**
-     * The Text Length command can be used to define the bottom border. See the PCL specification
-     * for details.
-     * @param numberOfLines the number of lines
-     * @throws IOException In case of an I/O error
-     */
-    public void setTextLength(int numberOfLines) throws IOException {
-        writeCommand("&l" + numberOfLines + "F");
-    }
-
-    /**
-     * Sets the Vertical Motion Index (VMI).
-     * @param value the VMI value
-     * @throws IOException In case of an I/O error
-     */
-    public void setVMI(double value) throws IOException {
-        writeCommand("&l" + formatDouble4(value) + "C");
-    }
-
-    /**
-     * Sets the cursor to a new absolute coordinate.
-     * @param x the X coordinate (in millipoints)
-     * @param y the Y coordinate (in millipoints)
-     * @throws IOException In case of an I/O error
-     */
-    public void setCursorPos(double x, double y) throws IOException {
-        if (x < 0) {
-            //A negative x value will result in a relative movement so go to "0" first.
-            //But this will most probably have no effect anyway since you can't paint to the left
-            //of the logical page
-            writeCommand("&a0h" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
-        } else {
-            writeCommand("&a" + formatDouble2(x / 100) + "h" + formatDouble2(y / 100) + "V");
-        }
-    }
-
-    /**
-     * Pushes the current cursor position on a stack (stack size: max 20 entries)
-     * @throws IOException In case of an I/O error
-     */
-    public void pushCursorPos() throws IOException {
-        writeCommand("&f0S");
-    }
-    
-    /**
-     * Pops the current cursor position from the stack.
-     * @throws IOException In case of an I/O error
-     */
-    public void popCursorPos() throws IOException {
-        writeCommand("&f1S");
-    }
-    
-    /**
-     * Changes the current print direction while maintaining the current cursor position.
-     * @param rotate the rotation angle (counterclockwise), one of 0, 90, 180 and 270.
-     * @throws IOException In case of an I/O error
-     */
-    public void changePrintDirection(int rotate) throws IOException {
-        writeCommand("&a" + rotate + "P");
-    }
-    
-    /**
-     * Enters the HP GL/2 mode.
-     * @param restorePreviousHPGL2Cursor true if the previous HP GL/2 pen position should be 
-     *                                   restored, false if the current position is maintained
-     * @throws IOException In case of an I/O error
-     */
-    public void enterHPGL2Mode(boolean restorePreviousHPGL2Cursor) throws IOException {
-        if (restorePreviousHPGL2Cursor) {
-            writeCommand("%0B");
-        } else {
-            writeCommand("%1B");
-        }
-    }
-    
-    /**
-     * Enters the PCL mode.
-     * @param restorePreviousPCLCursor true if the previous PCL cursor position should be restored,
-     *                                 false if the current position is maintained
-     * @throws IOException In case of an I/O error
-     */
-    public void enterPCLMode(boolean restorePreviousPCLCursor) throws IOException {
-        if (restorePreviousPCLCursor) {
-            writeCommand("%0A");
-        } else {
-            writeCommand("%1A");
-        }
-    }
-    
-    /**
-     * Generate a filled rectangle at the current cursor position.
-     *
-     * @param w the width in millipoints
-     * @param h the height in millipoints
-     * @param col the fill color
-     * @throws IOException In case of an I/O error
-     */
-    protected void fillRect(int w, int h, Color col) throws IOException {
-        if ((w == 0) || (h == 0)) {
-            return;
-        }
-        if (h < 0) {
-            h *= -1;
-        } else {
-            //y += h;
-        }
-
-        setPatternTransparencyMode(false);
-        writeCommand("*c" + formatDouble4(w / 100) + "h" 
-                          + formatDouble4(h / 100) + "V");
-        int lineshade = convertToPCLShade(col);
-        writeCommand("*c" + lineshade + "G");
-        writeCommand("*c2P");
-        // Reset pattern transparency mode.
-        setPatternTransparencyMode(true);
-    }
-
-    /**
-     * Sets the source transparency mode.
-     * @param transparent true if transparent, false for opaque
-     * @throws IOException In case of an I/O error
-     */
-    public void setSourceTransparencyMode(boolean transparent) throws IOException {
-        setTransparencyMode(transparent, currentPatternTransparency);
-    }
-
-    /**
-     * Sets the pattern transparency mode.
-     * @param transparent true if transparent, false for opaque
-     * @throws IOException In case of an I/O error
-     */
-    public void setPatternTransparencyMode(boolean transparent) throws IOException {
-        setTransparencyMode(currentSourceTransparency, transparent);
-    }
-
-    /**
-     * Sets the transparency modes.
-     * @param source source transparency: true if transparent, false for opaque
-     * @param pattern pattern transparency: true if transparent, false for opaque
-     * @throws IOException In case of an I/O error
-     */
-    public void setTransparencyMode(boolean source, boolean pattern) throws IOException {
-        if (source != currentSourceTransparency && pattern != currentPatternTransparency) {
-            writeCommand("*v" + (source ? '0' : '1') + "n" + (pattern ? '0' : '1') + "O");
-        } else if (source != currentSourceTransparency) {
-            writeCommand("*v" + (source ? '0' : '1') + "N");
-        } else if (pattern != currentPatternTransparency) {
-            writeCommand("*v" + (pattern ? '0' : '1') + "O");
-        }
-        this.currentSourceTransparency = source;
-        this.currentPatternTransparency = pattern;
-    }
-
-    /**
-     * Convert an RGB color value to a grayscale from 0 to 100.
-     * @param r the red component
-     * @param g the green component
-     * @param b the blue component
-     * @return the gray value
-     */
-    public final int convertToGray(int r, int g, int b) {
-        return (r * 30 + g * 59 + b * 11) / 100;
-    }
-    
-    /**
-     * Convert a Color value to a PCL shade value (0-100).
-     * @param col the color
-     * @return the PCL shade value (100=black)
-     */
-    public final int convertToPCLShade(Color col) {
-        float gray = convertToGray(col.getRed(), col.getGreen(), col.getBlue()) / 255f;
-        return (int)(100 - (gray * 100f));
-    }
-    
-    /**
-     * Select the current pattern
-     * @param patternID the pattern ID (<ESC>*c#G command)
-     * @param pattern the pattern type (<ESC>*v#T command)
-     * @throws IOException In case of an I/O error
-     */
-    public void selectCurrentPattern(int patternID, int pattern) throws IOException {
-        if (pattern > 1) {
-            writeCommand("*c" + patternID + "G");
-        }
-        writeCommand("*v" + pattern + "T");
-    }
-
-    /**
-     * Indicates whether an image is a monochrome (b/w) image.
-     * @param img the image
-     * @return true if it's a monochrome image
-     */
-    public static boolean isMonochromeImage(RenderedImage img) {
-        ColorModel cm = img.getColorModel();
-        if (cm instanceof IndexColorModel) {
-            IndexColorModel icm = (IndexColorModel)cm;
-            return icm.getMapSize() == 2;
-        } else {
-            return false;
-        }
-    }
-    
-    /**
-     * Indicates whether an image is a grayscale image.
-     * @param img the image
-     * @return true if it's a grayscale image
-     */
-    public static boolean isGrayscaleImage(RenderedImage img) {
-        return (img.getColorModel().getColorSpace().getNumComponents() == 1);
-    }
-    
-    private MonochromeBitmapConverter createMonochromeBitmapConverter() {
-        MonochromeBitmapConverter converter = null;
-        try {
-            String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
-            Class clazz = Class.forName(clName);
-            converter = (MonochromeBitmapConverter)clazz.newInstance();
-        } catch (ClassNotFoundException cnfe) {
-            // Class was not compiled so is not available. Simply ignore.
-        } catch (LinkageError le) {
-            // This can happen if fop was build with support for a
-            // particular provider (e.g. a binary fop distribution)
-            // but the required support files (i.e. JAI) are not
-            // available in the current runtime environment.
-            // Simply continue with the backup implementation.
-        } catch (InstantiationException e) {
-            // Problem instantiating the class, simply continue with the backup implementation
-        } catch (IllegalAccessException e) {
-            // Problem instantiating the class, simply continue with the backup implementation
-        }
-        if (converter == null) {
-            converter = new DefaultMonochromeBitmapConverter();
-        }
-        return converter;
-    }
-
-    private int calculatePCLResolution(int resolution) {
-        return calculatePCLResolution(resolution, false);
-    }
-    
-    /**
-     * Calculates the ideal PCL resolution for a given resolution.
-     * @param resolution the input resolution
-     * @param increased true if you want to go to a higher resolution, for example if you
-     *                  convert grayscale or color images to monochrome images so dithering has
-     *                  a chance to generate better quality.
-     * @return the resulting PCL resolution (one of 75, 100, 150, 200, 300, 600)
-     */
-    private int calculatePCLResolution(int resolution, boolean increased) {
-        int choice = -1;
-        for (int i = PCL_RESOLUTIONS.length - 2; i >= 0; i--) {
-            if (resolution > PCL_RESOLUTIONS[i]) {
-                int idx = i + 1;
-                if (idx < PCL_RESOLUTIONS.length - 2) {
-                    idx += increased ? 2 : 0;
-                } else if (idx < PCL_RESOLUTIONS.length - 1) {
-                    idx += increased ? 1 : 0;
-                }
-                choice = idx;
-                break;
-                //return PCL_RESOLUTIONS[idx];
-            }
-        }
-        if (choice < 0) {
-            choice = (increased ? 2 : 0);
-        }
-        while (choice > 0 && PCL_RESOLUTIONS[choice] > getMaximumBitmapResolution()) {
-            choice--;
-        }
-        return PCL_RESOLUTIONS[choice];
-    }
-    
-    private boolean isValidPCLResolution(int resolution) {
-        return resolution == calculatePCLResolution(resolution);
-    }
-    
-    private Dimension getAdjustedDimension(Dimension orgDim, double orgResolution, 
-            int pclResolution) {
-        if (orgResolution == pclResolution) {
-            return orgDim;
-        } else {
-            Dimension result = new Dimension();
-            result.width = (int)Math.round((double)orgDim.width * pclResolution / orgResolution); 
-            result.height = (int)Math.round((double)orgDim.height * pclResolution / orgResolution); 
-            return result;
-        }
-    }
-    
-    //Threshold table to convert an alpha channel (8-bit) into a clip mask (1-bit)
-    private static final byte[] THRESHOLD_TABLE = new byte[256];
-    static { // Initialize the arrays
-        for (int i = 0; i < 256; i++) {
-            THRESHOLD_TABLE[i] = (byte) ((i < 240) ? 255 : 0);
-        }
-    }    
-    
-    private RenderedImage getMask(RenderedImage img, Dimension targetDim) {
-        ColorModel cm = img.getColorModel(); 
-        if (cm.hasAlpha()) {
-            BufferedImage alpha = new BufferedImage(img.getWidth(), img.getHeight(), 
-                    BufferedImage.TYPE_BYTE_GRAY);
-            Raster raster = img.getData();
-            GraphicsUtil.copyBand(raster, cm.getNumColorComponents(), alpha.getRaster(), 0);
-
-            BufferedImageOp op1 = new LookupOp(new ByteLookupTable(0, THRESHOLD_TABLE), null);
-            BufferedImage alphat = op1.filter(alpha, null);
-
-            BufferedImage mask;
-            if (true) {
-                mask = new BufferedImage(targetDim.width, targetDim.height,
-                        BufferedImage.TYPE_BYTE_BINARY);
-            } else {
-                byte[] arr = {(byte)0, (byte)0xff};
-                ColorModel colorModel = new IndexColorModel(1, 2, arr, arr, arr);
-                WritableRaster wraster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
-                                                   targetDim.width, targetDim.height, 1, 1, null);
-                mask = new BufferedImage(colorModel, wraster, false, null);
-            }
-            
-            Graphics2D g2d = mask.createGraphics();
-            try {
-                AffineTransform at = new AffineTransform();
-                double sx = targetDim.getWidth() / img.getWidth();
-                double sy = targetDim.getHeight() / img.getHeight();
-                at.scale(sx, sy);
-                g2d.drawRenderedImage(alphat, at);
-            } finally {
-                g2d.dispose();
-            }
-            /*
-            try {
-                BatchDiffer.saveAsPNG(alpha, new java.io.File("D:/out-alpha.png"));
-                BatchDiffer.saveAsPNG(mask, new java.io.File("D:/out-mask.png"));
-            } catch (IOException e) {
-                e.printStackTrace();
-            }*/
-            return mask;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Paint a bitmap at the current cursor position. The bitmap is converted to a monochrome
-     * (1-bit) bitmap image.
-     * @param img the bitmap image
-     * @param targetDim the target Dimention (in mpt)
-     * @param sourceTransparency true if the background should not be erased
-     * @throws IOException In case of an I/O error
-     */
-    public void paintBitmap(RenderedImage img, Dimension targetDim, boolean sourceTransparency) 
-                throws IOException {
-        double targetResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width);
-        int resolution = (int)Math.round(targetResolution);
-        int effResolution = calculatePCLResolution(resolution, true);
-        Dimension orgDim = new Dimension(img.getWidth(), img.getHeight());
-        Dimension effDim = getAdjustedDimension(orgDim, targetResolution, effResolution);
-        boolean scaled = !orgDim.equals(effDim);
-
-        boolean monochrome = isMonochromeImage(img);
-        if (!monochrome) {
-            //Transparency mask disabled. Doesn't work reliably
-            final boolean transparencyDisabled = true;
-            RenderedImage mask = (transparencyDisabled ? null : getMask(img, effDim)); 
-            if (mask != null) {
-                pushCursorPos();
-                selectCurrentPattern(0, 1); //Solid white
-                setTransparencyMode(true, true);
-                paintMonochromeBitmap(mask, effResolution);
-                popCursorPos();
-            }
-            
-            BufferedImage src = null;
-            if (img instanceof BufferedImage && !scaled) {
-                if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) {
-                    src = new BufferedImage(effDim.width, effDim.height, 
-                            BufferedImage.TYPE_BYTE_GRAY);
-                    ColorConvertOp op = new ColorConvertOp(
-                            ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
-                    op.filter((BufferedImage)img, src);
-                } else {
-                    src = (BufferedImage)img;
-                }
-            }
-            if (src == null) {
-                src = new BufferedImage(effDim.width, effDim.height, 
-                        BufferedImage.TYPE_BYTE_GRAY);
-                Graphics2D g2d = src.createGraphics();
-                try {
-                    AffineTransform at = new AffineTransform();
-                    double sx = effDim.getWidth() / orgDim.getWidth();
-                    double sy = effDim.getHeight() / orgDim.getHeight();
-                    at.scale(sx, sy);
-                    g2d.drawRenderedImage(img, at);
-                } finally {
-                    g2d.dispose();
-                }
-            }
-            MonochromeBitmapConverter converter = createMonochromeBitmapConverter();
-            converter.setHint("quality", "false");
-
-            BufferedImage buf = (BufferedImage)converter.convertToMonochrome(src);
-            
-            RenderedImage red = buf;
-            selectCurrentPattern(0, 0); //Solid black
-            setTransparencyMode(sourceTransparency || mask != null, true);
-            paintMonochromeBitmap(red, effResolution);
-        } else {
-            //TODO untested!
-            RenderedImage effImg = img;
-            if (scaled) {
-                BufferedImage buf = new BufferedImage(effDim.width, effDim.height, 
-                        BufferedImage.TYPE_BYTE_BINARY);
-                Graphics2D g2d = buf.createGraphics();
-                try {
-                    AffineTransform at = new AffineTransform();
-                    double sx = effDim.getWidth() / orgDim.getWidth();
-                    double sy = effDim.getHeight() / orgDim.getHeight();
-                    at.scale(sx, sy);
-                    g2d.drawRenderedImage(img, at);
-                } finally {
-                    g2d.dispose();
-                }
-                effImg = buf;
-            }
-            setSourceTransparencyMode(sourceTransparency);
-            selectCurrentPattern(0, 0); //Solid black
-            paintMonochromeBitmap(effImg, effResolution);
-        }
-    }
-
-    /**
-     * Paint a bitmap at the current cursor position. The bitmap must be a monochrome
-     * (1-bit) bitmap image.
-     * @param img the bitmap image (must be 1-bit b/w)
-     * @param resolution the resolution of the image (must be a PCL resolution)
-     * @throws IOException In case of an I/O error
-     */
-    public void paintMonochromeBitmap(RenderedImage img, int resolution) throws IOException {
-        if (!isValidPCLResolution(resolution)) {
-            throw new IllegalArgumentException("Invalid PCL resolution: " + resolution);
-        }
-        setRasterGraphicsResolution(resolution);
-        writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
-        Raster raster = img.getData();
-        boolean monochrome = isMonochromeImage(img);
-        if (!monochrome) {
-            throw new IllegalArgumentException("img must be a monochrome image");
-        }
-        
-        int x = 0;
-        int y = 0;
-        int imgw = img.getWidth();
-        int imgh = img.getHeight();
-        int bytewidth = (imgw / 8);
-        if ((imgw % 8) != 0) {
-            bytewidth++;
-        }
-        byte ib;
-        byte[] rle = new byte[bytewidth * 2]; //compressed (RLE)
-        byte[] uncompressed = new byte[bytewidth]; //uncompressed
-        int lastcount = -1;
-        byte lastbyte = 0;
-        int rlewidth = 0;
-
-        // Transfer graphics data
-        for (y = 0; y < imgh; y++) {
-            ib = 0;
-            for (x = 0; x < imgw; x++) {
-                int sample = raster.getSample(x, y, 0);
-                //Set image bit for black
-                if ((sample == 0)) {
-                    ib |= (1 << (7 - (x % 8)));
-                }
-                    
-                //RLE encoding
-                if ((x % 8) == 7 || ((x + 1) == imgw)) {
-                    if (rlewidth < bytewidth) {
-                        if (lastcount >= 0) {
-                            if (ib == lastbyte) {
-                                lastcount++;
-                            } else {
-                                rle[rlewidth++] = (byte)(lastcount & 0xFF);
-                                rle[rlewidth++] = lastbyte;
-                                lastbyte = ib;
-                                lastcount = 0;
-                            }
-                        } else {
-                            lastbyte = ib;
-                            lastcount = 0;
-                        }
-                        if (lastcount == 255 || ((x + 1) == imgw)) {
-                            rle[rlewidth++] = (byte)(lastcount & 0xFF);
-                            rle[rlewidth++] = lastbyte;
-                            lastbyte = 0;
-                            lastcount = -1;
-                        }
-                    }
-                    uncompressed[x / 8] = ib;
-                    ib = 0;
-                }
-            }
-            if (rlewidth < bytewidth) {
-                writeCommand("*b1m" + rlewidth + "W");
-                this.out.write(rle, 0, rlewidth);
-            } else {
-                writeCommand("*b0m" + bytewidth + "W");
-                this.out.write(uncompressed);
-            }
-            lastcount = -1;
-            rlewidth = 0;
-        }
-
-        // End raster graphics
-        writeCommand("*rB");
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java b/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java
deleted file mode 100644 (file)
index 0e27a8d..0000000
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsEnvironment;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.awt.image.RenderedImage;
-import java.awt.image.renderable.RenderableImage;
-import java.io.IOException;
-import java.text.AttributedCharacterIterator;
-
-import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-/**
- * Graphics2D implementation implementing PCL and HP GL/2.
- * Note: This class cannot be used stand-alone to create full PCL documents.
- */
-public class PCLGraphics2D extends AbstractGraphics2D {
-
-    /** The PCL generator */
-    protected PCLGenerator gen;
-    
-    private boolean failOnUnsupportedFeature = true;
-    private boolean clippingDisabled = false;
-    
-    /**
-     * Create a new PCLGraphics2D.
-     * @param gen the PCL Generator to paint with
-     */
-    public PCLGraphics2D(PCLGenerator gen) {
-        super(true);
-        this.gen = gen;
-    }
-
-    /**
-     * Copy constructor
-     * @param g parent PCLGraphics2D
-     */
-    public PCLGraphics2D(PCLGraphics2D g) {
-        super(true);
-        this.gen = g.gen;
-    }
-
-    /** @see java.awt.Graphics#create() */
-    public Graphics create() {
-        PCLGraphics2D copy = new PCLGraphics2D(this);
-        copy.setGraphicContext((GraphicContext)getGraphicContext().clone());
-        return copy;
-    }
-
-    /** @see java.awt.Graphics#dispose() */
-    public void dispose() {
-        this.gen = null;
-    }
-
-    /**
-     * Sets the GraphicContext
-     * @param c GraphicContext to use
-     */
-    public void setGraphicContext(GraphicContext c) {
-        this.gc = c;
-    }
-
-    /**
-     * Allows to disable all clipping operations.
-     * @param value true if clipping should be disabled.
-     */
-    public void setClippingDisabled(boolean value) {
-        this.clippingDisabled = value;
-    }
-    
-    /**
-     * Central handler for IOExceptions for this class.
-     * @param ioe IOException to handle
-     */
-    public void handleIOException(IOException ioe) {
-        //TODO Surely, there's a better way to do this.
-        ioe.printStackTrace();
-    }
-
-    /**
-     * Raises an UnsupportedOperationException if this instance is configured to do so and an
-     * unsupported feature has been requested. Clients can make use of this to fall back to
-     * a more compatible way of painting a PCL graphic.
-     * @param msg the error message to be displayed
-     */
-    protected void handleUnsupportedFeature(String msg) {
-        if (this.failOnUnsupportedFeature) {
-            throw new UnsupportedOperationException(msg);
-        }
-    }
-    
-    /** @see java.awt.Graphics2D#getDeviceConfiguration() */
-    public GraphicsConfiguration getDeviceConfiguration() {
-        return GraphicsEnvironment.getLocalGraphicsEnvironment().
-                getDefaultScreenDevice().getDefaultConfiguration();
-    }
-
-    /**
-     * Applies a new Stroke object.
-     * @param stroke Stroke object to use
-     * @throws IOException In case of an I/O problem
-     */
-    protected void applyStroke(Stroke stroke) throws IOException {
-        if (stroke instanceof BasicStroke) {
-            BasicStroke bs = (BasicStroke)stroke;
-
-            float[] da = bs.getDashArray();
-            if (da != null) {
-                
-                gen.writeText("UL1,");
-                int len = Math.min(20, da.length);
-                float patternLen = 0.0f;
-                for (int idx = 0; idx < len; idx++) {
-                    patternLen += da[idx];
-                }
-                if (len == 1) {
-                    patternLen *= 2;
-                }
-                for (int idx = 0; idx < len; idx++) {
-                    float perc = da[idx] * 100 / patternLen;
-                    gen.writeText(gen.formatDouble2(perc));
-                    if (idx < da.length - 1) {
-                        gen.writeText(",");
-                    }
-                }
-                if (len == 1) {
-                    gen.writeText("," + gen.formatDouble2(da[0] * 100 / patternLen ));
-                    
-                }
-                gen.writeText(";");
-                /* TODO Dash phase NYI
-                float offset = bs.getDashPhase();
-                gen.writeln(gen.formatDouble4(offset) + " setdash");
-                */
-                Point2D ptLen = new Point2D.Double(patternLen, 0);
-                //interpret as absolute length
-                getTransform().deltaTransform(ptLen, ptLen);
-                double transLen = UnitConv.pt2mm(ptLen.distance(0, 0));
-                gen.writeText("LT1," + gen.formatDouble4(transLen) + ",1;");
-            } else {
-                gen.writeText("LT;");
-            }
-
-            gen.writeText("LA1"); //line cap
-            int ec = bs.getEndCap();
-            switch (ec) {
-            case BasicStroke.CAP_BUTT:
-                gen.writeText(",1");
-                break;
-            case BasicStroke.CAP_ROUND:
-                gen.writeText(",4");
-                break;
-            case BasicStroke.CAP_SQUARE:
-                gen.writeText(",2");
-                break;
-            default: System.err.println("Unsupported line cap: " + ec);
-            }
-
-            gen.writeText(",2"); //line join
-            int lj = bs.getLineJoin();
-            switch (lj) {
-            case BasicStroke.JOIN_MITER:
-                gen.writeText(",1");
-                break;
-            case BasicStroke.JOIN_ROUND:
-                gen.writeText(",4");
-                break;
-            case BasicStroke.JOIN_BEVEL:
-                gen.writeText(",5");
-                break;
-            default: System.err.println("Unsupported line join: " + lj);
-            }
-
-            float ml = bs.getMiterLimit();
-            gen.writeText(",3"  + gen.formatDouble4(ml));
-            
-            float lw = bs.getLineWidth();
-            Point2D ptSrc = new Point2D.Double(lw, 0);
-            //Pen widths are set as absolute metric values (WU0;)
-            Point2D ptDest = getTransform().deltaTransform(ptSrc, null);
-            double transDist = UnitConv.pt2mm(ptDest.distance(0, 0));
-            //System.out.println("--" + ptDest.distance(0, 0) + " " + transDist);
-            gen.writeText(";PW" + gen.formatDouble4(transDist) + ";");
-            
-        } else {
-            handleUnsupportedFeature("Unsupported Stroke: " + stroke.getClass().getName());
-        }
-    }
-
-    /**
-     * Applies a new Paint object.
-     * @param paint Paint object to use
-     * @throws IOException In case of an I/O problem
-     */
-    protected void applyPaint(Paint paint) throws IOException {
-        if (paint instanceof Color) {
-            Color col = (Color)paint;
-            int shade = gen.convertToPCLShade(col);
-            gen.writeText("TR0;FT10," + shade + ";");
-        } else {
-            handleUnsupportedFeature("Unsupported Paint: " + paint.getClass().getName());
-        }
-    }
-
-    private void writeClip(Shape imclip) throws IOException {
-        if (clippingDisabled) {
-            return;
-        }
-        if (imclip == null) {
-            //gen.writeText("IW;");
-        } else {
-            handleUnsupportedFeature("Clipping is not supported. Shape: " + imclip);
-            /* This is an attempt to clip using the "InputWindow" (IW) but this only allows to 
-             * clip a rectangular area. Force falling back to bitmap mode for now.
-            Rectangle2D bounds = imclip.getBounds2D();
-            Point2D p1 = new Point2D.Double(bounds.getX(), bounds.getY());
-            Point2D p2 = new Point2D.Double(
-                    bounds.getX() + bounds.getWidth(), bounds.getY() + bounds.getHeight());
-            getTransform().transform(p1, p1);
-            getTransform().transform(p2, p2);
-            gen.writeText("IW" + gen.formatDouble4(p1.getX())
-                    + "," + gen.formatDouble4(p2.getY())
-                    + "," + gen.formatDouble4(p2.getX())
-                    + "," + gen.formatDouble4(p1.getY()) + ";");
-            */
-        }
-    }
-
-    /** @see java.awt.Graphics2D#draw(java.awt.Shape) */
-    public void draw(Shape s) {
-        try {
-            AffineTransform trans = getTransform();
-    
-            Shape imclip = getClip();
-            writeClip(imclip);
-    
-            if (!Color.black.equals(getColor())) {
-                //TODO PCL 5 doesn't support colored pens, PCL5c has a pen color (PC) command
-                handleUnsupportedFeature("Only black is supported as stroke color: " + getColor());
-            }
-            applyStroke(getStroke());
-    
-            PathIterator iter = s.getPathIterator(trans);
-            processPathIteratorStroke(iter);
-            writeClip(null);
-        } catch (IOException ioe) {
-            handleIOException(ioe);
-        }
-    }
-
-    /** @see java.awt.Graphics2D#fill(java.awt.Shape) */
-    public void fill(Shape s) {
-        try {
-            AffineTransform trans = getTransform();
-            Shape imclip = getClip();
-            writeClip(imclip);
-            
-            applyPaint(getPaint());
-
-            PathIterator iter = s.getPathIterator(trans);
-            processPathIteratorFill(iter);
-            writeClip(null);
-        } catch (IOException ioe) {
-            handleIOException(ioe);
-        }
-    }
-
-    /**
-     * Processes a path iterator generating the nexessary painting operations.
-     * @param iter PathIterator to process
-     * @throws IOException In case of an I/O problem.
-     */
-    public void processPathIteratorStroke(PathIterator iter) throws IOException {
-        gen.writeText("\n");
-        double[] vals = new double[6];
-        boolean penDown = false;
-        double x = 0;
-        double y = 0;
-        StringBuffer sb = new StringBuffer(256);
-        penUp(sb);
-        while (!iter.isDone()) {
-            int type = iter.currentSegment(vals);
-            if (type == PathIterator.SEG_CLOSE) {
-                gen.writeText("PM;");
-                gen.writeText(sb.toString());
-                gen.writeText("PM2;EP;");
-                sb.setLength(0);
-                iter.next();
-                continue;
-            } else if (type == PathIterator.SEG_MOVETO) {
-                gen.writeText(sb.toString());
-                sb.setLength(0);
-                if (penDown) {
-                    penUp(sb);
-                    penDown = false;
-                }
-            } else {
-                if (!penDown) {
-                    penDown(sb);
-                    penDown = true;
-                }
-            }
-            switch (type) {
-            case PathIterator.SEG_CLOSE:
-                break;
-            case PathIterator.SEG_MOVETO:
-                x = vals[0];
-                y = vals[1];
-                plotAbsolute(x, y, sb);
-                gen.writeText(sb.toString());
-                sb.setLength(0);
-                break;
-            case PathIterator.SEG_LINETO:
-                x = vals[0];
-                y = vals[1];
-                plotAbsolute(x, y, sb);
-                break;
-            case PathIterator.SEG_CUBICTO:
-                x = vals[4];
-                y = vals[5];
-                bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
-                break;
-            case PathIterator.SEG_QUADTO:
-                double originX = x;
-                double originY = y;
-                x = vals[2];
-                y = vals[3];
-                quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
-                break;
-            default:
-                break;
-            }
-            iter.next();
-        }
-        sb.append("\n");
-        gen.writeText(sb.toString());
-    }
-    
-    /**
-     * Processes a path iterator generating the nexessary painting operations.
-     * @param iter PathIterator to process
-     * @throws IOException In case of an I/O problem.
-     */
-    public void processPathIteratorFill(PathIterator iter) throws IOException {
-        gen.writeText("\n");
-        double[] vals = new double[6];
-        boolean penDown = false;
-        double x = 0;
-        double y = 0;
-        boolean pendingPM0 = true;
-        StringBuffer sb = new StringBuffer(256);
-        penUp(sb);
-        while (!iter.isDone()) {
-            int type = iter.currentSegment(vals);
-            if (type == PathIterator.SEG_CLOSE) {
-                sb.append("PM1;");
-                iter.next();
-                continue;
-            } else if (type == PathIterator.SEG_MOVETO) {
-                if (penDown) {
-                    penUp(sb);
-                    penDown = false;
-                }
-            } else {
-                if (!penDown) {
-                    penDown(sb);
-                    penDown = true;
-                }
-            }
-            switch (type) {
-            case PathIterator.SEG_MOVETO:
-                x = vals[0];
-                y = vals[1];
-                plotAbsolute(x, y, sb);
-                break;
-            case PathIterator.SEG_LINETO:
-                x = vals[0];
-                y = vals[1];
-                plotAbsolute(x, y, sb);
-                break;
-            case PathIterator.SEG_CUBICTO:
-                x = vals[4];
-                y = vals[5];
-                bezierAbsolute(vals[0], vals[1], vals[2], vals[3], x, y, sb);
-                break;
-            case PathIterator.SEG_QUADTO:
-                double originX = x;
-                double originY = y;
-                x = vals[2];
-                y = vals[3];
-                quadraticBezierAbsolute(originX, originY, vals[0], vals[1], x, y, sb);
-                break;
-            default:
-                throw new IllegalStateException("Must not get here");
-            }
-            if (pendingPM0) {
-                pendingPM0 = false;
-                sb.append("PM;");
-            }
-            iter.next();
-        }
-        sb.append("PM2;");
-        fillPolygon(iter.getWindingRule(), sb);
-        sb.append("\n");
-        gen.writeText(sb.toString());
-    }
-    
-    private void fillPolygon(int windingRule, StringBuffer sb) {
-        int fillMethod = (windingRule == PathIterator.WIND_EVEN_ODD ? 0 : 1);
-        sb.append("FP").append(fillMethod).append(";");
-    }
-
-    private void plotAbsolute(double x, double y, StringBuffer sb) {
-        sb.append("PA").append(gen.formatDouble4(x));
-        sb.append(",").append(gen.formatDouble4(y)).append(";");
-    }
-
-    private void bezierAbsolute(double x1, double y1, double x2, double y2, double x3, double y3,
-            StringBuffer sb) {
-        sb.append("BZ").append(gen.formatDouble4(x1));
-        sb.append(",").append(gen.formatDouble4(y1));
-        sb.append(",").append(gen.formatDouble4(x2));
-        sb.append(",").append(gen.formatDouble4(y2));
-        sb.append(",").append(gen.formatDouble4(x3));
-        sb.append(",").append(gen.formatDouble4(y3)).append(";");
-    }
-
-    private void quadraticBezierAbsolute(double originX, double originY, 
-            double x1, double y1, double x2, double y2, StringBuffer sb) {
-        //Quadratic Bezier curve can be mapped to a normal bezier curve
-        //See http://pfaedit.sourceforge.net/bezier.html
-        double nx1 = originX + (2.0 / 3.0) * (x1 - originX);
-        double ny1 = originY + (2.0 / 3.0) * (y1 - originY);
-        
-        double nx2 = nx1 + (1.0 / 3.0) * (x2 - originX);
-        double ny2 = ny1 + (1.0 / 3.0) * (y2 - originY);
-        
-        bezierAbsolute(nx1, ny1, nx2, ny2, x2, y2, sb);
-    }
-
-    private void penDown(StringBuffer sb) {
-        sb.append("PD;");
-    }
-
-    private void penUp(StringBuffer sb) {
-        sb.append("PU;");
-    }
-
-    /** @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */
-    public void drawString(String s, float x, float y) {
-        java.awt.Font awtFont = getFont();
-        FontRenderContext frc = getFontRenderContext();
-        GlyphVector gv = awtFont.createGlyphVector(frc, s);
-        Shape glyphOutline = gv.getOutline(x, y);
-        fill(glyphOutline);
-    }
-
-    /** @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */
-    public void drawString(AttributedCharacterIterator iterator, float x,
-            float y) {
-        // TODO Auto-generated method stub
-        handleUnsupportedFeature("drawString NYI");
-    }
-
-    /**
-     * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage, 
-     *          java.awt.geom.AffineTransform)
-     */
-    public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
-        handleUnsupportedFeature("Bitmap images are not supported");
-    }
-
-    /**
-     * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage, 
-     *          java.awt.geom.AffineTransform)
-     */
-    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
-        handleUnsupportedFeature("Bitmap images are not supported");
-    }
-
-    /**
-     * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, 
-     *          java.awt.image.ImageObserver)
-     */
-    public boolean drawImage(Image img, int x, int y, int width, int height,
-            ImageObserver observer) {
-        handleUnsupportedFeature("Bitmap images are not supported");
-        return false;
-    }
-
-    /**
-     * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver)
-     */
-    public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
-        handleUnsupportedFeature("Bitmap images are not supported");
-        return false;
-        /*
-         * First attempt disabled.
-         * Reasons: Lack of transparency control, positioning and rotation issues
-        final int width = img.getWidth(observer);
-        final int height = img.getHeight(observer);
-        if (width == -1 || height == -1) {
-            return false;
-        }
-
-        Dimension size = new Dimension(width, height);
-        BufferedImage buf = buildBufferedImage(size);
-
-        java.awt.Graphics2D g = buf.createGraphics();
-        try {
-            g.setComposite(AlphaComposite.SrcOver);
-            g.setBackground(new Color(255, 255, 255));
-            g.setPaint(new Color(255, 255, 255));
-            g.fillRect(0, 0, width, height);
-            g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight()));
-
-            if (!g.drawImage(img, 0, 0, observer)) {
-                return false;
-            }
-        } finally {
-            g.dispose();
-        }
-
-        try {
-            AffineTransform at = getTransform();
-            gen.enterPCLMode(false);
-            //Shape imclip = getClip(); Clipping is not available in PCL
-            Point2D p1 = new Point2D.Double(x, y);
-            at.transform(p1, p1);
-            pclContext.getTransform().transform(p1, p1);
-            gen.setCursorPos(p1.getX(), p1.getY());
-            gen.paintBitmap(buf, 72); 
-            gen.enterHPGL2Mode(false);
-        } catch (IOException ioe) {
-            handleIOException(ioe);
-        }
-
-        return true;*/
-    }
-
-    /** @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */
-    public void copyArea(int x, int y, int width, int height, int dx, int dy) {
-        // TODO Auto-generated method stub
-        handleUnsupportedFeature("copyArea NYI");
-    }
-
-    /** @see java.awt.Graphics#setXORMode(java.awt.Color) */
-    public void setXORMode(Color c1) {
-        // TODO Auto-generated method stub
-        handleUnsupportedFeature("setXORMode NYI");
-    }
-
-    /**
-     * Used to create proper font metrics
-     */
-    private Graphics2D fmg;
-
-    {
-        BufferedImage bi = new BufferedImage(1, 1,
-                                             BufferedImage.TYPE_INT_ARGB);
-
-        fmg = bi.createGraphics();
-    }
-
-    /**
-     * Creates a buffered image.
-     * @param size dimensions of the image to be created
-     * @return the buffered image
-     */
-    protected BufferedImage buildBufferedImage(Dimension size) {
-        return new BufferedImage(size.width, size.height,
-                                 BufferedImage.TYPE_BYTE_GRAY);
-    }
-    
-    /** @see java.awt.Graphics#getFontMetrics(java.awt.Font) */
-    public java.awt.FontMetrics getFontMetrics(java.awt.Font f) {
-        return fmg.getFontMetrics(f);
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java b/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java
deleted file mode 100644 (file)
index d2e91f8..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-package org.apache.fop.render.pcl;
-
-import java.awt.Dimension;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-
-import org.apache.commons.io.output.ByteArrayOutputStream;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.fop.render.AbstractGraphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.util.UnitConv;
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-/**
- * Graphics2DAdapter implementation for PCL and HP GL/2.
- */
-public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter {
-
-    /** logging instance */
-    private static Log log = LogFactory.getLog(PCLGraphics2DAdapter.class);
-
-    /**
-     * Main constructor
-     */
-    public PCLGraphics2DAdapter() {
-    }
-    
-    /** @see org.apache.fop.render.Graphics2DAdapter */
-    public void paintImage(Graphics2DImagePainter painter, 
-            RendererContext context,
-            int x, int y, int width, int height) throws IOException {
-        PCLRendererContext pclContext = PCLRendererContext.wrapRendererContext(context);
-        PCLRenderer pcl = (PCLRenderer)context.getRenderer();
-        PCLGenerator gen = pcl.gen;
-        
-        // get the 'width' and 'height' attributes of the image/document
-        Dimension dim = painter.getImageSize();
-        float imw = (float)dim.getWidth();
-        float imh = (float)dim.getHeight();
-
-        boolean painted = false;
-        boolean paintAsBitmap = pclContext.paintAsBitmap();
-        if (!paintAsBitmap) {
-            ByteArrayOutputStream baout = new ByteArrayOutputStream();
-            PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution());
-            try {
-                GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone();
-
-                AffineTransform prepareHPGL2 = new AffineTransform();
-                prepareHPGL2.scale(0.001, 0.001);
-                ctx.setTransform(prepareHPGL2);
-
-                PCLGraphics2D graphics = new PCLGraphics2D(tempGen);
-                graphics.setGraphicContext(ctx);
-                graphics.setClippingDisabled(pclContext.isClippingDisabled());
-                Rectangle2D area = new Rectangle2D.Double(0.0, 0.0, imw, imh);
-                painter.paint(graphics, area);
-                
-                //If we arrive here, the graphic is natively paintable, so write the graphic
-                pcl.saveGraphicsState();
-                pcl.setCursorPos(x, y);
-                gen.writeCommand("*c" + gen.formatDouble4(width / 100f) + "x" 
-                        + gen.formatDouble4(height / 100f) + "Y");
-                gen.writeCommand("*c0T");
-                gen.enterHPGL2Mode(false);
-                gen.writeText("\nIN;");
-                gen.writeText("SP1;");
-                //One Plotter unit is 0.025mm!
-                double scale = imw / UnitConv.mm2pt(imw * 0.025);
-                gen.writeText("SC0," + gen.formatDouble4(scale) 
-                        + ",0,-" + gen.formatDouble4(scale) + ",2;");
-                gen.writeText("IR0,100,0,100;");
-                gen.writeText("PU;PA0,0;\n");
-                baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream
-                gen.writeText("\n");
-
-                gen.enterPCLMode(false);
-                pcl.restoreGraphicsState();
-                painted = true;
-            } catch (UnsupportedOperationException uoe) {
-                log.debug(
-                    "Cannot paint graphic natively. Falling back to bitmap painting. Reason: " 
-                        + uoe.getMessage());
-            }
-        }
-        
-        if (!painted) {
-            //Fallback solution: Paint to a BufferedImage
-            int resolution = (int)Math.round(context.getUserAgent().getTargetResolution());
-            BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true, false);
-
-            pcl.setCursorPos(x, y);
-            gen.paintBitmap(bi, new Dimension(width, height), pclContext.isSourceTransparency());
-        }
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLPageDefinition.java b/src/sandbox/org/apache/fop/render/pcl/PCLPageDefinition.java
deleted file mode 100644 (file)
index 43978e9..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import java.awt.Dimension;
-import java.awt.Rectangle;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.fop.util.UnitConv;
-
-/**
- * This class represents a page format with PCL-specific properties.
- */
-public class PCLPageDefinition {
-
-    private static List pageDefinitions;
-    private static PCLPageDefinition defaultPageDefinition;
-    
-    private String name;
-    private int selector;
-    private Dimension physicalPageSize;
-    private Rectangle logicalPageRect;
-    private boolean landscape;
-    
-    static {
-        createPageDefinitions();
-    }
-    
-    /**
-     * Main constructor
-     * @param name the name of the page definition
-     * @param selector the selector used by the <ESC>&l#A command (page size)
-     * @param physicalPageSize the physical page size
-     * @param logicalPageRect the rectangle defining the logical page
-     * @param landscape true if it is a landscape format
-     */
-    public PCLPageDefinition(String name, int selector, Dimension physicalPageSize, 
-            Rectangle logicalPageRect, boolean landscape) {
-        this.name = name;
-        this.selector = selector;
-        this.physicalPageSize = physicalPageSize;
-        this.logicalPageRect = logicalPageRect;
-        this.landscape = landscape;
-    }
-    
-    /** @return the name of the page definition */
-    public String getName() {
-        return this.name;
-    }
-    
-    /** @return the selector used by the <ESC>&l#A command (page size) */
-    public int getSelector() {
-        return this.selector;
-    }
-    
-    /** @return true if it is a landscape format */
-    public boolean isLandscapeFormat() {
-        return this.landscape;
-    }
-
-    /** @return the physical page size */
-    public Dimension getPhysicalPageSize() {
-        return this.physicalPageSize;
-    }
-    
-    /** @return the rectangle defining the logical page */
-    public Rectangle getLogicalPageRect() {
-        return this.logicalPageRect;
-    }
-    
-    private boolean matches(long width, long height, int errorMargin) {
-        return (Math.abs(this.physicalPageSize.width - width) < errorMargin) 
-            && (Math.abs(this.physicalPageSize.height - height) < errorMargin);
-    }
-    
-    /** @see java.lang.Object#toString() */
-    public String toString() {
-        return getName();
-    }
-
-    /**
-     * Tries to determine a matching page definition.
-     * @param width the physical page width (in mpt)
-     * @param height the physical page height (in mpt)
-     * @param errorMargin the error margin for detecting the right page definition
-     * @return the page definition or null if no match was found
-     */
-    public static PCLPageDefinition getPageDefinition(long width, long height, int errorMargin) {
-        Iterator iter = pageDefinitions.iterator();
-        while (iter.hasNext()) {
-            PCLPageDefinition def = (PCLPageDefinition)iter.next();
-            if (def.matches(width, height, errorMargin)) {
-                return def;
-            }
-        }
-        return null;
-    }
-    
-    /** @return the default page definition (letter) */
-    public static PCLPageDefinition getDefaultPageDefinition() {
-        return defaultPageDefinition;
-    }
-    
-    /**
-     * Converts an offset values for logical pages to millipoints. The values are given as pixels
-     * in a 300dpi environment.
-     * @param offset the offset as given in the PCL 5 specification (under "Printable Area")
-     * @return the converted value in millipoints
-     */
-    private static int convert300dpiDotsToMpt(int offset) {
-        return (int)Math.round(((double)offset) * 72000 / 300);
-    }
-    
-    private static Dimension createPhysicalPageSizeInch(float width, float height) {
-        return new Dimension(
-                (int)Math.round(UnitConv.in2mpt(width)), 
-                (int)Math.round(UnitConv.in2mpt(height)));
-    }
-    
-    private static Dimension createPhysicalPageSizeMm(float width, float height) {
-        return new Dimension(
-                (int)Math.round(UnitConv.mm2mpt(width)), 
-                (int)Math.round(UnitConv.mm2mpt(height)));
-    }
-    
-    private static Rectangle createLogicalPageRect(int x, int y, int width, int height) {
-        return new Rectangle(convert300dpiDotsToMpt(x), convert300dpiDotsToMpt(y), 
-                convert300dpiDotsToMpt(width), convert300dpiDotsToMpt(height));
-    }
-    
-    private static void createPageDefinitions() {
-        pageDefinitions = new java.util.ArrayList();
-        pageDefinitions.add(new PCLPageDefinition("Letter", 2,
-                createPhysicalPageSizeInch(8.5f, 11),
-                createLogicalPageRect(75, 0, 2400, 3300), false));
-        defaultPageDefinition = new PCLPageDefinition("Legal", 3, 
-                createPhysicalPageSizeInch(8.5f, 14),
-                createLogicalPageRect(75, 0, 2400, 4200), false);
-        pageDefinitions.add(defaultPageDefinition);
-        pageDefinitions.add(new PCLPageDefinition("Executive", 1, 
-                createPhysicalPageSizeInch(7.25f, 10.5f),
-                createLogicalPageRect(75, 0, 2025, 3150), false));
-        pageDefinitions.add(new PCLPageDefinition("Ledger", 6,
-                createPhysicalPageSizeInch(11, 17),
-                createLogicalPageRect(75, 0, 3150, 5100), false));
-        pageDefinitions.add(new PCLPageDefinition("A4", 26,
-                createPhysicalPageSizeMm(210, 297),
-                createLogicalPageRect(71, 0, 2338, 3507), false));
-        pageDefinitions.add(new PCLPageDefinition("A3", 27, 
-                createPhysicalPageSizeMm(297, 420),
-                createLogicalPageRect(71, 0, 3365, 4960), false));
-
-        //TODO Add envelope definitions
-        
-        pageDefinitions.add(new PCLPageDefinition("LetterL", 2,
-                createPhysicalPageSizeInch(11, 8.5f),
-                createLogicalPageRect(60, 0, 3180, 2550), true));
-        pageDefinitions.add(new PCLPageDefinition("LegalL", 3,
-                createPhysicalPageSizeInch(14, 8.5f),
-                createLogicalPageRect(60, 0, 4080, 2550), true));
-        pageDefinitions.add(new PCLPageDefinition("ExecutiveL", 1, 
-                createPhysicalPageSizeInch(10.5f, 7.25f),
-                createLogicalPageRect(60, 0, 3030, 2175), true));
-        pageDefinitions.add(new PCLPageDefinition("LedgerL", 6,
-                createPhysicalPageSizeInch(17, 11),
-                createLogicalPageRect(60, 0, 4980, 3300), true));
-        pageDefinitions.add(new PCLPageDefinition("A4L", 26,
-                createPhysicalPageSizeMm(297, 210),
-                createLogicalPageRect(59, 0, 3389, 2480), true));
-        pageDefinitions.add(new PCLPageDefinition("A3L", 27,
-                createPhysicalPageSizeMm(420, 297),
-                createLogicalPageRect(59, 0, 4842, 3507), true));
-    }
-    
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java b/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java
deleted file mode 100644 (file)
index 05952d9..0000000
+++ /dev/null
@@ -1,1448 +0,0 @@
-/*
- * Copyright 1999-2006 The Apache Software Foundation.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-package org.apache.fop.render.pcl;
-
-//Java
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.color.ColorSpace;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.ComponentColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferByte;
-import java.awt.image.PixelInterleavedSampleModel;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.awt.image.SampleModel;
-import java.awt.image.WritableRaster;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-
-import org.w3c.dom.Document;
-
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-// FOP
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.fop.apps.FOPException;
-import org.apache.fop.apps.MimeConstants;
-import org.apache.fop.area.Area;
-import org.apache.fop.area.Block;
-import org.apache.fop.area.BlockViewport;
-import org.apache.fop.area.CTM;
-import org.apache.fop.area.PageViewport;
-import org.apache.fop.area.Trait;
-import org.apache.fop.area.inline.AbstractTextArea;
-import org.apache.fop.area.inline.ForeignObject;
-import org.apache.fop.area.inline.Image;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.SpaceArea;
-import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.Viewport;
-import org.apache.fop.area.inline.WordArea;
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.image.EPSImage;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.ImageFactory;
-import org.apache.fop.image.XMLImage;
-import org.apache.fop.render.Graphics2DAdapter;
-import org.apache.fop.render.Graphics2DImagePainter;
-import org.apache.fop.render.PrintRenderer;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.render.RendererContextConstants;
-import org.apache.fop.render.java2d.FontMetricsMapper;
-import org.apache.fop.render.java2d.FontSetup;
-import org.apache.fop.render.java2d.Java2DRenderer;
-import org.apache.fop.render.pcl.extensions.PCLElementMapping;
-import org.apache.fop.traits.BorderProps;
-import org.apache.fop.util.QName;
-import org.apache.fop.util.UnitConv;
-
-/**
- * Renderer for the PCL 5 printer language. It also uses HP GL/2 for certain graphic elements.
- */
-public class PCLRenderer extends PrintRenderer {
-
-    /** logging instance */
-    private static Log log = LogFactory.getLog(PCLRenderer.class);
-
-    /** The MIME type for PCL */
-    public static final String MIME_TYPE = MimeConstants.MIME_PCL_ALT;
-
-    private static final QName CONV_MODE 
-            = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
-    private static final QName SRC_TRANSPARENCY 
-            = new QName(ExtensionElementMapping.URI, null, "source-transparency");
-    
-    /** The OutputStream to write the PCL stream to */
-    protected OutputStream out;
-    
-    /** The PCL generator */
-    protected PCLGenerator gen;
-    private boolean ioTrouble = false;
-
-    private Stack graphicContextStack = new Stack();
-    private GraphicContext graphicContext = new GraphicContext();
-
-    private PCLPageDefinition currentPageDefinition;
-    private int currentPrintDirection = 0;
-    private GeneralPath currentPath = null;
-    private java.awt.Color currentFillColor = null;
-    
-    /**
-     * Controls whether appearance is more important than speed. False can cause some FO feature
-     * to be ignored (like the advanced borders). 
-     */
-    private boolean qualityBeforeSpeed = false;
-    
-    /**
-     * Controls whether all text should be painted as text. This is a fallback setting in case
-     * the mixture of native and bitmapped text does not provide the necessary quality.
-     */
-    private boolean allTextAsBitmaps = false;
-    
-    /**
-     * Create the PCL renderer
-     */
-    public PCLRenderer() {
-    }
-
-    /**
-     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
-     */
-    public void configure(Configuration cfg) throws ConfigurationException {
-        super.configure(cfg);
-        String rendering = cfg.getChild("rendering").getValue(null);
-        if ("quality".equalsIgnoreCase(rendering)) {
-            this.qualityBeforeSpeed = true;
-        } else if ("speed".equalsIgnoreCase(rendering)) {
-            this.qualityBeforeSpeed = false;
-        } else if (rendering != null) {
-            throw new ConfigurationException(
-                    "Valid values for 'rendering' are 'quality' and 'speed'. Value found: " 
-                        + rendering);
-        }
-        String textRendering = cfg.getChild("text-rendering").getValue(null);
-        if ("bitmap".equalsIgnoreCase(textRendering)) {
-            this.allTextAsBitmaps = true;
-        } else if ("auto".equalsIgnoreCase(textRendering)) {
-            this.allTextAsBitmaps = false;
-        } else if (textRendering != null) {
-            throw new ConfigurationException(
-                    "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " 
-                        + textRendering);
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.Renderer#setupFontInfo(org.apache.fop.fonts.FontInfo)
-     */
-    public void setupFontInfo(FontInfo inFontInfo) {
-        //Don't call super.setupFontInfo() here!
-        //The PCLRenderer uses the Java2D FontSetup which needs a special font setup
-        //create a temp Image to test font metrics on
-        fontInfo = inFontInfo;
-        BufferedImage fontImage = new BufferedImage(100, 100,
-                BufferedImage.TYPE_INT_RGB);
-        Graphics2D g = fontImage.createGraphics();
-        //The next line is important to get accurate font metrics!
-        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 
-                RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-        FontSetup.setup(fontInfo, g);
-    }
-
-    /**
-     * Central exception handler for I/O exceptions.
-     * @param ioe IOException to handle
-     */
-    protected void handleIOTrouble(IOException ioe) {
-        if (!ioTrouble) {
-            log.error("Error while writing to target file", ioe);
-            ioTrouble = true;
-        }
-    }
-
-    /** @see org.apache.fop.render.Renderer#getGraphics2DAdapter() */
-    public Graphics2DAdapter getGraphics2DAdapter() {
-        return new PCLGraphics2DAdapter();
-    }
-
-    /** @return the GraphicContext used to track coordinate system transformations */
-    public GraphicContext getGraphicContext() {
-        return this.graphicContext;
-    }
-    
-    /** @return the target resolution */
-    protected int getResolution() {
-        int resolution = (int)Math.round(userAgent.getTargetResolution());
-        if (resolution <= 300) {
-            return 300;
-        } else {
-            return 600;
-        }
-    }
-    
-    /**
-     * Sets the current font (NOTE: Hard-coded font mappings ATM!)
-     * @param name the font name (internal F* names for now)
-     * @param size the font size
-     * @param text the text to be rendered (used to determine if there are non-printable chars)
-     * @return true if the font can be mapped to PCL
-     * @throws IOException if an I/O problem occurs
-     */
-    public boolean setFont(String name, float size, String text) throws IOException {
-        byte[] encoded = text.getBytes("ISO-8859-1");
-        for (int i = 0, c = encoded.length; i < c; i++) {
-            if (encoded[i] == 0x3F && text.charAt(i) != '?') {
-                return false;
-            }
-        }
-        int fontcode = 0;
-        if (name.length() > 1 && name.charAt(0) == 'F') {
-            try {
-                fontcode = Integer.parseInt(name.substring(1));
-            } catch (Exception e) {
-                log.error(e);
-            }
-        }
-        //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
-        String formattedSize = gen.formatDouble2(size / 1000);
-        switch (fontcode) {
-        case 1:     // F1 = Helvetica
-            // gen.writeCommand("(8U");
-            // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
-            // Arial is more common among PCL5 printers than Helvetica - so use Arial
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
-            break;
-        case 2:     // F2 = Helvetica Oblique
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
-            break;
-        case 3:     // F3 = Helvetica Bold
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
-            break;
-        case 4:     // F4 = Helvetica Bold Oblique
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
-            break;
-        case 5:     // F5 = Times Roman
-            // gen.writeCommand("(8U");
-            // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
-            // Times New is more common among PCL5 printers than Times - so use Times New
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
-            break;
-        case 6:     // F6 = Times Italic
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
-            break;
-        case 7:     // F7 = Times Bold
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
-            break;
-        case 8:     // F8 = Times Bold Italic
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
-            break;
-        case 9:     // F9 = Courier
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
-                    + "h0s0b4099T");
-            break;
-        case 10:    // F10 = Courier Oblique
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
-                    + "h1s0b4099T");
-            break;
-        case 11:    // F11 = Courier Bold
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
-                    + "h0s3b4099T");
-            break;
-        case 12:    // F12 = Courier Bold Oblique
-
-            gen.writeCommand("(0N");
-            gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f)) 
-                    + "h1s3b4099T");
-            break;
-        case 13:    // F13 = Symbol
-
-            return false;
-            //gen.writeCommand("(19M");
-            //gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
-            // ECMA Latin 1 Symbol Set in Times Roman???
-            // gen.writeCommand("(9U");
-            // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
-            //break;
-        case 14:    // F14 = Zapf Dingbats
-
-            return false;
-            //gen.writeCommand("(14L");
-            //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
-            //break;
-        default:
-            //gen.writeCommand("(0N");
-            //gen.writeCommand("(s" + formattedSize + "V");
-            return false;
-        }
-        return true;
-    }
-
-    /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */
-    public void startRenderer(OutputStream outputStream) throws IOException {
-        log.debug("Rendering areas to PCL...");
-        this.out = outputStream;
-        this.gen = new PCLGenerator(out, getResolution());
-
-        gen.universalEndOfLanguage();
-        gen.writeText("@PJL COMMENT Produced by " + userAgent.getProducer() + "\n");
-        if (userAgent.getTitle() != null) {
-            gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n");
-        }
-        gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n");
-        gen.writeText("@PJL ENTER LANGUAGE = PCL\n");
-        gen.resetPrinter();
-        gen.setUnitOfMeasure(getResolution());
-        gen.setRasterGraphicsResolution(getResolution());
-    }
-
-    /** @see org.apache.fop.render.Renderer#stopRenderer() */
-    public void stopRenderer() throws IOException {
-        gen.separateJobs();
-        gen.resetPrinter();
-        gen.universalEndOfLanguage();
-    }
-
-    /** @see org.apache.fop.render.AbstractRenderer */
-    public String getMimeType() {
-        return MIME_TYPE;
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderPage(org.apache.fop.area.PageViewport)
-     */
-    public void renderPage(PageViewport page) throws IOException, FOPException {
-        saveGraphicsState();
-        
-        //Paper source
-        String paperSource = page.getForeignAttributeValue(
-                new QName(PCLElementMapping.NAMESPACE, null, "paper-source"));
-        if (paperSource != null) {
-            gen.selectPaperSource(Integer.parseInt(paperSource));
-        }
-        
-        //Page size
-        final long pagewidth = Math.round(page.getViewArea().getWidth());
-        final long pageheight = Math.round(page.getViewArea().getHeight());
-        selectPageFormat(pagewidth, pageheight);
-        
-        super.renderPage(page);
-        
-        //Eject page
-        gen.formFeed();
-        restoreGraphicsState();
-    }
-
-    private void selectPageFormat(long pagewidth, long pageheight) throws IOException {
-        this.currentPageDefinition = PCLPageDefinition.getPageDefinition(
-                pagewidth, pageheight, 1000);
-        
-        if (this.currentPageDefinition == null) {
-            this.currentPageDefinition = PCLPageDefinition.getDefaultPageDefinition();
-            log.warn("Paper type could not be determined. Falling back to: " 
-                    + this.currentPageDefinition.getName());
-        }
-        log.debug("page size: " + currentPageDefinition.getPhysicalPageSize());
-        log.debug("logical page: " + currentPageDefinition.getLogicalPageRect());
-        if (this.currentPageDefinition.isLandscapeFormat()) {
-            gen.writeCommand("&l1O"); //Orientation
-        } else {
-            gen.writeCommand("&l0O"); //Orientation
-        }
-        gen.selectPageSize(this.currentPageDefinition.getSelector());
-        
-        gen.clearHorizontalMargins();
-        gen.setTopMargin(0);
-    }
-
-    /** Saves the current graphics state on the stack. */
-    protected void saveGraphicsState() {
-        graphicContextStack.push(graphicContext);
-        graphicContext = (GraphicContext)graphicContext.clone();
-    }
-
-    /** Restores the last graphics state from the stack. */
-    protected void restoreGraphicsState() {
-        graphicContext = (GraphicContext)graphicContextStack.pop();
-    }
-    
-    /**
-     * Clip an area. write a clipping operation given coordinates in the current
-     * transform. Coordinates are in points.
-     *
-     * @param x the x coordinate
-     * @param y the y coordinate
-     * @param width the width of the area
-     * @param height the height of the area
-     */
-    protected void clipRect(float x, float y, float width, float height) {
-        //PCL cannot clip (only HP GL/2 can)
-    }
-
-    private Point2D transformedPoint(float x, float y) {
-        return transformedPoint(Math.round(x), Math.round(y));
-    }
-    
-    private Point2D transformedPoint(int x, int y) {
-        AffineTransform at = graphicContext.getTransform();
-        if (log.isTraceEnabled()) {
-            log.trace("Current transform: " + at);
-        }
-        Point2D.Float orgPoint = new Point2D.Float(x, y);
-        Point2D.Float transPoint = new Point2D.Float();
-        at.transform(orgPoint, transPoint);
-        //At this point we have the absolute position in FOP's coordinate system
-        
-        //Now get PCL coordinates taking the current print direction and the logical page
-        //into account.
-        Dimension pageSize = currentPageDefinition.getPhysicalPageSize();
-        Rectangle logRect = currentPageDefinition.getLogicalPageRect();
-        switch (currentPrintDirection) {
-        case 0:
-            transPoint.x -= logRect.x;
-            transPoint.y -= logRect.y;
-            break;
-        case 90:
-            float ty = transPoint.x;
-            transPoint.x = pageSize.height - transPoint.y;
-            transPoint.y = ty;
-            transPoint.x -= logRect.y;
-            transPoint.y -= logRect.x;
-            break;
-        case 180:
-            transPoint.x = pageSize.width - transPoint.x;
-            transPoint.y = pageSize.height - transPoint.y;
-            transPoint.x -= pageSize.width - logRect.x - logRect.width;
-            transPoint.y -= pageSize.height - logRect.y - logRect.height;
-            //The next line is odd and is probably necessary due to the default value of the
-            //Text Length command: "1/2 inch less than maximum text length"
-            //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
-            transPoint.y -= UnitConv.in2mpt(0.5);
-            break;
-        case 270:
-            float tx = transPoint.y;
-            transPoint.y = pageSize.width - transPoint.x;
-            transPoint.x = tx;
-            transPoint.x -= pageSize.height - logRect.y - logRect.height;
-            transPoint.y -= pageSize.width - logRect.x - logRect.width;
-            break;
-        default:
-            throw new IllegalStateException("Illegal print direction: " + currentPrintDirection);
-        }
-        return transPoint;
-    }
-    
-    private void changePrintDirection() {
-        AffineTransform at = graphicContext.getTransform();
-        int newDir;
-        try {
-            if (at.getScaleX() == 0 && at.getScaleY() == 0 
-                    && at.getShearX() == 1 && at.getShearY() == -1) {
-                newDir = 90;
-            } else if (at.getScaleX() == -1 && at.getScaleY() == -1 
-                    && at.getShearX() == 0 && at.getShearY() == 0) {
-                newDir = 180;
-            } else if (at.getScaleX() == 0 && at.getScaleY() == 0 
-                    && at.getShearX() == -1 && at.getShearY() == 1) {
-                newDir = 270;
-            } else {
-                newDir = 0;
-            }
-            if (newDir != this.currentPrintDirection) {
-                this.currentPrintDirection = newDir;
-                gen.changePrintDirection(this.currentPrintDirection);
-            }
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM, Rectangle2D)
-     */
-    protected void startVParea(CTM ctm, Rectangle2D clippingRect) {
-        saveGraphicsState();
-        AffineTransform at = new AffineTransform(ctm.toArray());
-        graphicContext.transform(at);
-        changePrintDirection();
-        if (log.isDebugEnabled()) {
-            log.debug("startVPArea: " + at + " --> " + graphicContext.getTransform());
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#endVParea()
-     */
-    protected void endVParea() {
-        restoreGraphicsState();
-        changePrintDirection();
-        if (log.isDebugEnabled()) {
-            log.debug("endVPArea() --> " + graphicContext.getTransform());
-        }
-    }
-
-    /**
-     * Handle block traits.
-     * The block could be any sort of block with any positioning
-     * so this should render the traits such as border and background
-     * in its position.
-     *
-     * @param block the block to render the traits
-     */
-    protected void handleBlockTraits(Block block) {
-        int borderPaddingStart = block.getBorderAndPaddingWidthStart();
-        int borderPaddingBefore = block.getBorderAndPaddingWidthBefore();
-        
-        float startx = currentIPPosition / 1000f;
-        float starty = currentBPPosition / 1000f;
-        float width = block.getIPD() / 1000f;
-        float height = block.getBPD() / 1000f;
-
-        startx += block.getStartIndent() / 1000f;
-        startx -= block.getBorderAndPaddingWidthStart() / 1000f;
-
-        width += borderPaddingStart / 1000f;
-        width += block.getBorderAndPaddingWidthEnd() / 1000f;
-        height += borderPaddingBefore / 1000f;
-        height += block.getBorderAndPaddingWidthAfter() / 1000f;
-
-        drawBackAndBorders(block, startx, starty, width, height);
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
-     */
-    protected void renderText(final TextArea text) {
-        renderInlineAreaBackAndBorders(text);
-        
-        String fontname = getInternalFontNameForArea(text);
-        int fontsize = text.getTraitAsInteger(Trait.FONT_SIZE);
-
-        //Determine position
-        int saveIP = currentIPPosition;
-        int rx = currentIPPosition + text.getBorderAndPaddingWidthStart();
-        int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset();
-
-        try {
-            final Color col = (Color)text.getTrait(Trait.COLOR);
-            boolean pclFont = allTextAsBitmaps 
-                    ? false
-                    : setFont(fontname, fontsize, text.getText()); 
-            if (pclFont) {
-                //this.currentFill = col;
-                if (col != null) {
-                    //useColor(ct);
-                    gen.setTransparencyMode(true, false);
-                    gen.selectCurrentPattern(gen.convertToPCLShade(col), 2);
-                }
-                
-                saveGraphicsState();
-                graphicContext.translate(rx, bl);
-                setCursorPos(0, 0);
-                gen.setTransparencyMode(true, true);
-                
-                super.renderText(text); //Updates IPD and renders words and spaces
-                restoreGraphicsState();
-            } else {
-                //Use Java2D to paint different fonts via bitmap
-                final Font font = getFontFromArea(text);
-                final int baseline = text.getBaselineOffset();
-                
-                //for cursive fonts, so the text isn't clipped
-                int extraWidth = font.getFontSize() / 3;
-                final FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
-                        font.getFontName());
-                int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
-                final int additionalBPD = maxAscent - baseline;
-                
-                Graphics2DAdapter g2a = getGraphics2DAdapter();
-                final Rectangle paintRect = new Rectangle(
-                        rx, currentBPPosition + text.getOffset() - additionalBPD,
-                        text.getIPD() + extraWidth, text.getBPD() + additionalBPD);
-                RendererContext rc = createRendererContext(paintRect.x, paintRect.y, 
-                        paintRect.width, paintRect.height, null);
-                Map atts = new java.util.HashMap();
-                atts.put(CONV_MODE, "bitmap");
-                atts.put(SRC_TRANSPARENCY, "true");
-                rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
-                
-                Graphics2DImagePainter painter = new Graphics2DImagePainter() {
-
-                    public void paint(Graphics2D g2d, Rectangle2D area) {
-                        g2d.setFont(mapper.getFont(font.getFontSize()));
-                        g2d.translate(0, baseline + additionalBPD);
-                        g2d.scale(1000, 1000);
-                        g2d.setColor(col);
-                        Java2DRenderer.renderText(text, g2d, font);
-                    }
-                    
-                    public Dimension getImageSize() {
-                        return paintRect.getSize();
-                    }
-                    
-                };
-                g2a.paintImage(painter, rc, 
-                        paintRect.x, paintRect.y, paintRect.width, paintRect.height);
-                currentIPPosition = saveIP + text.getAllocIPD();
-            }
-        
-            //renderTextDecoration(tf, fontsize, area, bl, rx);
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-    }
-
-    /**
-     * Sets the current cursor position. The coordinates are transformed to the absolute position
-     * on the logical PCL page and then passed on to the PCLGenerator.
-     * @param x the x coordinate (in millipoints)
-     * @param y the y coordinate (in millipoints)
-     */
-    void setCursorPos(float x, float y) {
-        try {
-            Point2D transPoint = transformedPoint(x, y);
-            gen.setCursorPos(transPoint.getX(), transPoint.getY());
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractPathOrientedRenderer#clip()
-     */
-    protected void clip() {
-        if (currentPath == null) {
-            throw new IllegalStateException("No current path available!");
-        }
-        //TODO Find a good way to do clipping. PCL itself cannot clip.
-        currentPath = null;
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractPathOrientedRenderer#closePath()
-     */
-    protected void closePath() {
-        currentPath.closePath();
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float)
-     */
-    protected void lineTo(float x, float y) {
-        if (currentPath == null) {
-            currentPath = new GeneralPath();
-        }
-        currentPath.lineTo(x, y);
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractPathOrientedRenderer#moveTo(float, float)
-     */
-    protected void moveTo(float x, float y) {
-        if (currentPath == null) {
-            currentPath = new GeneralPath();
-        }
-        currentPath.moveTo(x, y);
-    }
-    
-    /**
-     * Fill a rectangular area.
-     * @param x the x coordinate (in pt)
-     * @param y the y coordinate (in pt)
-     * @param width the width of the rectangle
-     * @param height the height of the rectangle
-     */
-    protected void fillRect(float x, float y, float width, float height) {
-        try {
-            setCursorPos(x * 1000, y * 1000);
-            gen.fillRect((int)(width * 1000), (int)(height * 1000), 
-                    this.currentFillColor);
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-    }
-    
-    /**
-     * Sets the new current fill color.
-     * @param color the color
-     */
-    protected void updateFillColor(java.awt.Color color) {
-        this.currentFillColor = color;
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderWord(org.apache.fop.area.inline.WordArea)
-     */
-    protected void renderWord(WordArea word) {
-        //Font font = getFontFromArea(word.getParentArea());
-
-        String s = word.getWord();
-
-        try {
-            gen.writeText(s);
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-
-        super.renderWord(word);
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderSpace(org.apache.fop.area.inline.SpaceArea)
-     */
-    protected void renderSpace(SpaceArea space) {
-        AbstractTextArea textArea = (AbstractTextArea)space.getParentArea();
-        String s = space.getSpace();
-        char sp = s.charAt(0);
-        Font font = getFontFromArea(textArea);
-        
-        int tws = (space.isAdjustable() 
-                ? textArea.getTextWordSpaceAdjust() 
-                        + 2 * textArea.getTextLetterSpaceAdjust()
-                : 0);
-
-        double dx = (font.getCharWidth(sp) + tws) / 100f;
-        try {
-            gen.writeCommand("&a+" + gen.formatDouble2(dx) + "H");
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-        super.renderSpace(space);
-    }
-
-    /**
-     * Render an inline viewport.
-     * This renders an inline viewport by clipping if necessary.
-     * @param viewport the viewport to handle
-     * @todo Copied from AbstractPathOrientedRenderer
-     */
-    public void renderViewport(Viewport viewport) {
-
-        float x = currentIPPosition / 1000f;
-        float y = (currentBPPosition + viewport.getOffset()) / 1000f;
-        float width = viewport.getIPD() / 1000f;
-        float height = viewport.getBPD() / 1000f;
-        // TODO: Calculate the border rect correctly. 
-        float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f;
-        float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f;
-        float bpwidth = borderPaddingStart 
-                + (viewport.getBorderAndPaddingWidthEnd() / 1000f);
-        float bpheight = borderPaddingBefore
-                + (viewport.getBorderAndPaddingWidthAfter() / 1000f);
-
-        drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight);
-
-        if (viewport.getClip()) {
-            saveGraphicsState();
-
-            clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height);
-        }
-        super.renderViewport(viewport);
-
-        if (viewport.getClip()) {
-            restoreGraphicsState();
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List)
-     */
-    protected void renderBlockViewport(BlockViewport bv, List children) {
-        // clip and position viewport if necessary
-
-        // save positions
-        int saveIP = currentIPPosition;
-        int saveBP = currentBPPosition;
-        //String saveFontName = currentFontName;
-
-        CTM ctm = bv.getCTM();
-        int borderPaddingStart = bv.getBorderAndPaddingWidthStart();
-        int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore();
-        float x, y;
-        x = (float)(bv.getXOffset() + containingIPPosition) / 1000f;
-        y = (float)(bv.getYOffset() + containingBPPosition) / 1000f;
-        //This is the content-rect
-        float width = (float)bv.getIPD() / 1000f;
-        float height = (float)bv.getBPD() / 1000f;
-        
-
-        if (bv.getPositioning() == Block.ABSOLUTE
-                || bv.getPositioning() == Block.FIXED) {
-
-            currentIPPosition = bv.getXOffset();
-            currentBPPosition = bv.getYOffset();
-
-            //For FIXED, we need to break out of the current viewports to the
-            //one established by the page. We save the state stack for restoration
-            //after the block-container has been painted. See below.
-            List breakOutList = null;
-            if (bv.getPositioning() == Block.FIXED) {
-                breakOutList = breakOutOfStateStack();
-            }
-            
-            CTM tempctm = new CTM(containingIPPosition, containingBPPosition);
-            ctm = tempctm.multiply(ctm);
-
-            //Adjust for spaces (from margin or indirectly by start-indent etc.
-            x += bv.getSpaceStart() / 1000f;
-            currentIPPosition += bv.getSpaceStart();
-            
-            y += bv.getSpaceBefore() / 1000f;
-            currentBPPosition += bv.getSpaceBefore(); 
-
-            float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f;
-            float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f;
-
-            drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight);
-
-            //Now adjust for border/padding
-            currentIPPosition += borderPaddingStart;
-            currentBPPosition += borderPaddingBefore;
-            
-            Rectangle2D clippingRect = null;
-            if (bv.getClip()) {
-                clippingRect = new Rectangle(currentIPPosition, currentBPPosition, 
-                        bv.getIPD(), bv.getBPD());
-            }
-
-            startVParea(ctm, clippingRect);
-            currentIPPosition = 0;
-            currentBPPosition = 0;
-            renderBlocks(bv, children);
-            endVParea();
-
-            if (breakOutList != null) {
-                restoreStateStackAfterBreakOut(breakOutList);
-            }
-            
-            currentIPPosition = saveIP;
-            currentBPPosition = saveBP;
-        } else {
-
-            currentBPPosition += bv.getSpaceBefore();
-
-            //borders and background in the old coordinate system
-            handleBlockTraits(bv);
-
-            //Advance to start of content area
-            currentIPPosition += bv.getStartIndent();
-
-            CTM tempctm = new CTM(containingIPPosition, currentBPPosition);
-            ctm = tempctm.multiply(ctm);
-            
-            //Now adjust for border/padding
-            currentBPPosition += borderPaddingBefore;
-
-            Rectangle2D clippingRect = null;
-            if (bv.getClip()) {
-                clippingRect = new Rectangle(currentIPPosition, currentBPPosition, 
-                        bv.getIPD(), bv.getBPD());
-            }
-            
-            startVParea(ctm, clippingRect);
-            currentIPPosition = 0;
-            currentBPPosition = 0;
-            renderBlocks(bv, children);
-            endVParea();
-
-            currentIPPosition = saveIP;
-            currentBPPosition = saveBP;
-            
-            currentBPPosition += (int)(bv.getAllocBPD());
-        }
-        //currentFontName = saveFontName;
-    }
-
-    private List breakOutOfStateStack() {
-        log.debug("Block.FIXED --> break out");
-        List breakOutList = new java.util.ArrayList();
-        while (!this.graphicContextStack.empty()) {
-            breakOutList.add(0, this.graphicContext);
-            restoreGraphicsState();
-        }
-        return breakOutList;
-    }
-
-    private void restoreStateStackAfterBreakOut(List breakOutList) {
-        log.debug("Block.FIXED --> restoring context after break-out");
-        for (int i = 0, c = breakOutList.size(); i < c; i++) {
-            saveGraphicsState();
-            this.graphicContext = (GraphicContext)breakOutList.get(i);
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D)
-     */
-    public void renderImage(Image image, Rectangle2D pos) {
-        drawImage(image.getURL(), pos, image.getForeignAttributes());
-    }
-
-    /**
-     * Draw an image at the indicated location.
-     * @param url the URI/URL of the image
-     * @param pos the position of the image
-     * @param foreignAttributes an optional Map with foreign attributes, may be null
-     */
-    protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) {
-        url = ImageFactory.getURL(url);
-        ImageFactory fact = userAgent.getFactory().getImageFactory();
-        FopImage fopimage = fact.getImage(url, userAgent);
-        if (fopimage == null) {
-            return;
-        }
-        if (!fopimage.load(FopImage.DIMENSIONS)) {
-            return;
-        }
-        String mime = fopimage.getMimeType();
-        if ("text/xml".equals(mime)) {
-            if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
-                return;
-            }
-            Document doc = ((XMLImage) fopimage).getDocument();
-            String ns = ((XMLImage) fopimage).getNameSpace();
-
-            renderDocument(doc, ns, pos, foreignAttributes);
-        } else if ("image/svg+xml".equals(mime)) {
-            if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
-                return;
-            }
-            Document doc = ((XMLImage) fopimage).getDocument();
-            String ns = ((XMLImage) fopimage).getNameSpace();
-
-            renderDocument(doc, ns, pos, foreignAttributes);
-        } else if (fopimage instanceof EPSImage) {
-            log.warn("EPS images are not supported by this renderer");
-        } else {
-            if (!fopimage.load(FopImage.BITMAP)) {
-                log.error("Bitmap image could not be processed: " + fopimage);
-                return;
-            }
-            byte[] imgmap = fopimage.getBitmaps();
-            
-            ColorModel cm = new ComponentColorModel(
-                    ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), 
-                    new int[] {8, 8, 8},
-                    false, false,
-                    ColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
-            int imgw = fopimage.getWidth();
-            int imgh = fopimage.getHeight();
-            SampleModel sampleModel = new PixelInterleavedSampleModel(
-                    DataBuffer.TYPE_BYTE, imgw, imgh, 3, imgw * 3, new int[] {0, 1, 2});
-            DataBuffer dbuf = new DataBufferByte(imgmap, imgw * imgh * 3);
-
-            WritableRaster raster = Raster.createWritableRaster(sampleModel,
-                    dbuf, null);
-
-            // Combine the color model and raster into a buffered image
-            RenderedImage img = new BufferedImage(cm, raster, false, null);
-
-            try {
-                setCursorPos(this.currentIPPosition + (int)pos.getX(),
-                        this.currentBPPosition + (int)pos.getY());
-                gen.paintBitmap(img, 
-                        new Dimension((int)pos.getWidth(), (int)pos.getHeight()), 
-                        false);
-            } catch (IOException ioe) {
-                handleIOTrouble(ioe);
-            }
-        }
-    }
-
-    /**
-     * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
-     */
-    public void renderForeignObject(ForeignObject fo, Rectangle2D pos) {
-        Document doc = fo.getDocument();
-        String ns = fo.getNameSpace();
-        renderDocument(doc, ns, pos, fo.getForeignAttributes());
-    }
-
-    /** 
-     * Common method to render the background and borders for any inline area.
-     * The all borders and padding are drawn outside the specified area.
-     * @param area the inline area for which the background, border and padding is to be
-     * rendered
-     * @todo Copied from AbstractPathOrientedRenderer
-     */
-    protected void renderInlineAreaBackAndBorders(InlineArea area) {
-        float x = currentIPPosition / 1000f;
-        float y = (currentBPPosition + area.getOffset()) / 1000f;
-        float width = area.getIPD() / 1000f;
-        float height = area.getBPD() / 1000f;
-        float borderPaddingStart = area.getBorderAndPaddingWidthStart() / 1000f;
-        float borderPaddingBefore = area.getBorderAndPaddingWidthBefore() / 1000f;
-        float bpwidth = borderPaddingStart 
-                + (area.getBorderAndPaddingWidthEnd() / 1000f);
-        float bpheight = borderPaddingBefore
-                + (area.getBorderAndPaddingWidthAfter() / 1000f);
-        
-        if (height != 0.0f || bpheight != 0.0f && bpwidth != 0.0f) {
-            drawBackAndBorders(area, x, y - borderPaddingBefore
-                                , width + bpwidth
-                                , height + bpheight);
-        }
-    }
-    
-    /**
-     * Draw the background and borders. This draws the background and border
-     * traits for an area given the position.
-     *
-     * @param area the area whose traits are used
-     * @param startx the start x position
-     * @param starty the start y position
-     * @param width the width of the area
-     * @param height the height of the area
-     */
-    protected void drawBackAndBorders(Area area, float startx, float starty,
-            float width, float height) {
-        BorderProps bpsBefore = (BorderProps) area.getTrait(Trait.BORDER_BEFORE);
-        BorderProps bpsAfter = (BorderProps) area.getTrait(Trait.BORDER_AFTER);
-        BorderProps bpsStart = (BorderProps) area.getTrait(Trait.BORDER_START);
-        BorderProps bpsEnd = (BorderProps) area.getTrait(Trait.BORDER_END);
-    
-        // draw background
-        Trait.Background back;
-        back = (Trait.Background) area.getTrait(Trait.BACKGROUND);
-        if (back != null) {
-    
-            // Calculate padding rectangle
-            float sx = startx;
-            float sy = starty;
-            float paddRectWidth = width;
-            float paddRectHeight = height;
-    
-            if (bpsStart != null) {
-                sx += bpsStart.width / 1000f;
-                paddRectWidth -= bpsStart.width / 1000f;
-            }
-            if (bpsBefore != null) {
-                sy += bpsBefore.width / 1000f;
-                paddRectHeight -= bpsBefore.width / 1000f;
-            }
-            if (bpsEnd != null) {
-                paddRectWidth -= bpsEnd.width / 1000f;
-            }
-            if (bpsAfter != null) {
-                paddRectHeight -= bpsAfter.width / 1000f;
-            }
-    
-            if (back.getColor() != null) {
-                updateFillColor(back.getColor());
-                fillRect(sx, sy, paddRectWidth, paddRectHeight);
-            }
-    
-            // background image
-            if (back.getFopImage() != null) {
-                FopImage fopimage = back.getFopImage();
-                if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) {
-                    saveGraphicsState();
-                    clipRect(sx, sy, paddRectWidth, paddRectHeight);
-                    int horzCount = (int) ((paddRectWidth * 1000 / fopimage
-                            .getIntrinsicWidth()) + 1.0f);
-                    int vertCount = (int) ((paddRectHeight * 1000 / fopimage
-                            .getIntrinsicHeight()) + 1.0f);
-                    if (back.getRepeat() == EN_NOREPEAT) {
-                        horzCount = 1;
-                        vertCount = 1;
-                    } else if (back.getRepeat() == EN_REPEATX) {
-                        vertCount = 1;
-                    } else if (back.getRepeat() == EN_REPEATY) {
-                        horzCount = 1;
-                    }
-                    // change from points to millipoints
-                    sx *= 1000;
-                    sy *= 1000;
-                    if (horzCount == 1) {
-                        sx += back.getHoriz();
-                    }
-                    if (vertCount == 1) {
-                        sy += back.getVertical();
-                    }
-                    for (int x = 0; x < horzCount; x++) {
-                        for (int y = 0; y < vertCount; y++) {
-                            // place once
-                            Rectangle2D pos;
-                            // Image positions are relative to the currentIP/BP
-                            pos = new Rectangle2D.Float(
-                                    sx - currentIPPosition 
-                                        + (x * fopimage.getIntrinsicWidth()),
-                                    sy - currentBPPosition
-                                        + (y * fopimage.getIntrinsicHeight()),
-                                    fopimage.getIntrinsicWidth(),
-                                    fopimage.getIntrinsicHeight());
-                            drawImage(back.getURL(), pos, null);
-                        }
-                    }
-                    restoreGraphicsState();
-                } else {
-                    log.warn(
-                            "Can't find background image: " + back.getURL());
-                }
-            }
-        }
-        
-        Rectangle2D.Float borderRect = new Rectangle2D.Float(startx, starty, width, height);
-        drawBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
-    }
-
-    /**
-     * Draws borders.
-     * @param borderRect the border rectangle
-     * @param bpsBefore the border specification on the before side
-     * @param bpsAfter the border specification on the after side
-     * @param bpsStart the border specification on the start side
-     * @param bpsEnd the border specification on the end side
-     */
-    protected void drawBorders(Rectangle2D.Float borderRect, 
-            final BorderProps bpsBefore, final BorderProps bpsAfter, 
-            final BorderProps bpsStart, final BorderProps bpsEnd) {
-        if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
-            return; //no borders to paint
-        }
-        if (qualityBeforeSpeed) {
-            drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
-        } else {
-            drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
-        }
-    }
-    
-    /**
-     * Draws borders. Borders are drawn as shaded rectangles with no clipping.
-     * @param borderRect the border rectangle
-     * @param bpsBefore the border specification on the before side
-     * @param bpsAfter the border specification on the after side
-     * @param bpsStart the border specification on the start side
-     * @param bpsEnd the border specification on the end side
-     */
-    protected void drawFastBorders(Rectangle2D.Float borderRect, 
-            final BorderProps bpsBefore, final BorderProps bpsAfter, 
-            final BorderProps bpsStart, final BorderProps bpsEnd) {
-        float startx = borderRect.x;
-        float starty = borderRect.y;
-        float width = borderRect.width;
-        float height = borderRect.height;
-        if (bpsBefore != null) {
-            float borderWidth = bpsBefore.width / 1000f;
-            updateFillColor(bpsBefore.color);
-            fillRect(startx, starty, width, borderWidth);
-        }
-        if (bpsAfter != null) {
-            float borderWidth = bpsAfter.width / 1000f;
-            updateFillColor(bpsAfter.color);
-            fillRect(startx, (starty + height - borderWidth), 
-                    width, borderWidth);
-        }
-        if (bpsStart != null) {
-            float borderWidth = bpsStart.width / 1000f;
-            updateFillColor(bpsStart.color);
-            fillRect(startx, starty, borderWidth, height);
-        }
-        if (bpsEnd != null) {
-            float borderWidth = bpsEnd.width / 1000f;
-            updateFillColor(bpsEnd.color);
-            fillRect((startx + width - borderWidth), starty, borderWidth, height);
-        }
-    }
-    
-    /**
-     * Draws borders. Borders are drawn in-memory and painted as a bitmap.
-     * @param borderRect the border rectangle
-     * @param bpsBefore the border specification on the before side
-     * @param bpsAfter the border specification on the after side
-     * @param bpsStart the border specification on the start side
-     * @param bpsEnd the border specification on the end side
-     */
-    protected void drawQualityBorders(Rectangle2D.Float borderRect, 
-            final BorderProps bpsBefore, final BorderProps bpsAfter, 
-            final BorderProps bpsStart, final BorderProps bpsEnd) {
-        Graphics2DAdapter g2a = getGraphics2DAdapter();
-        final Rectangle.Float effBorderRect = new Rectangle2D.Float(
-                 borderRect.x - (currentIPPosition / 1000f),
-                 borderRect.y - (currentBPPosition / 1000f),
-                 borderRect.width,
-                 borderRect.height);
-        final Rectangle paintRect = new Rectangle(
-                (int)Math.round(borderRect.x * 1000f),
-                (int)Math.round(borderRect.y * 1000f), 
-                (int)Math.floor(borderRect.width * 1000f) + 1,
-                (int)Math.floor(borderRect.height * 1000f) + 1);
-        //Add one pixel wide safety margin around the paint area
-        int pixelWidth = (int)Math.round(UnitConv.in2mpt(1) / userAgent.getTargetResolution());
-        final int xoffset = (int)Math.round(-effBorderRect.x * 1000f) + pixelWidth;
-        final int yoffset = pixelWidth;
-        paintRect.x += xoffset;
-        paintRect.y += yoffset;
-        paintRect.width += 2 * pixelWidth;
-        paintRect.height += 2 * pixelWidth;
-        
-        RendererContext rc = createRendererContext(paintRect.x, paintRect.y, 
-                paintRect.width, paintRect.height, null);
-        Map atts = new java.util.HashMap();
-        atts.put(CONV_MODE, "bitmap");
-        atts.put(SRC_TRANSPARENCY, "true");
-        rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
-        
-        Graphics2DImagePainter painter = new Graphics2DImagePainter() {
-
-            public void paint(Graphics2D g2d, Rectangle2D area) {
-                g2d.translate(xoffset, yoffset);
-                g2d.scale(1000, 1000);
-                float startx = effBorderRect.x;
-                float starty = effBorderRect.y;
-                float width = effBorderRect.width;
-                float height = effBorderRect.height;
-                boolean[] b = new boolean[] {
-                    (bpsBefore != null), (bpsEnd != null), 
-                    (bpsAfter != null), (bpsStart != null)};
-                if (!b[0] && !b[1] && !b[2] && !b[3]) {
-                    return;
-                }
-                float[] bw = new float[] {
-                    (b[0] ? bpsBefore.width / 1000f : 0.0f),
-                    (b[1] ? bpsEnd.width / 1000f : 0.0f),
-                    (b[2] ? bpsAfter.width / 1000f : 0.0f),
-                    (b[3] ? bpsStart.width / 1000f : 0.0f)};
-                float[] clipw = new float[] {
-                    BorderProps.getClippedWidth(bpsBefore) / 1000f,    
-                    BorderProps.getClippedWidth(bpsEnd) / 1000f,    
-                    BorderProps.getClippedWidth(bpsAfter) / 1000f,    
-                    BorderProps.getClippedWidth(bpsStart) / 1000f};
-                starty += clipw[0];
-                height -= clipw[0];
-                height -= clipw[2];
-                startx += clipw[3];
-                width -= clipw[3];
-                width -= clipw[1];
-                
-                boolean[] slant = new boolean[] {
-                    (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])};
-                if (bpsBefore != null) {
-                    //endTextObject();
-
-                    float sx1 = startx;
-                    float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1);
-                    float ex1 = startx + width;
-                    float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1);
-                    float outery = starty - clipw[0];
-                    float clipy = outery + clipw[0];
-                    float innery = outery + bw[0];
-
-                    //saveGraphicsState();
-                    Graphics2D g = (Graphics2D)g2d.create();
-                    moveTo(sx1, clipy);
-                    float sx1a = sx1;
-                    float ex1a = ex1;
-                    if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
-                        if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
-                            sx1a -= clipw[3];
-                        }
-                        if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
-                            ex1a += clipw[1];
-                        }
-                        lineTo(sx1a, outery);
-                        lineTo(ex1a, outery);
-                    }
-                    lineTo(ex1, clipy);
-                    lineTo(ex2, innery);
-                    lineTo(sx2, innery);
-                    closePath();
-                    //clip();
-                    g.clip(currentPath);
-                    currentPath = null;
-                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
-                            sx1a, outery, ex1a - sx1a, innery - outery);
-                    Java2DRenderer.drawBorderLine(lineRect, true, true, 
-                            bpsBefore.style, bpsBefore.color, g);
-                    //restoreGraphicsState();
-                }
-                if (bpsEnd != null) {
-                    //endTextObject();
-
-                    float sy1 = starty;
-                    float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1);
-                    float ey1 = starty + height;
-                    float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1);
-                    float outerx = startx + width + clipw[1];
-                    float clipx = outerx - clipw[1];
-                    float innerx = outerx - bw[1];
-                    
-                    //saveGraphicsState();
-                    Graphics2D g = (Graphics2D)g2d.create();
-                    moveTo(clipx, sy1);
-                    float sy1a = sy1;
-                    float ey1a = ey1;
-                    if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
-                        if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
-                            sy1a -= clipw[0];
-                        }
-                        if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
-                            ey1a += clipw[2];
-                        }
-                        lineTo(outerx, sy1a);
-                        lineTo(outerx, ey1a);
-                    }
-                    lineTo(clipx, ey1);
-                    lineTo(innerx, ey2);
-                    lineTo(innerx, sy2);
-                    closePath();
-                    //clip();
-                    g.setClip(currentPath);
-                    currentPath = null;
-                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
-                            innerx, sy1a, outerx - innerx, ey1a - sy1a);
-                    Java2DRenderer.drawBorderLine(lineRect, false, false, 
-                            bpsEnd.style, bpsEnd.color, g);
-                    //restoreGraphicsState();
-                }
-                if (bpsAfter != null) {
-                    //endTextObject();
-
-                    float sx1 = startx;
-                    float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1);
-                    float ex1 = startx + width;
-                    float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1);
-                    float outery = starty + height + clipw[2];
-                    float clipy = outery - clipw[2];
-                    float innery = outery - bw[2];
-
-                    //saveGraphicsState();
-                    Graphics2D g = (Graphics2D)g2d.create();
-                    moveTo(ex1, clipy);
-                    float sx1a = sx1;
-                    float ex1a = ex1;
-                    if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
-                        if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
-                            sx1a -= clipw[3];
-                        }
-                        if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) {
-                            ex1a += clipw[1];
-                        }
-                        lineTo(ex1a, outery);
-                        lineTo(sx1a, outery);
-                    }
-                    lineTo(sx1, clipy);
-                    lineTo(sx2, innery);
-                    lineTo(ex2, innery);
-                    closePath();
-                    //clip();
-                    g.setClip(currentPath);
-                    currentPath = null;
-                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
-                            sx1a, innery, ex1a - sx1a, outery - innery);
-                    Java2DRenderer.drawBorderLine(lineRect, true, false, 
-                            bpsAfter.style, bpsAfter.color, g);
-                    //restoreGraphicsState();
-                }
-                if (bpsStart != null) {
-                    //endTextObject();
-
-                    float sy1 = starty;
-                    float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1);
-                    float ey1 = sy1 + height;
-                    float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1);
-                    float outerx = startx - clipw[3];
-                    float clipx = outerx + clipw[3];
-                    float innerx = outerx + bw[3];
-
-                    //saveGraphicsState();
-                    Graphics2D g = (Graphics2D)g2d.create();
-                    moveTo(clipx, ey1);
-                    float sy1a = sy1;
-                    float ey1a = ey1;
-                    if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) {
-                        if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) {
-                            sy1a -= clipw[0];
-                        }
-                        if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) {
-                            ey1a += clipw[2];
-                        }
-                        lineTo(outerx, ey1a);
-                        lineTo(outerx, sy1a);
-                    }
-                    lineTo(clipx, sy1);
-                    lineTo(innerx, sy2);
-                    lineTo(innerx, ey2);
-                    closePath();
-                    //clip();
-                    g.setClip(currentPath);
-                    currentPath = null;
-                    Rectangle2D.Float lineRect = new Rectangle2D.Float(
-                            outerx, sy1a, innerx - outerx, ey1a - sy1a);
-                    Java2DRenderer.drawBorderLine(lineRect, false, false, 
-                            bpsStart.style, bpsStart.color, g);
-                    //restoreGraphicsState();
-                }
-            }
-
-            public Dimension getImageSize() {
-                return paintRect.getSize();
-            }
-            
-        };
-        try {
-            g2a.paintImage(painter, rc, 
-                    paintRect.x - xoffset, paintRect.y, paintRect.width, paintRect.height);
-        } catch (IOException ioe) {
-            handleIOTrouble(ioe);
-        }
-    }
-    
-    
-    
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLRendererContext.java b/src/sandbox/org/apache/fop/render/pcl/PCLRendererContext.java
deleted file mode 100644 (file)
index ae5646d..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.render.RendererContext;
-import org.apache.fop.util.QName;
-
-/**
- * Wrapper on the RendererContext to access the information structure for drawing 
- * the XML document.
- */
-public class PCLRendererContext extends RendererContext.RendererContextWrapper {
-
-    /**
-     * Wrap the render context to allow easier access to its values.
-     *
-     * @param context the renderer context
-     * @return the PCL-specific renderer context wrapper
-     */
-    public static PCLRendererContext wrapRendererContext(RendererContext context) {
-        PCLRendererContext pcli = new PCLRendererContext(context);
-        return pcli;
-    }
-
-    /**
-     * Main constructor
-     * @param context the RendererContent instance
-     */
-    public PCLRendererContext(RendererContext context) {
-        super(context);
-    }
-    
-    /** @return true if the SVG image should be rendered as a bitmap */
-    public boolean paintAsBitmap() {
-        QName qName = new QName(ExtensionElementMapping.URI, null, "conversion-mode");
-        return getForeignAttributes() != null 
-             && "bitmap".equalsIgnoreCase((String)getForeignAttributes().get(qName));
-    }
-    
-    /** @return true if clipping is disabled inside the PCLGraphics2D. */
-    public boolean isClippingDisabled() {
-        QName qName = new QName(ExtensionElementMapping.URI, null, "disable-clipping");
-        return getForeignAttributes() != null 
-             && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
-    }
-
-    public boolean isSourceTransparency() {
-        QName qName = new QName(ExtensionElementMapping.URI, null, "source-transparency");
-        return getForeignAttributes() != null 
-             && "true".equalsIgnoreCase((String)getForeignAttributes().get(qName));
-    }
-    
-
-}
\ No newline at end of file
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLRendererMaker.java b/src/sandbox/org/apache/fop/render/pcl/PCLRendererMaker.java
deleted file mode 100644 (file)
index 2e39d35..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*\r
- * Copyright 2005 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* $Id$ */\r
-\r
-package org.apache.fop.render.pcl;\r
-\r
-import org.apache.fop.apps.FOUserAgent;\r
-import org.apache.fop.apps.MimeConstants;\r
-import org.apache.fop.render.AbstractRendererMaker;\r
-import org.apache.fop.render.Renderer;\r
-\r
-/**\r
- * RendererMaker for the PCL Renderer.\r
- */\r
-public class PCLRendererMaker extends AbstractRendererMaker {\r
-\r
-    private static final String[] MIMES = new String[] {\r
-        MimeConstants.MIME_PCL,\r
-        MimeConstants.MIME_PCL_ALT};\r
-    \r
-    \r
-    /**@see org.apache.fop.render.AbstractRendererMaker */\r
-    public Renderer makeRenderer(FOUserAgent ua) {\r
-        return new PCLRenderer();\r
-    }\r
-\r
-    /** @see org.apache.fop.render.AbstractRendererMaker#needsOutputStream() */\r
-    public boolean needsOutputStream() {\r
-        return true;\r
-    }\r
-\r
-    /** @see org.apache.fop.render.AbstractRendererMaker#getSupportedMimeTypes() */\r
-    public String[] getSupportedMimeTypes() {\r
-        return MIMES;\r
-    }\r
-\r
-}\r
diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLSVGHandler.java b/src/sandbox/org/apache/fop/render/pcl/PCLSVGHandler.java
deleted file mode 100644 (file)
index 7c1a45a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.pcl;
-
-// FOP
-import org.apache.fop.render.AbstractGenericSVGHandler;
-import org.apache.fop.render.Renderer;
-
-/**
- * PCL XML handler for SVG. Uses Apache Batik for SVG processing.
- * This handler handles XML for foreign objects when rendering to HP GL/2.
- * It renders SVG to HP GL/2 using the PCLGraphics2D.
- * @see PCLGraphics2DAdapter
- */
-public class PCLSVGHandler extends AbstractGenericSVGHandler {
-
-    /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */
-    public boolean supportsRenderer(Renderer renderer) {
-        return (renderer instanceof PCLRenderer);
-    }
-    
-}
-
diff --git a/src/sandbox/org/apache/fop/render/pcl/extensions/PCLElementMapping.java b/src/sandbox/org/apache/fop/render/pcl/extensions/PCLElementMapping.java
deleted file mode 100644 (file)
index b25ab93..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2006 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id: AFPElementMapping.java 397875 2006-04-28 11:58:33Z manuel $ */
-
-package org.apache.fop.render.pcl.extensions;
-
-import java.util.HashMap;
-
-import org.apache.fop.fo.ElementMapping;
-
-/**
- * PCL-specific extensions for Apache FOP.
- */
-public class PCLElementMapping extends ElementMapping {
-
-    /** The namespace used for PCL extensions */
-    public static final String NAMESPACE = "http://xmlgraphics.apache.org/fop/extensions/pcl";
-
-    /** The usual namespace prefix used for PCL extensions */
-    public static final String NAMESPACE_PREFIX = "pcl";
-
-    /** Main constructor */
-    public PCLElementMapping() {
-        this.namespaceURI = NAMESPACE;
-    }
-
-    /** @see org.apache.fop.fo.ElementMapping#initialize() */
-    protected void initialize() {
-
-        if (foObjs == null) {
-            foObjs = new HashMap();
-            //No extension elements, yet, only attributes
-        }
-
-    }
-
-}
diff --git a/src/sandbox/org/apache/fop/render/pcl/package.html b/src/sandbox/org/apache/fop/render/pcl/package.html
deleted file mode 100644 (file)
index ba47bd2..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  Copyright 2005-2006 The Apache Software Foundation
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-<!-- $Id$ -->
-<HTML>
-<TITLE>org.apache.fop.render.pcl Package</TITLE>
-<BODY>
-<P>PCL Renderer (Supports PCL5 and HP GL/2)</P>
-</BODY>
-</HTML>
\ No newline at end of file