You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2014/08/30 20:38:08 UTC

svn commit: r1621508 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics: color/PDPattern.java pattern/TilingPaint.java

Author: tilman
Date: Sat Aug 30 18:38:08 2014
New Revision: 1621508

URL: http://svn.apache.org/r1621508
Log:
PDFBOX-1094, PDFBOX-1422: fix tiling and shading patterns

Modified:
    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

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=1621508&r1=1621507&r2=1621508&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 Sat Aug 30 18:38:08 2014
@@ -24,6 +24,7 @@ import org.apache.pdfbox.pdmodel.graphic
 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;
@@ -34,7 +35,6 @@ import java.io.IOException;
 import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.util.Matrix;
 
 /**
  * A Pattern color space is either a Tiling pattern or a Shading pattern.
@@ -106,22 +106,39 @@ public final class PDPattern extends PDS
 
     @Override
     public Paint toPaint(PDFRenderer renderer, PDColor color, 
-            Matrix subStreamMatrix, AffineTransform xform, 
+            Matrix substreamMatrix, AffineTransform xform, 
             int pageHeight) throws IOException
     {
         PDAbstractPattern pattern = getPattern(color);
         if (pattern instanceof PDTilingPattern)
         {
-            PDTilingPattern tilingPattern = (PDTilingPattern)pattern;
+            PDTilingPattern tilingPattern = (PDTilingPattern) pattern;
+                        
+            Matrix patternMatrix = tilingPattern.getMatrix();
+            Matrix substreamMatrixClone = substreamMatrix.clone();
+            substreamMatrixClone.setValue(2, 0, 0);
+            substreamMatrixClone.setValue(2, 1, 0);
+            Matrix matrix;
+            if (patternMatrix == null)
+            {
+                matrix = substreamMatrixClone;
+            }
+            else
+            {
+                matrix = patternMatrix.multiply(substreamMatrixClone);
+            }
+            
             if (tilingPattern.getPaintType() == PDTilingPattern.PAINT_COLORED)
             {
                 // colored tiling pattern
-                return new TilingPaint(renderer, tilingPattern, subStreamMatrix, xform);
+                return new TilingPaint(renderer, tilingPattern, 
+                        matrix, xform);
             }
             else
             {
                 // uncolored tiling pattern
-                return new TilingPaint(renderer, tilingPattern, underlyingColorSpace, color, subStreamMatrix, xform);
+                return new TilingPaint(renderer, tilingPattern, underlyingColorSpace, color, 
+                        matrix, xform);
             }
         }
         else
@@ -133,7 +150,12 @@ public final class PDPattern extends PDS
                 LOG.error("shadingPattern ist null, will be filled with transparency");
                 return new Color(0,0,0,0);
             }
-            return shading.toPaint(shadingPattern.getMatrix());
+            Matrix patternMatrix = shadingPattern.getMatrix();
+            if (patternMatrix == null)
+            {
+                return shading.toPaint(substreamMatrix);
+            }
+            return shading.toPaint(patternMatrix.multiply(substreamMatrix));
         }
     }
 

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=1621508&r1=1621507&r2=1621508&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 Sat Aug 30 18:38:08 2014
@@ -29,17 +29,19 @@ import java.awt.image.ComponentColorMode
 import java.awt.image.DataBuffer;
 import java.awt.image.WritableRaster;
 import java.io.IOException;
-
-import org.apache.pdfbox.rendering.PDFRenderer;
-import org.apache.pdfbox.rendering.PageDrawer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 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
@@ -47,116 +49,128 @@ import org.apache.pdfbox.util.Matrix;
 public class TilingPaint extends TexturePaint
 {
     /**
+     * Logger instance.
+     */
+    private static final Log LOG = LogFactory.getLog(TilingPaint.class);
+
+    /**
      * Creates a new colored tiling Paint.
+     *
      * @param pattern tiling pattern dictionary
      */
