You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2014/03/06 10:05:09 UTC

svn commit: r1574811 [1/2] - in /pdfbox/trunk: pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/ pdfbox/src/main/java/org/apache/pdfbox/pdmod...

Author: jahewson
Date: Thu Mar  6 09:05:08 2014
New Revision: 1574811

URL: http://svn.apache.org/r1574811
Log:
PDFBOX-1963, PDFBOX-1962: Refactor RenderUtil, PageDrawer and PDFImageWriter into 'rendering' module

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFPrinter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfviewer/PageDrawer.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageable.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFImageWriter.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/RenderUtil.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/ImageIOUtil.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/BeginInlineImage.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipEvenOddRule.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipNonZeroRule.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClosePath.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveTo.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalPoint.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitialPoint.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/EndPath.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePath.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddRule.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePath.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroRule.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/LineTo.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/MoveTo.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/SHFill.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/StrokePath.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/font/PDSimpleFontTest.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestImageIOUtils.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestRendering.java
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFReader.java
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PDFToImage.java
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/PrintPDF.java
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/gui/PDFPagePanel.java
    pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/gui/PageWrapper.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java Thu Mar  6 09:05:08 2014
@@ -1288,6 +1288,16 @@ public class PDDocument implements Close
     }
 
     /**
+     * Returns the page at the given index.
+     * @param pageIndex the page index
+     * @return the page at the given index.
+     */
+    public PDPage getPage(int pageIndex)
+    {
+        return (PDPage) getDocumentCatalog().getAllPages().get(pageIndex);
+    }
+
+    /**
      * This will return the total page count of the PDF document.
      * 
      * @return The total number of pages in the PDF document.

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPage.java Thu Mar  6 09:05:08 2014
@@ -53,10 +53,7 @@ public class PDPage implements COSObject
      */
     private static final Log LOG = LogFactory.getLog(PDPage.class);
 
-    /**
-     * Default DPI in user space.
-     */
-    public static final int DEFAULT_USER_SPACE_UNIT_DPI = 72;
+    private static final int DEFAULT_USER_SPACE_UNIT_DPI = 72;
 
     private static final float MM_TO_UNITS = 1 / (10 * 2.54f) * DEFAULT_USER_SPACE_UNIT_DPI;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java Thu Mar  6 09:05:08 2014
@@ -22,6 +22,7 @@ import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.common.COSObjectable;
 import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
+import org.apache.pdfbox.rendering.PDFRenderer;
 
 import java.awt.Color;
 import java.awt.Paint;
@@ -231,9 +232,9 @@ public abstract class PDColorSpace imple
      * @return an AWT paint
      * @throws IOException if the color conversion fails
      */
-    public Paint toPaint(PDColor color) throws IOException
+    public Paint toPaint(PDFRenderer renderer,  PDColor color) throws IOException
     {
-        return toPaint(color, 0);
+        return toPaint(renderer, color, 0);
     }
 
     /**
@@ -245,7 +246,7 @@ public abstract class PDColorSpace imple
      * @return an AWT paint
      * @throws IOException if the color conversion fails
      */
-    public Paint toPaint(PDColor color, int pageHeight) throws IOException
+    public Paint toPaint(PDFRenderer renderer, PDColor color, int pageHeight) throws IOException
     {
         float[] rgb = toRGB(color.getComponents());
         return new Color(rgb[0], rgb[1], rgb[2]);

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java Thu Mar  6 09:05:08 2014
@@ -34,6 +34,7 @@ import org.apache.pdfbox.pdmodel.graphic
 import org.apache.pdfbox.pdmodel.graphics.shading.Type1ShadingPaint;
 import org.apache.pdfbox.pdmodel.graphics.shading.Type4ShadingPaint;
 import org.apache.pdfbox.pdmodel.graphics.shading.Type5ShadingPaint;
+import org.apache.pdfbox.rendering.PDFRenderer;
 
 import java.awt.Color;
 import java.awt.Paint;
@@ -110,13 +111,13 @@ public final class PDPattern extends PDS
     }
 
     @Override
