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/10/29 22:24:06 UTC

svn commit: r1635307 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox: contentstream/ pdmodel/graphics/color/ pdmodel/graphics/pattern/ rendering/

Author: jahewson
Date: Wed Oct 29 21:24:05 2014
New Revision: 1635307

URL: http://svn.apache.org/r1635307
Log:
PDFBOX-2423 / PDFBOX-1094: Fix and improve pattern rendering

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.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/rendering/PageDrawer.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java?rev=1635307&r1=1635306&r2=1635307&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java Wed Oct 29 21:24:05 2014
@@ -313,18 +313,26 @@ public class PDFStreamEngine
         popResources(parent);
     }
 
-    // todo: a temporary workaround for tiling patterns (overrides matrix and bbox)
-    public final void processChildStreamWithMatrix(PDTilingPattern contentStream, PDPage page,
-                                                 Matrix matrix, PDRectangle bbox) throws IOException
+    /**
+     * Processes the given tiling pattern.
+     *
+     * @param tilingPattern tiling patten
+     */
+    protected final void processTilingPattern(PDTilingPattern tilingPattern) throws IOException
     {
-        initPage(page);
+        PDResources parent = pushResources(tilingPattern);
+        saveGraphicsState();
 
-        // transform ctm
-        Matrix concat = matrix.multiply(getGraphicsState().getCurrentTransformationMatrix());
-        getGraphicsState().setCurrentTransformationMatrix(concat);
+        // note: we don't transform the CTM using the stream's matrix, as TilingPaint handles this
 
-        processStream(contentStream, bbox);
-        currentPage = null;
+        // clip to bounding box
+        PDRectangle bbox = tilingPattern.getBBox();
+        clipToRect(bbox);
+
+        processStreamOperators(tilingPattern);
+
+        restoreGraphicsState();
+        popResources(parent);
     }
 
     /**

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=1635307&r1=1635306&r2=1635307&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 Wed Oct 29 21:24:05 2014
@@ -20,13 +20,9 @@ import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSObject;
-import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.common.COSObjectable;
-import org.apache.pdfbox.rendering.PDFRenderer;
 
-import java.awt.Color;
-import java.awt.Paint;
 import java.awt.Transparency;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorConvertOp;
@@ -34,9 +30,7 @@ import java.awt.image.ComponentColorMode
 import java.awt.image.WritableRaster;
 import java.io.IOException;
 import java.awt.color.ColorSpace;
-import java.awt.geom.AffineTransform;
 import java.awt.image.ColorModel;
-import org.apache.pdfbox.util.Matrix;
 
 /**
  * A color space specifies how the colours of graphics objects will be painted on the page.
@@ -239,22 +233,6 @@ public abstract class PDColorSpace imple
         return dest;
     }
 
-    /**
-     * Returns the AWT paint which corresponds to the given color value in this color space
-     * and the height of the current page. This is for use with pattern color spaces.
-     * @param color the color value
-     * @param subStreamMatrix the substream matrix
-     * @param xform the graphics transform
-     * @return an AWT paint
-     * @throws IOException if the color conversion fails
-     */
-    public Paint toPaint(PDFRenderer renderer, PDPage page, PDColor color, Matrix subStreamMatrix,
-                         AffineTransform xform) throws IOException
-    {
-        float[] rgb = toRGB(color.getComponents());
-        return new Color(rgb[0], rgb[1], rgb[2]);
-    }
-
     @Override
     public COSBase getCOSObject()
     {

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=1635307&r1=1635306&r2=1635307&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 Wed Oct 29 21:24:05 2014
@@ -16,20 +16,10 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.color;
 
-import java.awt.Color;
 import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
-import org.apache.pdfbox.pdmodel.graphics.pattern.PDShadingPattern;
-import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
-import org.apache.pdfbox.pdmodel.graphics.pattern.TilingPaint;
-import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
-import org.apache.pdfbox.rendering.PDFRenderer;
-import org.apache.pdfbox.util.Matrix;
 
-import java.awt.Paint;
-import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
 
 import java.awt.image.WritableRaster;
@@ -44,11 +34,6 @@ import org.apache.commons.logging.LogFac
  */
 public final class PDPattern extends PDSpecialColorSpace
 {
-    /**
-     * log instance.
-     */
-    private static final Log LOG = LogFactory.getLog(PDPattern.class);
-    
     private final PDResources resources;
     private PDColorSpace underlyingColorSpace;
 
@@ -110,57 +95,6 @@ public final class PDPattern extends PDS
         throw new UnsupportedOperationException();
     }
 
-    @Override
-    public Paint toPaint(PDFRenderer renderer, PDPage page, PDColor color, Matrix substreamMatrix,
-                         AffineTransform xform) throws IOException
-    {
-        PDAbstractPattern pattern = getPattern(color);
-        if (pattern instanceof PDTilingPattern)
-        {
-            PDTilingPattern tilingPattern = (PDTilingPattern) pattern;
-                        
-            Matrix patternMatrix = tilingPattern.getMatrix();
-            Matrix matrix;
-            if (patternMatrix == null)
-            {
-                matrix = substreamMatrix;
-            }
-            else
-            {
-                matrix = patternMatrix.multiply(substreamMatrix);
-            }
-            
-            if (tilingPattern.getPaintType() == PDTilingPattern.PAINT_COLORED)
-            {
-                // colored tiling pattern
-                return new TilingPaint(renderer, page, tilingPattern,
-                        matrix, xform);
-            }
-            else
-            {
-                // uncolored tiling pattern
-                return new TilingPaint(renderer, page, tilingPattern, underlyingColorSpace, color,
-                        matrix, xform);
-            }
-        }
-        else
-        {
-            PDShadingPattern shadingPattern = (PDShadingPattern)pattern;
-            PDShading shading = shadingPattern.getShading();
-            if (shading == null)
-            {
-                LOG.error("shadingPattern is null, will be filled with transparency");
-                return new Color(0,0,0,0);
-            }
-            Matrix patternMatrix = shadingPattern.getMatrix();
-            if (patternMatrix == null)
-            {
-                return shading.toPaint(substreamMatrix);
-            }
-            return shading.toPaint(patternMatrix.multiply(substreamMatrix));
-        }
-    }
-
     /**
      * Returns the pattern for the given color.
      * 
@@ -181,6 +115,14 @@ public final class PDPattern extends PDS
         }
     }
 
+    /**
+     * Returns the underlying color space, if this is an uncolored tiling pattern, otherwise null.
+     */
+    public final PDColorSpace getUnderlyingColorSpace()
+    {
+        return underlyingColorSpace;
+    }
+
     @Override
     public String toString()
     {

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=1635307&r1=1635306&r2=1635307&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 Wed Oct 29 21:24:05 2014
@@ -17,11 +17,14 @@
 package org.apache.pdfbox.pdmodel.graphics.pattern;
 
 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.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
@@ -32,146 +35,95 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 
-import org.apache.pdfbox.pdmodel.PDPage;
 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.rendering.PDFRenderer;
 import org.apache.pdfbox.rendering.PageDrawer;
-import org.apache.pdfbox.rendering.TilingPatternDrawer;
-import org.apache.pdfbox.util.Matrix;
 
 /**
- * AWT Paint for a tiling pattern, which consists of a small repeating graphical
- * figure.
+ * AWT Paint for a tiling pattern, which consists of a small repeating graphical figure.
  *
  * @author Andreas Lehmkühler
  * @author John Hewson
  */
-public class TilingPaint extends TexturePaint
+public class TilingPaint implements Paint
 {
+    private final PDTilingPattern pattern;
+    private final TexturePaint paint;
+
     /**
      * Creates a new colored tiling Paint.
      *
-     * @param renderer renderer to render the page
+     * @param drawer renderer to render the page
      * @param pattern tiling pattern dictionary
-     * @param matrix initial substream transformation matrix
-     * @param xform initial graphics transform of the page
-     * 
+     *
      * @throws java.io.IOException if something goes wrong while drawing the
      * pattern
      */
-    public TilingPaint(PDFRenderer renderer, PDPage page, PDTilingPattern pattern, Matrix matrix, AffineTransform xform) throws IOException
+    public TilingPaint(PageDrawer drawer, PDTilingPattern pattern, AffineTransform xform)
+            throws IOException
     {
-        super(getImage(renderer, page, pattern, null, null, matrix, xform), getTransformedRect(pattern, matrix));
+        this.paint = new TexturePaint(getImage(drawer, pattern, null, null, xform),
+                                      getAnchorRect(pattern));
+        this.pattern = pattern;
     }
 
     /**
      * Creates a new uncolored tiling Paint.
      *
-     * @param renderer renderer to render the page
+     * @param drawer renderer to render the page
      * @param pattern tiling pattern dictionary
      * @param colorSpace color space for this tiling
      * @param color color for this tiling
-     * @param matrix initial substream transformation matrix
-     * @param xform initial graphics transform of the page
-     * 
+     *
      * @throws java.io.IOException if something goes wrong while drawing the pattern
      */
-    public TilingPaint(PDFRenderer renderer, PDPage page, PDTilingPattern pattern, PDColorSpace colorSpace,
-            PDColor color, Matrix matrix, AffineTransform xform) throws IOException
+    public TilingPaint(PageDrawer drawer, PDTilingPattern pattern, PDColorSpace colorSpace,
+                       PDColor color, AffineTransform xform) throws IOException
     {
-        super(getImage(renderer, page, pattern, colorSpace, color, matrix, xform), getTransformedRect(pattern, matrix));
+        this.paint = new TexturePaint(getImage(drawer, pattern, colorSpace, color, xform),
+                                      getAnchorRect(pattern));
+        this.pattern = pattern;
     }
 
-    //  gets rect in parent content stream coordinates
-    private static Rectangle2D getTransformedRect(PDTilingPattern pattern, Matrix matrix)
+    // note: this is not called in TexturePaint subclasses, which is why we wrap TexturePaint
+    @Override
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds,
+                                      AffineTransform xform, RenderingHints hints)
     {
-        float x = pattern.getBBox().getLowerLeftX();
-        float y = pattern.getBBox().getLowerLeftY();
-        float width = pattern.getBBox().getWidth();
-        float height = pattern.getBBox().getHeight();
-
-        // xStep and yStep, but ignore 32767 steps
-        if (pattern.getXStep() != 0 && pattern.getXStep() != Short.MAX_VALUE)
-        {
-            width = pattern.getXStep();
-        }
-        if (pattern.getYStep() != 0 && pattern.getYStep() != Short.MAX_VALUE)
-        {
-            height = pattern.getYStep();
-        }
-
-        Rectangle2D rectangle;
-        AffineTransform at = matrix.createAffineTransform();
-        Point2D p1 = new Point2D.Float(x, y);
-        Point2D p2 = new Point2D.Float(x + width, y + height);
-        at.transform(p1, p1);
-        at.transform(p2, p2);
-        // at.createTransformedShape(rect).getBounds2D() gets empty rectangle
-        // when negative numbers, so we do it the hard way
-        rectangle = new Rectangle2D.Float(
-                (float) Math.min(p1.getX(), p2.getX()),
-                (float) Math.min(p1.getY(), p2.getY()),
-                (float) Math.abs(p2.getX() - p1.getX()),
-                (float) Math.abs(p2.getY() - p1.getY()));
-        return rectangle;
-    }
-
-    // get lower left coord of bbox
-    private static Point2D getTransformedPoint(PDTilingPattern pattern, Matrix matrix)
-    {
-        float x = pattern.getBBox().getLowerLeftX();
-        float y = pattern.getBBox().getLowerLeftY();
-        float width = pattern.getBBox().getWidth();
-        float height = pattern.getBBox().getHeight();
-
-        AffineTransform at = matrix.createAffineTransform();
-        Point2D p1 = new Point2D.Float(x, y);
-        Point2D p2 = new Point2D.Float(x + width, y + height);
-        at.transform(p1, p1);
-        at.transform(p2, p2);
-        return new Point2D.Float(
-                (float) Math.min(p1.getX(), p2.getX()),
-                (float) Math.min(p1.getY(), p2.getY()));
+        // todo: use userBounds or deviceBounds to avoid scaling issue with Tracemonkey?
+        AffineTransform xformPattern = (AffineTransform)xform.clone();
+        xformPattern.concatenate(pattern.getMatrix().createAffineTransform());
+        return paint.createContext(cm, deviceBounds, userBounds, xformPattern, hints);
     }
 
     // gets image in parent stream coordinates
-    private static BufferedImage getImage(PDFRenderer renderer, PDPage page, PDTilingPattern pattern,
-            PDColorSpace colorSpace, PDColor color, Matrix matrix, AffineTransform xform) throws IOException
+    private static BufferedImage getImage(PageDrawer drawer, PDTilingPattern pattern,
+                                          PDColorSpace colorSpace, PDColor color,
+                                          AffineTransform xform) throws IOException
     {
         ColorSpace outputCS = ColorSpace.getInstance(ColorSpace.CS_sRGB);
         ColorModel cm = new ComponentColorModel(outputCS, true, false,
                 Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
 
-        Rectangle2D rect = getTransformedRect(pattern, matrix);
-        float width = (float)rect.getWidth();
-        float height = (float)rect.getHeight();
+        Rectangle2D anchor = getAnchorRect(pattern);
+        float width = (float)Math.abs(anchor.getWidth());
+        float height = (float)Math.abs(anchor.getHeight());
+
+        // device transform (i.e. DPI)
+        width *= (float)xform.getScaleX();
+        height *= (float)xform.getScaleY();
 
-        int rasterWidth = Math.max(1, ceiling(width * Math.abs(xform.getScaleX())));
-        int rasterHeight = Math.max(1, ceiling(height * Math.abs(xform.getScaleY())));
+        int rasterWidth = Math.max(1, ceiling(width));
+        int rasterHeight = Math.max(1, ceiling(height));
 
         // create raster
         WritableRaster raster = cm.createCompatibleWritableRaster(rasterWidth, rasterHeight);
         BufferedImage image = new BufferedImage(cm, raster, false, null);
 
-        matrix = matrix.clone();
-        Point2D p = getTransformedPoint(pattern, matrix);
-        matrix.setValue(2, 0, matrix.getValue(2, 0) - (float) p.getX()); // tx
-        matrix.setValue(2, 1, matrix.getValue(2, 1) - (float) p.getY()); // ty
-
-        // TODO: need to make it easy to use a custom TilingPatternDrawer
-        PageDrawer drawer = new TilingPatternDrawer(renderer, page);
-        PDRectangle pdRect = new PDRectangle(0, 0, width, height);
-
         Graphics2D graphics = image.createGraphics();
-        // transform without the translation
-        AffineTransform at = new AffineTransform(
-                xform.getScaleX(), xform.getShearY(),
-                -xform.getShearX(), xform.getScaleY(),
-                0, 0);
-        graphics.transform(at);
-        drawer.drawTilingPattern(graphics, pattern, pdRect, matrix, colorSpace, color);
+        graphics.transform(xform); // device transform (i.e. DPI)
+        drawer.drawTilingPattern(graphics, pattern, colorSpace, color);
         graphics.dispose();
 
         return image;
@@ -193,4 +145,23 @@ public class TilingPaint extends Texture
     {
         return Transparency.TRANSLUCENT;
     }
+
+    // includes XStep/YStep
+    public static Rectangle2D getAnchorRect(PDTilingPattern pattern)
+    {
+        float xStep = pattern.getXStep();
+        if (xStep == 0)
+        {
+            xStep = pattern.getBBox().getWidth();
+        }
+
+        float yStep = pattern.getYStep();
+        if (yStep == 0)
+        {
+            yStep = pattern.getBBox().getHeight();
+        }
+
+        PDRectangle anchor = pattern.getBBox();
+        return new Rectangle2D.Float(anchor.getLowerLeftX(), anchor.getLowerLeftY(), xStep, yStep);
+    }
 }

Modified: 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=1635307&r1=1635306&r2=1635307&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Wed Oct 29 21:24:05 2014
@@ -17,6 +17,7 @@
 package org.apache.pdfbox.rendering;
 
 import java.awt.BasicStroke;
+import java.awt.Color;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Paint;
@@ -42,8 +43,11 @@ import org.apache.commons.logging.LogFac
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.font.PDCIDFontType0;
 import org.apache.pdfbox.pdmodel.font.PDCIDFontType2;
-import org.apache.pdfbox.pdmodel.font.PDType3CharProc;
+import org.apache.pdfbox.pdmodel.graphics.color.PDPattern;
 import org.apache.pdfbox.pdmodel.graphics.image.PDImage;
+import org.apache.pdfbox.pdmodel.graphics.pattern.PDAbstractPattern;
+import org.apache.pdfbox.pdmodel.graphics.pattern.PDShadingPattern;
+import org.apache.pdfbox.pdmodel.graphics.pattern.TilingPaint;
 import org.apache.pdfbox.pdmodel.graphics.state.RenderingMode;
 import org.apache.pdfbox.rendering.font.CIDType0Glyph2D;
 import org.apache.pdfbox.rendering.font.Glyph2D;
@@ -56,7 +60,6 @@ import org.apache.pdfbox.pdmodel.font.PD
 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.PDLineDashPattern;
 import org.apache.pdfbox.pdmodel.graphics.state.PDSoftMask;
 import org.apache.pdfbox.pdmodel.graphics.blend.SoftMaskPaint;
@@ -83,9 +86,8 @@ public class PageDrawer extends PDFGraph
     // parent document renderer
     private final PDFRenderer renderer;
 
+    // the graphics device to draw to, xform is the initial transform of the device (i.e. DPI)
     private Graphics2D graphics;
-
-    // initial transform
     private AffineTransform xform;
     
     // clipping winding rule used for the clipping path
@@ -145,6 +147,7 @@ public class PageDrawer extends PDFGraph
     {
         graphics = (Graphics2D) g;
         xform = graphics.getTransform();
+
         setRenderingHints();
 
         graphics.translate(0, (int) pageSize.getHeight());
@@ -170,29 +173,93 @@ public class PageDrawer extends PDFGraph
      *
      * @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.
-     * @param matrix initial substream transformation matrix.
      * @param colorSpace color space for this tiling.
      * @param color color for this tiling.
      * @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
+    public void drawTilingPattern(Graphics2D g, PDTilingPattern pattern, PDColorSpace colorSpace,
+                                  PDColor color) throws IOException
     {
+        Graphics2D oldGraphics = graphics;
         graphics = g;
+
+        GeneralPath oldLinePath = linePath;
+        linePath = new GeneralPath();
+
+        Area oldLastClip = lastClip;
+        lastClip = null;
+
         setRenderingHints();
+        saveGraphicsState();
 
-        // color
+        // non-colored patterns have to be given a color
         if (colorSpace != null)
         {
+            color = new PDColor(color.getComponents(), colorSpace);
             getGraphicsState().setNonStrokingColorSpace(colorSpace);
             getGraphicsState().setNonStrokingColor(color);
             getGraphicsState().setStrokingColorSpace(colorSpace);
             getGraphicsState().setStrokingColor(color);
         }
 
-        processChildStreamWithMatrix(pattern, getPage(), matrix, pageDimension);
+        processTilingPattern(pattern);
+
+        restoreGraphicsState();
+        graphics = oldGraphics;
+        linePath = oldLinePath;
+        lastClip = oldLastClip;
+    }
+
+    /**
+     * Returns an AWT paint for the given PDColor.
+     */
+    private Paint getPaint(PDColor color) throws IOException
+    {
+        PDColorSpace colorSpace = color.getColorSpace();
+        if (!(colorSpace instanceof PDPattern))
+        {
+            float[] rgb = colorSpace.toRGB(color.getComponents());
+            return new Color(rgb[0], rgb[1], rgb[2]);
+        }
+        else
+        {
+            PDPattern patternSpace = (PDPattern)colorSpace;
+            PDAbstractPattern pattern = patternSpace.getPattern(color);
+            if (pattern instanceof PDTilingPattern)
+            {
+                PDTilingPattern tilingPattern = (PDTilingPattern) pattern;
+
+                if (tilingPattern.getPaintType() == PDTilingPattern.PAINT_COLORED)
+                {
+                    // colored tiling pattern
+                    return new TilingPaint(this, tilingPattern, xform);
+                }
+                else
+                {
+                    // uncolored tiling pattern
+                    return new TilingPaint(this, tilingPattern,
+                            patternSpace.getUnderlyingColorSpace(), color, xform);
+                }
+            }
+            else
+            {
+                PDShadingPattern shadingPattern = (PDShadingPattern)pattern;
+                PDShading shading = shadingPattern.getShading();
+                if (shading == null)
+                {
+                    LOG.error("shadingPattern is null, will be filled with transparency");
+                    return new Color(0,0,0,0);
+                }
+
+                // fixme: shading needs to use the correct matrix
+                Matrix patternMatrix = shadingPattern.getMatrix();
+                if (patternMatrix == null)
+                {
+                    patternMatrix = new Matrix();
+                }
+                return shading.toPaint(patternMatrix);
+            }
+        }
     }
 
     // sets the clipping path using caching for performance, we track lastClip manually because
@@ -305,29 +372,6 @@ public class PageDrawer extends PDFGraph
     }
 
     /**
-     * Render the text using a type 3 font.
-     * 
-     * @param font the type3 font
-     * @param code internal PDF character codes of glyph
-     * 
-     * @throws IOException if something went wrong
-     */
-    private void drawType3Glyph(PDType3Font font, int code, Matrix textRenderingMatrix) throws IOException
-    {
-        PDType3CharProc charProc = font.getCharProc(code);
-        if (charProc != null)
-        {
-            lastClip = null;
-            processType3Stream(charProc, textRenderingMatrix);
-            lastClip = null;
-        }
-        else
-        {
-            LOG.error("Stream for Type 3 character " + code + " not found");
-        }
-    }
-
-    /**
      * Provide a Glyph2D for the given font.
      * 
      * @param font the font
@@ -450,19 +494,15 @@ public class PageDrawer extends PDFGraph
     // returns the stroking AWT Paint
     private Paint getStrokingPaint() throws IOException
     {
-        PDGraphicsState graphicsState = getGraphicsState();
-        return applySoftMaskToPaint(graphicsState.getStrokingColorSpace()
-                .toPaint(renderer, getPage(), graphicsState.getStrokingColor(),
-                         getSubStreamMatrix(), xform),
-                graphicsState.getSoftMask());
+        return applySoftMaskToPaint(
+                getPaint(getGraphicsState().getStrokingColor()),
+                getGraphicsState().getSoftMask());
     }
 
     // returns the non-stroking AWT Paint
     private Paint getNonStrokingPaint() throws IOException
     {
-        return getGraphicsState().getNonStrokingColorSpace()
-                .toPaint(renderer, getPage(), getGraphicsState().getNonStrokingColor(),
-                        getSubStreamMatrix(), xform);
+        return getPaint(getGraphicsState().getNonStrokingColor());
     }
 
     // create a new stroke based on the current CTM and the current stroke
@@ -671,10 +711,8 @@ public class PageDrawer extends PDFGraph
         if (pdImage.isStencil())
         {
             // fill the image with paint
-            PDColorSpace colorSpace = getGraphicsState().getNonStrokingColorSpace();
             PDColor color = getGraphicsState().getNonStrokingColor();
-            BufferedImage image = pdImage.getStencilImage(
-                    colorSpace.toPaint(renderer, getPage(), color, getSubStreamMatrix(), xform));
+            BufferedImage image = pdImage.getStencilImage(getPaint(color));
 
             // draw the image
             drawBufferedImage(image, at);