-    public TilingPaint(PDFRenderer renderer, PDTilingPattern pattern, 
-            Matrix matrix, AffineTransform xform) throws IOException
+    public TilingPaint(PDFRenderer renderer, PDTilingPattern pattern, Matrix matrix, AffineTransform xform) throws IOException
     {
-        super(getImage(renderer, pattern, null ,null), getTransformedRect(pattern));
+        super(getImage(renderer, pattern, null, null, matrix, xform), getTransformedRect(pattern, matrix));
     }
 
     /**
      * Creates a new uncolored tiling Paint.
+     *
      * @param pattern tiling pattern dictionary
      * @param colorSpace color space for this tiling
      * @param color color for this tiling
      */
     public TilingPaint(PDFRenderer renderer, PDTilingPattern pattern, PDColorSpace colorSpace,
-                       PDColor color, Matrix matrix, AffineTransform xform) throws IOException
+            PDColor color, Matrix matrix, AffineTransform xform) throws IOException
     {
-        super(getImage(renderer, pattern, colorSpace, color), getTransformedRect(pattern));
+        super(getImage(renderer, pattern, colorSpace, color, matrix, xform), getTransformedRect(pattern, matrix));
     }
 
     //  gets rect in parent content stream coordinates
-    private static Rectangle2D getTransformedRect(PDTilingPattern pattern)
+    private static Rectangle2D getTransformedRect(PDTilingPattern pattern, Matrix matrix)
     {
         float x = pattern.getBBox().getLowerLeftX();
         float y = pattern.getBBox().getLowerLeftY();
         float width = pattern.getBBox().getWidth();
         float height = pattern.getBBox().getHeight();
 
-        // xStep and yStep
-        if (pattern.getXStep() != 0)
+        // xStep and yStep, but ignore 32767 steps
+        if (pattern.getXStep() != 0 && pattern.getXStep() != Short.MAX_VALUE)
         {
             width = pattern.getXStep();
         }
-        if (pattern.getYStep() != 0)
+        if (pattern.getYStep() != 0 && pattern.getYStep() != Short.MAX_VALUE)
         {
             height = pattern.getYStep();
         }
 
         Rectangle2D rectangle;
-        if (pattern.getMatrix() == null)
-        {
-            rectangle = new Rectangle2D.Float(x, y, width, height);
-        }
-        else
-        {
-            AffineTransform at = pattern.getMatrix().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()));
-        }
+        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()));
+    }
+
     // gets image in parent stream coordinates
     private static BufferedImage getImage(PDFRenderer renderer, PDTilingPattern pattern,
-                                          PDColorSpace colorSpace, PDColor color) throws IOException
+            PDColorSpace colorSpace, PDColor color, Matrix matrix, 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);
+        Rectangle2D rect = getTransformedRect(pattern, matrix);
         int width = Math.round((float) rect.getWidth());
         int height = Math.round((float) rect.getHeight());
-        if (width < 1)
+
+        int rasterWidth = (int) (width * Math.abs(xform.getScaleX()));
+        int rasterHeight = (int) (height * Math.abs(xform.getScaleY()));
+        if (rasterWidth < 1)
         {
-            width = 1;
+            rasterWidth = 1;
         }
-        if (height < 1)
+        if (rasterHeight < 1)
         {
-            height = 1;
-        }        
+            rasterHeight = 1;
+        }
 
         // create raster
-        WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
+        WritableRaster raster = cm.createCompatibleWritableRaster(rasterWidth, rasterHeight);
         BufferedImage image = new BufferedImage(cm, raster, false, null);
 
-        // TODO the pattern matrix needs to map onto the parent stream's initial space, not the CTM
-        //      so the transformation below is not correct, because TilingPaint needs more
-        //      information to perform the transformation correctly, see PDF 32000, p174.
-
-        // matrix
-        Matrix matrix;
-        if (pattern.getMatrix() == null)
-        {
-            // identity
-            matrix = new Matrix();
-        }
-        else
-        {
-            // undo translation
-            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
-        }
+        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);
         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.dispose();