-    public Paint toPaint(PDColor color) throws IOException
+    public Paint toPaint(PDFRenderer renderer, PDColor color) throws IOException
     {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public Paint toPaint(PDColor color, int pageHeight) throws IOException
+    public Paint toPaint(PDFRenderer renderer, PDColor color, int pageHeight) throws IOException
     {
         if (!patterns.containsKey(color.getPatternName()))
         {
@@ -126,7 +127,7 @@ public final class PDPattern extends PDS
         PDAbstractPattern pattern = patterns.get(color.getPatternName());
         if (pattern instanceof PDTilingPattern)
         {
-            return toTilingPaint((PDTilingPattern)pattern, color);
+            return toTilingPaint(renderer, (PDTilingPattern)pattern, color);
         }
         else
         {
@@ -134,22 +135,22 @@ public final class PDPattern extends PDS
         }
     }
 
-    public Paint toTilingPaint(PDTilingPattern tilingPattern, PDColor color)
+    public Paint toTilingPaint(PDFRenderer renderer, PDTilingPattern tilingPattern, PDColor color)
             throws IOException
     {
         if (tilingPattern.getPaintType() == PDTilingPattern.PAINT_COLORED)
         {
             // colored tiling pattern
-            return new TilingPaint(tilingPattern);
+            return new TilingPaint(renderer, tilingPattern);
         }
         else
         {
             // uncolored tiling pattern
-            return new TilingPaint(tilingPattern, underlyingColorSpace, color);
+            return new TilingPaint(renderer, tilingPattern, underlyingColorSpace, color);
         }
     }
-    public Paint toShadingPaint(PDShadingPattern shadingPattern, int pageHeight)
-            throws IOException
+
+    public Paint toShadingPaint(PDShadingPattern shadingPattern, int pageHeight) throws IOException
     {
         PDShading shadingResources = shadingPattern.getShading();
         int shadingType = shadingResources != null ? shadingResources.getShadingType() : 0;

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java Thu Mar  6 09:05:08 2014
@@ -16,17 +16,12 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.pattern;
 
-import java.awt.Color;
 import java.awt.Graphics2D;
-import java.awt.Paint;
-import java.awt.PaintContext;
 import java.awt.Rectangle;
-import java.awt.RenderingHints;
 import java.awt.TexturePaint;
 import java.awt.Transparency;
 import java.awt.color.ColorSpace;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
 import java.awt.image.ComponentColorModel;
@@ -34,11 +29,11 @@ import java.awt.image.DataBuffer;
 import java.awt.image.WritableRaster;
 import java.io.IOException;
 
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PDFRenderer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
-import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -46,23 +41,15 @@ import org.apache.pdfbox.util.Matrix;
  * @author Andreas Lehmkühler
  * @author John Hewson
  */
-public class TilingPaint implements Paint
+public class TilingPaint extends TexturePaint
 {
-    private static Color TRANSPARENT = new Color(0, 0, 0, 0);
-
-    private final PDTilingPattern pattern;
-    private final PDColorSpace colorSpace;
-    private final PDColor color;
-
     /**
      * Creates a new colored tiling Paint.
      * @param pattern tiling pattern dictionary
      */
-    public TilingPaint(PDTilingPattern pattern) throws IOException
+    public TilingPaint(PDFRenderer renderer, PDTilingPattern pattern) throws IOException
     {
-        this.pattern = pattern;
-        this.colorSpace = null;
-        this.color = null;
+        super(getImage(renderer, pattern, null ,null), getTransformedRect(pattern));
     }
 
     /**
@@ -71,146 +58,67 @@ public class TilingPaint implements Pain
      * @param colorSpace color space for this tiling
      * @param color color for this tiling
      */
-    public TilingPaint(PDTilingPattern pattern, PDColorSpace colorSpace, PDColor color)
-            throws IOException
+    public TilingPaint(PDFRenderer renderer, PDTilingPattern pattern, PDColorSpace colorSpace,
+                       PDColor color) throws IOException
     {
-        this.pattern = pattern;
-        this.colorSpace = colorSpace;
-        this.color = color;
-    }
-
-    @Override
-    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
-                                      Rectangle2D userBounds, AffineTransform xform,
-                                      RenderingHints hints)
-    {
-        System.out.println("TilingPaint#createContext" +
-                " rectangle: " + deviceBounds +
-                " affineTransform: " + xform);
-        try
-        {
-            ColorSpace outputCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);
-            ColorModel cm2 = new ComponentColorModel(outputCS, true, false,
-                    Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
-
-            // DISABLED
-            //return new TilingPaintContext(cm2 /*HACK*/, deviceBounds, xform, getTilingImage(cm, xform));
-
-            hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-
-            // EXPERIMENT
-            // ... CRAZY HACK:
-            TexturePaint paint = new TexturePaint(getTilingImage(cm, xform), getTransformedRect(xform, false));
-            return paint.createContext(cm, deviceBounds, userBounds, xform, hints); // ^^^^^ USE SPACE RECT, NO XFORM.
-        }
-        catch (IOException e)
-        {
-            e.printStackTrace(); // TODO !!!!!!
-            // TODO: log
-            return TRANSPARENT.createContext(cm, deviceBounds, userBounds,
-                    xform, hints);
-        }
+        super(getImage(renderer, pattern, colorSpace, color), getTransformedRect(pattern));
     }
 
     //  gets rect in parent content stream coordinates
-    private Rectangle getTransformedRect(AffineTransform transform, boolean applyCTM)
+    private static Rectangle getTransformedRect(PDTilingPattern pattern)
     {
-        // pattern matrix
-        Rectangle rect;
         if (pattern.getMatrix() == null)
         {
-            rect = new Rectangle(pattern.getBBox().createDimension());
+            return new Rectangle(pattern.getBBox().createDimension());
         }
         else
         {
             AffineTransform at = pattern.getMatrix().createAffineTransform();
-            rect = new Rectangle(pattern.getBBox().createDimension());
-            rect = at.createTransformedShape(rect).getBounds();
-        }
-
-        // x/y step
-        if (pattern.getMatrix() != null)
-        {
-            // TODO can be -ve
-            rect.width = Math.round(pattern.getXStep() * Math.abs(pattern.getMatrix().getXScale()));
-            rect.height = Math.round(pattern.getYStep() * Math.abs(pattern.getMatrix().getYScale()));
-        }
-        else
-        {
-            rect.width = pattern.getXStep();
-            rect.height = pattern.getYStep();
-        }
-
-        // ctm
-        if (applyCTM)
-        {
-            rect = transform.createTransformedShape(rect).getBounds();
+            Rectangle rect = new Rectangle(pattern.getBBox().createDimension());
+            return at.createTransformedShape(rect).getBounds();
         }
-
-        return rect;
     }
 
     // gets image in parent stream coordinates
-    private BufferedImage getTilingImage(ColorModel colorModel, AffineTransform transform)
-            throws IOException
+    private static BufferedImage getImage(PDFRenderer renderer, PDTilingPattern pattern,
+                                          PDColorSpace colorSpace, PDColor color) throws IOException
     {
-        // TODO use colorModel parameter
         ColorSpace outputCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);
         ColorModel cm = new ComponentColorModel(outputCS, true, false,
                 Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
 
-        Rectangle rect = getTransformedRect(transform, true);
-        int width = 1000;
-        int height = 1000;
+        Rectangle rect = getTransformedRect(pattern);
+        int width = Math.round((float)rect.getWidth());
+        int height = Math.round((float)rect.getHeight());
 
         // create raster
         WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
         BufferedImage image = new BufferedImage(cm, raster, false, null);
 
+        // TODO xStep and yStep
+
         // matrix
-        AffineTransform patternMatrix;
+        Matrix matrix;
         if (pattern.getMatrix() == null)
         {
             // identity
-            patternMatrix = new AffineTransform();
+            matrix = new Matrix();
         }
         else
         {
-            // pattern matrix
-            patternMatrix = pattern.getMatrix().createAffineTransform();
-
-            // flip -ve x-scale
-            if (patternMatrix.getScaleX() < -0)
-            {
-                patternMatrix.scale(-1, 1);
-            }
+            // undo translation
+            matrix = (Matrix)pattern.getMatrix().clone();
+            matrix.setValue(2, 0, matrix.getValue(2, 0) - (float)rect.getX()); // tx
+            matrix.setValue(2, 1, matrix.getValue(2, 1) - (float)rect.getY()); // ty
         }
 
-        // ************************************************************************************************************
-        // I've figured this out: the pattern is drawn only once over the page background and then sampled. PDFBOX-1094
-        // ************************************************************************************************************
-
-        // ****TODO****  This code works for tiling_pattern1 but not for PDFBOX-1094 (instrument the fill commands to find out why)
+        // TODO shouldn't create PageDrawer here, the class needs to be overridable
+        // can we re-use the existing PageDrawer somehow and just push/pop its graphics state?
 
-        // NEW HACK: ASSUME STREAM TRANSFORM IS IDENTITY
-        transform = AffineTransform.getScaleInstance(transform.getScaleX(), -transform.getScaleY()); // <--- HACK SCALING TAKEN FROM CTM (but should be from stream start)
-
-
-        // TODO supposed to be relative to the parent stream's initial CTM, not its current CTM
-        //patternMatrix.scale(transform.getScaleX(), -transform.getScaleY());
-        transform.preConcatenate(patternMatrix);
-
-        Matrix matrix = new Matrix();
-        matrix.setFromAffineTransform(transform); // !!
-
-        Graphics2D graphics = image.createGraphics();
-        PageDrawer drawer = new PageDrawer();
+        PageDrawer drawer = new PageDrawer(renderer);
         PDRectangle pdRect = new PDRectangle(0, 0, width, height);
 
-        // NEW HACK: this is usually done in drawPage
-        graphics.scale(1, -1);
-        graphics.translate(0, -height);
-
+        Graphics2D graphics = image.createGraphics();
         drawer.drawTilingPattern(graphics, pattern, pdRect, matrix, colorSpace, color);
         drawer.dispose();
         graphics.dispose();

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFPrinter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFPrinter.java?rev=1574811&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFPrinter.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFPrinter.java Thu Mar  6 09:05:08 2014
@@ -0,0 +1,221 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.pdfbox.rendering;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Pageable;
+import java.awt.print.Paper;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterIOException;
+import java.awt.print.PrinterJob;
+import java.io.IOException;
+
+/**
+ * Prints a PDF document using AWT.
+ * This class may be overridden in order to perform custom printing.
+ *
+ * @author Andreas Lehmkühler
+ * @author John Hewson
+ */
+public class PDFPrinter
+{
+    protected final PDDocument document;
+    protected final PDFRenderer renderer;
+    protected final PrinterJob printerJob;
+
+    /**
+     * Creates a new PDFPrinter.
+     * @param document the document to print
+     */
+    public PDFPrinter(PDDocument document) throws PrinterException
+    {
+        this(document, PrinterJob.getPrinterJob());
+    }
+
+    /**
+     * Creates a new PDFPrinter for a given printer job.
+     * @param document the document to print
+     * @param printerJob the printer job to use
+     */
+    public PDFPrinter(PDDocument document, PrinterJob printerJob) throws PrinterException
+    {
+        if (document == null)
+        {
+            throw new IllegalArgumentException("document");
+        }
+        else if (printerJob == null)
+        {
+            throw new IllegalArgumentException("printerJob");
+        }
+        else if (!document.getCurrentAccessPermission().canPrint())
+        {
+            throw new PrinterException("You do not have permission to print this document");
+        }
+        this.document = document;
+        this.renderer = new PDFRenderer(document);
+        this.printerJob = printerJob;
+    }
+
+    /**
+     * Prints the given document using the default printer without prompting the user.
+     * @throws java.awt.print.PrinterException if the document cannot be printed
+     */
+    public void silentPrint() throws PrinterException
+    {
+        silentPrint(PrinterJob.getPrinterJob());
+    }
+
+    /**
+     * Prints the given document using the default printer without prompting the user.
+     * @param printerJob a printer job definition
+     * @throws PrinterException if the document cannot be printed
+     */
+    public void silentPrint(PrinterJob printerJob) throws PrinterException
+    {
+        print(printerJob, true);
+    }
+
+    /**
+     * Prints the given document using the default printer without prompting the user.
+     * The image is generated using {@link PageDrawer}.
+     * This is a convenience method to create the java.awt.print.PrinterJob.
+     * Advanced printing tasks can be performed using {@link #getPageable()} instead.
+     * @throws PrinterException if the document cannot be printed
+     */
+    public void print() throws PrinterException
+    {
+        print(PrinterJob.getPrinterJob());
+    }
+
+    /**
+     * Prints the given document using the default printer without prompting the user.
+     * @param printerJob the printer job.
+     * @throws PrinterException if the document cannot be printed
+     */
+    public void print(PrinterJob printerJob) throws PrinterException
+    {
+        print(printerJob, false);
+    }
+
+    // todo: new
+    public PDFPageable getPageable()
+    {
+        return new PDFPageable();
+    }
+
+    // prints a document
+    private void print(PrinterJob job, boolean isSilent) throws PrinterException
+    {
+        if (job == null)
+        {
+            throw new IllegalArgumentException("job cannot be null");
+        }
+        else
+        {
+            job.setPageable(new PDFPageable());
+            if (isSilent || job.printDialog())
+            {
+                job.print();
+            }
+        }
+    }
+
+    protected class PDFPageable implements Pageable
+    {
+        @Override
+        public int getNumberOfPages()
+        {
+            return document.getNumberOfPages();
+        }
+
+        @Override
+        public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException
+        {
+            PageFormat format = printerJob.defaultPage();
+
+            PDPage page = document.getPage(pageIndex);
+            Dimension media = page.findMediaBox().createDimension();
+            Dimension crop = page.findCropBox().createDimension();
+
+            // Center the ImageableArea if the crop is smaller than the media
+            double diffWidth = 0.0;
+            double diffHeight = 0.0;
+            if (!media.equals(crop))
+            {
+                diffWidth = (media.getWidth() - crop.getWidth()) / 2.0;
+                diffHeight = (media.getHeight() - crop.getHeight()) / 2.0;
+            }
+
+            Paper paper = format.getPaper();
+            if (media.getWidth() < media.getHeight())
+            {
+                format.setOrientation(PageFormat.PORTRAIT);
+                paper.setImageableArea(diffWidth, diffHeight, crop.getWidth(), crop.getHeight());
+            }
+            else
+            {
+                format.setOrientation(PageFormat.LANDSCAPE);
+                paper.setImageableArea(diffHeight, diffWidth, crop.getHeight(), crop.getWidth());
+            }
+            format.setPaper(paper);
+
+            return format;
+        }
+
+        @Override
+        public Printable getPrintable(int i) throws IndexOutOfBoundsException
+        {
+            if (i >= getNumberOfPages())
+            {
+                throw new IndexOutOfBoundsException(i + " >= " +  getNumberOfPages());
+            }
+            return new PDFPrintable();
+        }
+    }
+
+    protected class PDFPrintable implements Printable
+    {
+        @Override
+        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
+                throws PrinterException
+        {
+            if (pageIndex < 0 || pageIndex >= document.getNumberOfPages())
+            {
+                return NO_SUCH_PAGE;
+            }
+
+            // draws to graphics using PDFRender
+            try
+            {
+                // TODO need to specify print DPI
+                renderer.renderPageToGraphics(pageIndex, (Graphics2D) graphics);
+                return PAGE_EXISTS;
+            }
+            catch (IOException io)
+            {
+                throw new PrinterIOException(io);
+            }
+        }
+    }
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java?rev=1574811&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PDFRenderer.java Thu Mar  6 09:05:08 2014
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.pdfbox.rendering;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+
+/**
+ * Renders a PDF document to an AWT BufferedImage.
+ * This class may be overridden in order to perform custom rendering.
+ *
+ * @author John Hewson
+ * @author Andreas Lehmkühler
+ */
+public class PDFRenderer
+{
+    protected final PDDocument document;
+    // TODO keep rendering state such as caches here
+
+    /**
+     * Creates a new PDFRenderer.
+     * @param document the document to render
+     */
+    public PDFRenderer(PDDocument document)
+    {
+        this.document = document;
+    }
+
+    /**
+     * Returns the given page as an RGB image at 72 DPI
+     * @param pageIndex the zero-based index of the page to be converted.
+     * @return the rendered page image
+     * @throws IOException if the PDF cannot be read
+     */
+    public BufferedImage renderImage(int pageIndex) throws IOException
+    {
+        return renderImage(pageIndex, 1);
+    }
+
+    /**
+     * Returns the given page as an RGB image at the given scale.
+     * A scale of 1 will render at 72 DPI.
+     * @param pageIndex the zero-based index of the page to be converted
+     * @param scale the scaling factor, where 1 = 72 DPI
+     * @return the rendered page image
+     * @throws IOException if the PDF cannot be read
+     */
+    public BufferedImage renderImage(int pageIndex, float scale) throws IOException
+    {
+        return renderImage(pageIndex, scale, false);
+    }
+
+    /**
+     * Returns the given page as an RGB or ARGB image at the given scale.
+     * @param pageIndex the zero-based index of the page to be converted
+     * @param scale the scaling factor, where 1 = 72 DPI
+     * @param useAlpha true if an ARGB image is to be returned
+     * @return the rendered page image
+     * @throws IOException if the PDF cannot be read
+     */
+    public BufferedImage renderImage(int pageIndex, float scale, boolean useAlpha)
+            throws IOException
+    {
+        PDPage page = document.getPage(pageIndex);
+
+        PDRectangle cropBox = page.findCropBox();
+        float widthPt = cropBox.getWidth();
+        float heightPt = cropBox.getHeight();
+        int widthPx = Math.round(widthPt * scale);
+        int heightPx = Math.round(heightPt * scale);
+        int rotationAngle = page.findRotation();
+
+        // normalize the rotation angle
+        if (rotationAngle < 0)
+        {
+            rotationAngle += 360;
+        }
+        else if (rotationAngle >= 360)
+        {
+            rotationAngle -= 360;
+        }
+
+        int imageType = useAlpha ?
+                BufferedImage.TYPE_INT_ARGB :
+                BufferedImage.TYPE_INT_RGB;
+
+        // swap width and height
+        BufferedImage image;
+        if (rotationAngle == 90 || rotationAngle == 270)
+        {
+            image = new BufferedImage(heightPx, widthPx, imageType);
+        }
+        else
+        {
+            image = new BufferedImage(widthPx, heightPx, imageType);
+        }
+
+        // use a transparent background if the imageType supports alpha
+        Graphics2D g = image.createGraphics();
+        if (!useAlpha)
+        {
+            g.setBackground(Color.WHITE);
+        }
+
+        renderPage(page, g, image.getWidth(), image.getHeight(), scale, scale);
+        g.dispose();
+
+        return image;
+    }
+
+    /**
+     * Renders a given page to an AWT Graphics2D instance.
+     * @param pageIndex the zero-based index of the page to be converted
+     * @param graphics the Graphics2D on which to draw the page
+     * @throws IOException if the PDF cannot be read
+     */
+    public void renderPageToGraphics(int pageIndex, Graphics2D graphics) throws IOException
+    {
+        PDPage page = document.getPage(pageIndex);
+        // TODO need width/wight calculations? should these be in PageDrawer?
+        PDRectangle cropBox = page.findCropBox();
+        renderPage(page, graphics, (int)cropBox.getWidth(), (int)cropBox.getHeight(), 1f, 1f);
+    }
+
+    // renders a page to the given graphics
+    // TODO need to be able to override this
+    private void renderPage(PDPage page, Graphics2D graphics, int width, int height, float scaleX,
+                            float scaleY) throws IOException
+    {
+        graphics.clearRect(0, 0, width, height);
+        int rotationAngle = page.findRotation();
+        if (rotationAngle != 0)
+        {
+            int translateX = 0;
+            int translateY = 0;
+            switch (rotationAngle)
+            {
+            case 90:
+                translateX = width;
+                break;
+            case 270:
+                translateY = height;
+                break;
+            case 180:
+                translateX = width;
+                translateY = height;
+                break;
+            default:
+                break;
+            }
+            graphics.translate(translateX, translateY);
+            graphics.rotate((float) Math.toRadians(rotationAngle));
+        }
+        // TODO should we be passing the scale to PageDrawer rather than messing with Graphics?
+        graphics.scale(scaleX, scaleY);
+        PageDrawer drawer = new PageDrawer(this);   // TODO: need to make it easy to use a custom PageDrawer
+        drawer.drawPage(graphics, page, page.findCropBox());
+        drawer.dispose();
+    }
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1574811&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Thu Mar  6 09:05:08 2014
@@ -0,0 +1,876 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.pdfbox.rendering;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.RenderingHints;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fontbox.cff.CFFFont;
+import org.apache.fontbox.ttf.TrueTypeFont;
+import org.apache.fontbox.type1.Type1Font;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdfviewer.font.Glyph2D;
+import org.apache.pdfbox.pdfviewer.font.TTFGlyph2D;
+import org.apache.pdfbox.pdfviewer.font.Type1Glyph2D;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDMatrix;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.font.FontManager;
+import org.apache.pdfbox.pdmodel.font.PDCIDFontType0Font;
+import org.apache.pdfbox.pdmodel.font.PDCIDFontType2Font;
+import org.apache.pdfbox.pdmodel.font.PDFont;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptor;
+import org.apache.pdfbox.pdmodel.font.PDFontDescriptorDictionary;
+import org.apache.pdfbox.pdmodel.font.PDSimpleFont;
+import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont;
+import org.apache.pdfbox.pdmodel.font.PDType0Font;
+import org.apache.pdfbox.pdmodel.font.PDType1CFont;
+import org.apache.pdfbox.pdmodel.font.PDType1Font;
+import org.apache.pdfbox.pdmodel.font.PDType3Font;
+import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
+import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
+import org.apache.pdfbox.pdmodel.graphics.shading.AxialShadingPaint;
+import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
+import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType2;
+import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType3;
+import org.apache.pdfbox.pdmodel.graphics.shading.RadialShadingPaint;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.apache.pdfbox.pdmodel.graphics.state.PDTextState;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.PDFStreamEngine;
+import org.apache.pdfbox.util.ResourceLoader;
+import org.apache.pdfbox.util.TextPosition;
+
+/**
+ * This will paint a page in a PDF document to a graphics context.
+ * 
+ * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
+ * 
+ */
+public class PageDrawer extends PDFStreamEngine
+{
+    private static final Log LOG = LogFactory.getLog(PageDrawer.class);
+    private static final Color COLOR_TRANSPARENT = new Color(0, 0, 0, 0);
+
+    // parent document renderer
+    private final PDFRenderer renderer;
+
+    private Graphics2D graphics;
+
+    // clipping winding rule used for the clipping path.
+    private int clippingWindingRule = -1;
+
+    private GeneralPath linePath = new GeneralPath();
+
+    private Map<PDFont, Glyph2D> fontGlyph2D = new HashMap<PDFont, Glyph2D>();
+    private Map<PDFont, Font> awtFonts = new HashMap<PDFont, Font>();
+
+    private int pageHeight;
+    
+    /**
+     * Default constructor, loads properties from file.
+     * 
+     * @throws IOException If there is an error loading properties from the file.
+     */
+    public PageDrawer(PDFRenderer renderer) throws IOException
+    {
+        super(ResourceLoader.loadProperties("org/apache/pdfbox/resources/PageDrawer.properties", true));
+        this.renderer = renderer;
+    }
+
+    /**
+     * Returns the parent renderer.
+     * @return the parent renderer.
+     */
+    public PDFRenderer getRenderer()
+    {
+        return renderer;
+    }
+
+    /**
+     * This will draw the page to the requested context.
+     * 
+     * @param g The graphics context to draw onto.
+     * @param page The page to draw.
+     * @param pageSize The size of the page to draw.
+     * 
+     * @throws IOException If there is an IO error while drawing the page.
+     */
+    public void drawPage(Graphics g, PDPage page, PDRectangle pageSize) throws IOException
+    {
+        graphics = (Graphics2D) g;
+        pageHeight = (int)pageSize.getHeight();
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+        graphics.translate(0, pageHeight);
+        graphics.scale(1, -1);
+        // TODO use getStroke() to set the initial stroke
+        graphics.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
+
+        // Only if there is some content, we have to process it.
+        // Otherwise we are done here and we will produce an empty page
+        if (page.getContents() != null)
+        {
+            PDResources resources = page.findResources();
+            processStream(resources, page.getContents().getStream(), page.findCropBox(), page.findRotation());
+        }
+
+        List<PDAnnotation> annotations = page.getAnnotations();
+        for (int i = 0; i < annotations.size(); i++)
+        {
+            PDAnnotation annot = (PDAnnotation) annotations.get(i);
+            PDRectangle rect = annot.getRectangle();
+            String appearanceName = annot.getAppearanceStream();
+            PDAppearanceDictionary appearDictionary = annot.getAppearance();
+            if (appearDictionary != null)
+            {
+                if (appearanceName == null)
+                {
+                    appearanceName = "default";
+                }
+                Map<String, PDAppearanceStream> appearanceMap = appearDictionary.getNormalAppearance();
+                if (appearanceMap != null)
+                {
+                    PDAppearanceStream appearance = (PDAppearanceStream) appearanceMap.get(appearanceName);
+                    if (appearance != null)
+                    {
+                        Point2D point = new Point2D.Float(rect.getLowerLeftX(), rect.getLowerLeftY());
+                        Matrix matrix = appearance.getMatrix();
+                        if (matrix != null)
+                        {
+                            // transform the rectangle using the given matrix
+                            AffineTransform at = matrix.createAffineTransform();
+                            at.scale(1, -1);
+                            at.transform(point, point);
+                        }
+                        graphics.translate((int) point.getX(), -(int) point.getY());
+                        processSubStream(appearance.getResources(), appearance.getStream());
+                        graphics.translate(-(int) point.getX(), (int) point.getY());
+                    }
+                }
+            }
+        }
+        graphics = null;
+    }
+
+    /**
+     * This will draw the pattern stream to the requested context.
+     *
+     * @param g The graphics context to draw onto.
+     * @param pattern The tiling pattern to be used.
+     * @param pageDimension The size of the page to draw.
+     * @throws IOException If there is an IO error while drawing the page.
+     */
+    public void drawTilingPattern(Graphics2D g, PDTilingPattern pattern, PDRectangle pageDimension,
+                                  Matrix matrix, PDColorSpace colorSpace, PDColor color)
+                                  throws IOException
+    {
+        graphics = g;
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+        initStream(pageDimension, 0);
+
+        // transform ctm
+        Matrix concat = getGraphicsState().getCurrentTransformationMatrix().multiply(matrix);
+        getGraphicsState().setCurrentTransformationMatrix(concat);
+
+        // color
+        if (colorSpace != null)
+        {
+            getGraphicsState().setNonStrokingColorSpace(colorSpace);
+            getGraphicsState().setNonStrokingColor(color);
+            getGraphicsState().setStrokingColorSpace(colorSpace);
+            getGraphicsState().setStrokingColor(color);
+        }
+
+        processSubStream(pattern.getResources(), (COSStream)pattern.getCOSObject());
+    }
+
+    /**
+     * Remove all cached resources.
+     */
+    public void dispose()
+    {
+        super.dispose();
+        if (fontGlyph2D != null)
+        {
+            Iterator<Glyph2D> iter = fontGlyph2D.values().iterator();
+            while (iter.hasNext())
+            {
+                iter.next().dispose();
+            }
+            fontGlyph2D.clear();
+            fontGlyph2D = null;
+        }
+        if (awtFonts != null)
+        {
+            awtFonts.clear();
+        }
+        graphics = null;
+        linePath = null;
+    }
+
+    /**
+     * You should override this method if you want to perform an action when a text is being processed.
+     * 
+     * @param text The text to process
+     */
+    protected void processTextPosition(TextPosition text)
+    {
+        try
+        {
+            PDGraphicsState graphicsState = getGraphicsState();
+            Composite composite;
+            Paint paint;
+            switch (graphicsState.getTextState().getRenderingMode())
+            {
+            case PDTextState.RENDERING_MODE_FILL_TEXT:
+                composite = graphicsState.getNonStrokeJavaComposite();
+                paint = getNonStrokingPaint();
+                break;
+            case PDTextState.RENDERING_MODE_STROKE_TEXT:
+                composite = graphicsState.getStrokeJavaComposite();
+                paint = getStrokingPaint();
+                break;
+            case PDTextState.RENDERING_MODE_NEITHER_FILL_NOR_STROKE_TEXT:
+                // basic support for text rendering mode "invisible"
+                // TODO why are we drawing anything at all?
+                paint = COLOR_TRANSPARENT;
+                composite = graphicsState.getStrokeJavaComposite();
+                break;
+            default:
+                // TODO : need to implement....
+                LOG.debug("Unsupported RenderingMode " + this.getGraphicsState().getTextState().getRenderingMode()
+                        + " in PageDrawer.processTextPosition()." + " Using RenderingMode "
+                        + PDTextState.RENDERING_MODE_FILL_TEXT + " instead");
+                composite = graphicsState.getNonStrokeJavaComposite();
+                paint = getNonStrokingPaint();
+            }
+            graphics.setComposite(composite);
+            graphics.setPaint(paint);
+
+            PDFont font = text.getFont();
+            AffineTransform at = text.getTextPos().createAffineTransform();
+            PDMatrix fontMatrix = font.getFontMatrix();
+            // TODO setClip() is a massive performance hot spot. Investigate optimization possibilities
+            graphics.setClip(graphicsState.getCurrentClippingPath());
+
+            // use different methods to draw the string
+            if (font.isType3Font())
+            {
+                // Type3 fonts don't use the same units within the font matrix as all the other fonts
+                at.scale(fontMatrix.getValue(0, 0), fontMatrix.getValue(1, 1));
+                // Type3 fonts are using streams for each character
+                drawType3String((PDType3Font) font, text, at);
+            }
+            else
+            {
+                Glyph2D glyph2D = createGlyph2D(font);
+                if (glyph2D != null)
+                {
+                    AffineTransform fontMatrixAT = new AffineTransform(fontMatrix.getValue(0, 0), fontMatrix.getValue(
+                            0, 1), fontMatrix.getValue(1, 0), fontMatrix.getValue(1, 1), fontMatrix.getValue(2, 0),
+                            fontMatrix.getValue(2, 1));
+                    at.concatenate(fontMatrixAT);
+                    // Let PDFBox render the font if supported
+                    drawGlyph2D(glyph2D, text.getCodePoints(), at);
+                }
+                else
+                {
+                    // Use AWT to render the font (standard14 fonts, substituted embedded fonts)
+                    // TODO to be removed in the long run
+                    drawString((PDSimpleFont) font, text.getCharacter(), at);
+                }
+            }
+        }
+        catch (IOException io)
+        {
+            io.printStackTrace();
+        }
+    }
+
+    /**
+     * Render the font using the Glyph2d interface.
+     * 
+     * @param glyph2D the Glyph2D implementation provided a GeneralPath for each glyph
+     * @param codePoints the string to be rendered
+     * @param at the transformation
+     * @throws IOException if something went wrong
+     */
+    private void drawGlyph2D(Glyph2D glyph2D, int[] codePoints, AffineTransform at) throws IOException
+    {
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        for (int i = 0; i < codePoints.length; i++)
+        {
+            GeneralPath path = glyph2D.getPathForCharacterCode(codePoints[i]);
+            if (path != null)
+            {
+                AffineTransform atInverse = null;
+                if (!at.isIdentity())
+                {
+                    try
+                    {
+                        atInverse = at.createInverse();
+                    }
+                    catch (NoninvertibleTransformException exception)
+                    {
+                        LOG.error("Can't invert the given affine transformation", exception);
+                    }
+                }
+                if (atInverse != null)
+                {
+                    graphics.transform(at);
+                }
+                graphics.fill(path);
+                if (atInverse != null)
+                {
+                    graphics.transform(atInverse);
+                }
+            }
+        }
+    }
+
+    /**
+     * Render the text using a type 3 font.
+     * 
+     * @param font the type3 font
+     * @param text the text to be rendered
+     * @param at the transformation
+     * 
+     * @throws IOException if something went wrong
+     */
+    private void drawType3String(PDType3Font font, TextPosition text, AffineTransform at) throws IOException
+    {
+        int[] codePoints = text.getCodePoints();
+        int textLength = codePoints.length;
+        for (int i = 0; i < textLength; i++)
+        {
+            COSStream stream = font.getCharStream((char)codePoints[i]);
+            if (stream != null)
+            {
+                // save the current graphics state
+                getGraphicsStack().push((PDGraphicsState) getGraphicsState().clone());
+
+                Matrix ctm = new Matrix();
+                ctm.setFromAffineTransform(at);
+                getGraphicsState().setCurrentTransformationMatrix(ctm);
+                processSubStream(font.getType3Resources(), stream);
+
+                // restore the saved graphics state
+                setGraphicsState(getGraphicsStack().pop());
+            }
+            else
+            {
+                LOG.debug("drawType3String: stream for character " + (char)codePoints[i] + " not found");
+            }
+        }
+    }
+
+    /**
+     * This will draw a string on a canvas using the font.
+     *
+     * @param font the font to be used to draw the string
+     * @param string The string to draw.
+     * @param at The transformation matrix with all information for scaling and shearing of the font.
+     *
+     * @throws IOException If there is an error drawing the specific string.
+     */
+    private void drawString(PDSimpleFont font, String string, AffineTransform at) throws IOException
+    {
+        Font awtFont = createAWTFont(font);
+        FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true);
+        GlyphVector glyphs = awtFont.createGlyphVector(frc, string);
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        writeFont(at, glyphs);
+    }
+
+    private void writeFont(final AffineTransform at, final GlyphVector glyphs)
+    {
+        try
+        {
+            // Convert from PDF, where glyphs are upright when direction is from
+            // bottom to top, to AWT, where this is the other way around
+            at.scale(1, -1);
+            AffineTransform atInverse = at.createInverse();
+            graphics.transform(at);
+            graphics.drawGlyphVector(glyphs, 0, 0);
+            graphics.transform(atInverse);
+        }
+        catch (NoninvertibleTransformException exception)
+        {
+            LOG.error("Can't invert the given affine transformation", exception);
+        }
+    }
+
+    /**
+     * Provides an AWT font for the given PDFont.
+     * 
+     * @param font the font which needs an AWT font
+     * @return the corresponding AWT font
+     * @throws IOException if something went wrong
+     */
+    private Font createAWTFont(PDSimpleFont font) throws IOException
+    {
+        Font awtFont = null;
+        // Is there already a AWTFont for the given font?
+        if (awtFonts.containsKey(font))
+        {
+            awtFont = awtFonts.get(font);
+        }
+        else
+        {
+            if (font instanceof PDType1Font)
+            {
+                PDType1Font type1Font = (PDType1Font) font;
+                PDFontDescriptor fd = type1Font.getFontDescriptor();
+                if (fd instanceof PDFontDescriptorDictionary)
+                {
+                    PDFontDescriptorDictionary fdDictionary = (PDFontDescriptorDictionary) fd;
+                    if (fdDictionary.getFontFile() == null)
+                    {
+                        // check if the font is part of our environment
+                        if (fd.getFontName() != null)
+                        {
+                            awtFont = FontManager.getAwtFont(fd.getFontName());
+                        }
+                        if (awtFont != null)
+                        {
+                            type1Font.setIsFontSubstituted(true);
+                        }
+                        else
+                        {
+                            LOG.info("Can't find the specified font " + fd.getFontName());
+                        }
+                    }
+                }
+                else
+                {
+                    // check if the font is part of our environment
+                    String baseFont = type1Font.getBaseFont();
+                    awtFont = FontManager.getAwtFont(baseFont);
+                    if (awtFont == null)
+                    {
+                        LOG.info("Can't find the specified basefont " + baseFont);
+                    }
+                }
+            }
+            else
+            {
+                LOG.info("Unsupported type of font " + font.getClass().getName());
+            }
+            if (awtFont == null)
+            {
+                // Fallback: we can't find anything, so we have to use the standard font
+                awtFont = FontManager.getStandardFont();
+                LOG.info("Using font " + awtFont.getName() + " instead of " + font.getBaseFont());
+                font.setIsFontSubstituted(true);
+            }
+            awtFonts.put(font, awtFont);
+        }
+        return awtFont;
+    }
+
+    /**
+     * Provide a Glyph2D for the given font.
+     * 
+     * @param font the font
+     * @return the implementation of the Glyph2D interface for the given font
+     * @throws IOException if something went wrong
+     */
+    private Glyph2D createGlyph2D(PDFont font) throws IOException
+    {
+        Glyph2D glyph2D = null;
+        // Is there already a Glyph2D for the given font?
+        if (fontGlyph2D.containsKey(font))
+        {
+            glyph2D = fontGlyph2D.get(font);
+        }
+        else
+        {
+            // check if the given font is supported
+            if (font instanceof PDTrueTypeFont)
+            {
+                PDTrueTypeFont ttfFont = (PDTrueTypeFont) font;
+                // get the true type font raw data
+                TrueTypeFont ttf = ttfFont.getTTFFont();
+                if (ttf != null)
+                {
+                    glyph2D = new TTFGlyph2D(ttf, font);
+                }
+            }
+            else if (font instanceof PDType1Font)
+            {
+                PDType1Font pdType1Font = (PDType1Font) font;
+                PDType1CFont type1CFont = pdType1Font.getType1CFont();
+                if (type1CFont != null)
+                {
+                    // get the cffFont raw data
+                    CFFFont cffFont = type1CFont.getCFFFont();
+                    if (cffFont != null)
+                    {
+                        glyph2D = new Type1Glyph2D(cffFont, type1CFont.getFontEncoding());
+                    }
+                }
+                else
+                {
+                    // get the pfb raw data
+                    Type1Font type1Font = pdType1Font.getType1Font();
+                    if (type1Font != null)
+                    {
+                        glyph2D = new Type1Glyph2D(type1Font, pdType1Font.getFontEncoding());
+                    }
+                }
+            }
+            else if (font instanceof PDType0Font)
+            {
+                PDType0Font type0Font = (PDType0Font) font;
+                if (type0Font.getDescendantFont() instanceof PDCIDFontType2Font)
+                {
+                    // a CIDFontType2Font contains TTF font
+                    PDCIDFontType2Font cidType2Font = (PDCIDFontType2Font) type0Font.getDescendantFont();
+                    // get the true type font raw data
+                    TrueTypeFont ttf = cidType2Font.getTTFFont();
+                    if (ttf != null)
+                    {
+                        glyph2D = new TTFGlyph2D(ttf, font, cidType2Font);
+                    }
+                }
+                else if (type0Font.getDescendantFont() instanceof PDCIDFontType0Font)
+                {
+                    // a CIDFontType2Font contains TTF font
+                    PDCIDFontType0Font cidType2Font = (PDCIDFontType0Font) type0Font.getDescendantFont();
+                    PDType1CFont type1CFont = cidType2Font.getType1CFont();
+                    if (type1CFont != null)
+                    {
+                        // get the cffFont raw data
+                        CFFFont cffFont = type1CFont.getCFFFont();
+                        if (cffFont != null)
+                        {
+                            glyph2D = new Type1Glyph2D(cffFont, type1CFont.getFontEncoding());
+                        }
+                    }
+                }
+            }
+            // cache the Glyph2D instance
+            if (glyph2D != null)
+            {
+                fontGlyph2D.put(font, glyph2D);
+            }
+        }
+        return glyph2D;
+    }
+
+    /**
+     * Get the current line path to be drawn.
+     * 
+     * @return The current line path to be drawn.
+     */
+    public GeneralPath getLinePath()
+    {
+        return linePath;
+    }
+
+    // returns the stroking AWT Paint
+    private Paint getStrokingPaint() throws IOException
+    {
+        return getGraphicsState().getStrokingColorSpace()
+                .toPaint(renderer, getGraphicsState().getStrokingColor(), pageHeight);
+    }
+
+    // returns the non-stroking AWT Paint
+    private Paint getNonStrokingPaint() throws IOException
+    {
+        return getGraphicsState().getNonStrokingColorSpace()
+                .toPaint(renderer, getGraphicsState().getNonStrokingColor(), pageHeight);
+    }
+
+    // create a new stroke based on the current CTM and the current stroke
+    private BasicStroke getStroke()
+    {
+        PDGraphicsState state = getGraphicsState();
+
+        // apply the CTM
+        float lineWidth = transformWidth(state.getLineWidth());
+
+        // minimum line width as used by Adobe Reader
+        if (lineWidth < 0.25)
+        {
+            lineWidth = 0.25f;
+        }
+
+        PDLineDashPattern dashPattern = state.getLineDashPattern();
+        int phaseStart = dashPattern.getPhase();
+        float[] dashArray = dashPattern.getDashArray();
+        if (dashArray != null)
+        {
+            // apply the CTM
+            for (int i = 0; i < dashArray.length; ++i)
+            {
+                dashArray[i] = transformWidth(dashArray[i]);
+            }
+            phaseStart = (int)transformWidth(phaseStart);
+
+            // empty dash array is illegal
+            if (dashArray.length == 0)
+            {
+                dashArray = null;
+            }
+        }
+        return new BasicStroke(lineWidth, state.getLineCap(), state.getLineJoin(),
+                               state.getMiterLimit(), dashArray, phaseStart);
+    }
+
+    /**
+     * Stroke the path.
+     * 
+     * @throws IOException If there is an IO error while stroking the path.
+     */
+    public void strokePath() throws IOException
+    {
+        graphics.setComposite(getGraphicsState().getStrokeJavaComposite());
+        Paint strokingPaint = getStrokingPaint();
+        if (strokingPaint == null)
+        {
+            LOG.info("ColorSpace " + getGraphicsState().getStrokingColorSpace().getName() +
+                     " doesn't provide a stroking color, using white instead!");
+            strokingPaint = Color.WHITE;// ((PageDrawer)context).strokePath();
+        }
+        graphics.setPaint(strokingPaint);
+        graphics.setStroke(getStroke());
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        graphics.draw(linePath);
+        linePath.reset();
+    }
+
+    /**
+     * Fill the path.
+     *
+     * @param windingRule The winding rule this path will use.
+     *
+     * @throws IOException If there is an IO error while filling the path.
+     */
+    public void fillPath(int windingRule) throws IOException
+    {
+        graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite());
+        Paint nonStrokingPaint = getNonStrokingPaint();
+        if (nonStrokingPaint == null)
+        {
+            LOG.info("ColorSpace " + getGraphicsState().getNonStrokingColorSpace().getName() +
+                    " doesn't provide a non-stroking color, using white instead!");
+            nonStrokingPaint = Color.WHITE;
+        }
+        graphics.setPaint(nonStrokingPaint);
+        linePath.setWindingRule(windingRule);
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        graphics.fill(linePath);
+        linePath.reset();
+    }
+
+    /**
+     * Strokes and fills the path.
+     *
+     * @param windingRule The winding rule this path will use.
+     *
+     * @throws IOException If there is an IO error while filling the path.
+     */
+    public void strokeAndFillPath(int windingRule) throws IOException
+    {
+        // TODO can we avoid cloning the path?
+        GeneralPath path = (GeneralPath)linePath.clone();
+        strokePath();
+        linePath = path;
+        fillPath(windingRule);
+    }
+
+    // This code generalizes the code Jim Lynch wrote for AppendRectangleToPath
+    /**
+     * use the current transformation matrix to transform a single point.
+     *
+     * @param x x-coordinate of the point to be transform
+     * @param y y-coordinate of the point to be transform
+     * @return the transformed coordinates as Point2D.Double
+     */
+    public Point2D.Double transformedPoint(double x, double y)
+    {
+        double[] position = { x, y };
+        getGraphicsState().getCurrentTransformationMatrix().createAffineTransform()
+                .transform(position, 0, position, 0, 1);
+        return new Point2D.Double(position[0], position[1]);
+    }
+
+    // transforms a width using the CTM
+    private float transformWidth(float width)
+    {
+        Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
+
+        if (ctm == null)
+        {
+            // TODO does the CTM really need to use null?
+            return width;
+        }
+
+        float x = ctm.getValue(0, 0) + ctm.getValue(1, 0);
+        float y = ctm.getValue(0, 1) + ctm.getValue(1, 1);
+        return width * (float)Math.sqrt((x * x + y * y) * 0.5);
+    }
+
+    /**
+     * Set the clipping Path.
+     * 
+     * @param windingRule The winding rule this path will use.
+     * 
+     * @deprecated use {@link #setClippingWindingRule(int)} instead
+     * 
+     */
+    public void setClippingPath(int windingRule)
+    {
+        setClippingWindingRule(windingRule);
+    }
+
+    /**
+     * Set the clipping winding rule.
+     * 
+     * @param windingRule The winding rule which will be used for clipping.
+     * 
+     */
+    public void setClippingWindingRule(int windingRule)
+    {
+        clippingWindingRule = windingRule;
+    }
+
+    /**
+     * Set the clipping Path.
+     * 
+     */
+    public void endPath()
+    {
+        if (clippingWindingRule > -1)
+        {
+            PDGraphicsState graphicsState = getGraphicsState();
+            GeneralPath clippingPath = (GeneralPath) linePath.clone();  // TODO do we really need to clone this? isn't the line path reset anyway?
+            clippingPath.setWindingRule(clippingWindingRule);
+            // If there is already set a clipping path, we have to intersect the new with the existing one
+            if (graphicsState.getCurrentClippingPath() != null)
+            {
+                Area currentArea = new Area(getGraphicsState().getCurrentClippingPath());
+                Area newArea = new Area(clippingPath);
+                currentArea.intersect(newArea);
+                graphicsState.setCurrentClippingPath(currentArea);
+            }
+            else
+            {
+                graphicsState.setCurrentClippingPath(clippingPath);
+            }
+            clippingWindingRule = -1;
+        }
+        linePath.reset();
+    }
+
+    /**
+     * Draw the AWT image. Called by Invoke. Moved into PageDrawer so that Invoke doesn't have to reach in here for
+     * Graphics as that breaks extensibility.
+     * 
+     * @param awtImage The image to draw.
+     * @param at The transformation to use when drawing.
+     * 
+     */
+    public void drawImage(Image awtImage, AffineTransform at)
+    {
+        graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite());
+        graphics.setClip(getGraphicsState().getCurrentClippingPath());
+        int width = awtImage.getWidth(null);
+        int height = awtImage.getHeight(null);
+        AffineTransform imageTransform = new AffineTransform(at);
+        imageTransform.scale(1.0 / width, -1.0 / height);
+        imageTransform.translate(0, -height);
+        graphics.drawImage(awtImage, imageTransform, null);
+    }
+
+    /**
+     * Fill with Shading. Called by SHFill operator.
+     * 
+     * @param shadingName The name of the Shading Dictionary to use for this fill instruction.
+     * 
+     * @throws IOException If there is an IO error while shade-filling the clipping area.
+     */
+    // TODO would this now be better off using PDPattern?
+    public void shFill(COSName shadingName) throws IOException
+    {
+        PDShading shading = getResources().getShadings().get(shadingName.getName());
+        LOG.debug("Shading = " + shading.toString());
+        int shadingType = shading.getShadingType();
+        Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
+        Paint paint = null;
+        switch (shadingType)
+        {
+        case 1:
+            // TODO
+            LOG.debug("Function based shading not yet supported");
+            break;
+        case 2:
+            paint = new AxialShadingPaint((PDShadingType2) shading, ctm, pageHeight);
+            break;
+        case 3:
+            paint = new RadialShadingPaint((PDShadingType3) shading, ctm, pageHeight);
+            break;
+        case 4:
+        case 5:
+        case 6:
+        case 7:
+            // TODO
+            LOG.debug("Shading type " + shadingType + " not yet supported");
+            break;
+        default:
+            throw new IOException("Invalid ShadingType " + shadingType + " for Shading " + shadingName);
+        }
+        graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite());
+        graphics.setPaint(paint);
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+        graphics.fill(getGraphicsState().getCurrentClippingPath());
+    }
+}

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/ImageIOUtil.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/ImageIOUtil.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/ImageIOUtil.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/ImageIOUtil.java Thu Mar  6 09:05:08 2014
@@ -80,15 +80,13 @@ public class ImageIOUtil
      * @param image the image to be written
      * @param imageFormat the target format (ex. "png")
      * @param filename used to construct the filename for the individual images
-     * @param imageType the image type (see {@link BufferedImage}.TYPE_*)
      * @param resolution the resolution in dpi (dots per inch)
      * 
      * @return true if the images were produced, false if there was an error
      * @throws IOException if an I/O error occurs
      */
-    public static boolean writeImage(BufferedImage image, String imageFormat, String filename, 
-            int imageType, int resolution)
-    throws IOException
+    public static boolean writeImage(BufferedImage image, String imageFormat, String filename,
+                                     int resolution) throws IOException
     {
         String fileName = filename + "." + imageFormat;
         File file = new File(fileName);
@@ -105,8 +103,8 @@ public class ImageIOUtil
      * @return true if the images were produced, false if there was an error
      * @throws IOException if an I/O error occurs
      */
-    public static boolean writeImage(BufferedImage image, String imageFormat, OutputStream outputStream) 
-    throws IOException
+    public static boolean writeImage(BufferedImage image, String imageFormat,
+                                     OutputStream outputStream) throws IOException
     {
         return writeImage(image, imageFormat, outputStream, DEFAULT_SCREEN_RESOLUTION);
     }
@@ -122,8 +120,8 @@ public class ImageIOUtil
      * @return true if the images were produced, false if there was an error
      * @throws IOException if an I/O error occurs
      */
-    public static boolean writeImage(BufferedImage image, String imageFormat, Object outputStream, int resolution)
-    throws IOException
+    public static boolean writeImage(BufferedImage image, String imageFormat, Object outputStream,
+                                     int resolution) throws IOException
     {
         return writeImage(image, imageFormat, outputStream, resolution, DEFAULT_COMPRESSION_QUALITY);
     }
@@ -141,9 +139,8 @@ public class ImageIOUtil
      * @return true if the images were produced, false if there was an error
      * @throws IOException if an I/O error occurs
      */
-    public static boolean writeImage(BufferedImage image, String imageFormat, Object outputStream, int resolution, 
-            float quality)
-    throws IOException
+    public static boolean writeImage(BufferedImage image, String imageFormat, Object outputStream,
+                                     int resolution, float quality) throws IOException
     {
         boolean bSuccess = true;
         ImageOutputStream output = null;

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/AppendRectangleToPath.java Thu Mar  6 09:05:08 2014
@@ -22,7 +22,7 @@ import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/BeginInlineImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/BeginInlineImage.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/BeginInlineImage.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/BeginInlineImage.java Thu Mar  6 09:05:08 2014
@@ -21,7 +21,7 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
 import org.apache.pdfbox.pdmodel.graphics.image.PDInlineImage;
@@ -50,7 +50,7 @@ public final class BeginInlineImage exte
         {
             PDColorSpace colorSpace = drawer.getGraphicsState().getNonStrokingColorSpace();
             PDColor color = drawer.getGraphicsState().getNonStrokingColor();
-            awtImage = image.getStencilImage(colorSpace.toPaint(color)); // <--- TODO: pass page height?
+            awtImage = image.getStencilImage(colorSpace.toPaint(drawer.getRenderer(), color)); // <--- TODO: pass page height?
         }
         else
         {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipEvenOddRule.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipEvenOddRule.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipEvenOddRule.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipEvenOddRule.java Thu Mar  6 09:05:08 2014
@@ -20,7 +20,7 @@ import java.awt.geom.GeneralPath;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipNonZeroRule.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipNonZeroRule.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipNonZeroRule.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClipNonZeroRule.java Thu Mar  6 09:05:08 2014
@@ -20,7 +20,7 @@ import java.awt.geom.GeneralPath;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClosePath.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClosePath.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClosePath.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/ClosePath.java Thu Mar  6 09:05:08 2014
@@ -19,7 +19,7 @@ package org.apache.pdfbox.util.operator.
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveTo.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveTo.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveTo.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveTo.java Thu Mar  6 09:05:08 2014
@@ -21,7 +21,7 @@ import java.awt.geom.Point2D;
 
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalPoint.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalPoint.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalPoint.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateFinalPoint.java Thu Mar  6 09:05:08 2014
@@ -21,7 +21,7 @@ import java.awt.geom.Point2D;
 
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitialPoint.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitialPoint.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitialPoint.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/CurveToReplicateInitialPoint.java Thu Mar  6 09:05:08 2014
@@ -22,7 +22,7 @@ import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/EndPath.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/EndPath.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/EndPath.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/EndPath.java Thu Mar  6 09:05:08 2014
@@ -19,7 +19,7 @@ package org.apache.pdfbox.util.operator.
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePath.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePath.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePath.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddAndStrokePath.java Thu Mar  6 09:05:08 2014
@@ -19,7 +19,7 @@ package org.apache.pdfbox.util.operator.
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddRule.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddRule.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddRule.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillEvenOddRule.java Thu Mar  6 09:05:08 2014
@@ -21,7 +21,7 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePath.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePath.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePath.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroAndStrokePath.java Thu Mar  6 09:05:08 2014
@@ -19,7 +19,7 @@ package org.apache.pdfbox.util.operator.
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroRule.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroRule.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroRule.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/FillNonZeroRule.java Thu Mar  6 09:05:08 2014
@@ -21,7 +21,7 @@ import java.io.IOException;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java Thu Mar  6 09:05:08 2014
@@ -28,7 +28,7 @@ import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.filter.MissingImageReaderException;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
@@ -71,7 +71,7 @@ public final class Invoke extends Operat
                 {
                     PDColorSpace colorSpace = drawer.getGraphicsState().getNonStrokingColorSpace();
                     PDColor color = drawer.getGraphicsState().getNonStrokingColor();
-                    awtImage = image.getStencilImage(colorSpace.toPaint(color)); // <--- TODO: pass page height?
+                    awtImage = image.getStencilImage(colorSpace.toPaint(drawer.getRenderer(), color)); // <--- TODO: pass page height?
                 }
                 else
                 {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/LineTo.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/LineTo.java?rev=1574811&r1=1574810&r2=1574811&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/LineTo.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/LineTo.java Thu Mar  6 09:05:08 2014
@@ -21,7 +21,7 @@ import java.awt.geom.Point2D;
 
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.pdfviewer.PageDrawer;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.PDFOperator;
 import org.apache.pdfbox.util.operator.OperatorProcessor;