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/12/15 18:12:07 UTC

svn commit: r1643042 - in /pdfbox/trunk: examples/src/main/java/org/apache/pdfbox/examples/util/ pdfbox/src/main/java/org/apache/pdfbox/contentstream/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel...

Author: jahewson
Date: Wed Dec  3 02:02:13 2014
New Revision: 1643042

URL: http://svn.apache.org/r1643042
Log:
PDFBOX-2423: Improve pattern rendering

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/TilingPaint.java
      - copied, changed from r1642606, pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java
Removed:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/TilingPatternDrawer.java
Modified:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFTextStreamEngine.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java?rev=1643042&r1=1643041&r2=1643042&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java Wed Dec  3 02:02:13 2014
@@ -132,7 +132,7 @@ public class PrintImageLocations extends
                 
                 double imageXScale = imageTransform.getScaleX();
                 double imageYScale = imageTransform.getScaleY();
-                System.out.println("position = " + ctmNew.getXPosition() + ", " + ctmNew.getYPosition());
+                System.out.println("position = " + ctmNew.getTranslateX() + ", " + ctmNew.getTranslateY());
                 // size in pixel
                 System.out.println("size = " + imageWidth + "px, " + imageHeight + "px");
                 // size in page units

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=1643042&r1=1643041&r2=1643042&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 Dec  3 02:02:13 2014
@@ -16,8 +16,9 @@
  */
 package org.apache.pdfbox.contentstream;
 
-import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -43,7 +44,8 @@ import org.apache.pdfbox.pdmodel.font.PD
 import org.apache.pdfbox.pdmodel.font.PDFontFactory;
 import org.apache.pdfbox.pdmodel.font.PDType3CharProc;
 import org.apache.pdfbox.pdmodel.font.PDType3Font;
-import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
 import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
 import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
 import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
@@ -69,13 +71,13 @@ public class PDFStreamEngine
 
     private Matrix textMatrix;
     private Matrix textLineMatrix;
-    protected Matrix subStreamMatrix = new Matrix();
 
     private final Stack<PDGraphicsState> graphicsStack = new Stack<PDGraphicsState>();
 
     private PDResources resources;
     private PDPage currentPage;
     private boolean isProcessingPage;
+    private Matrix initialMatrix;
 
     // skip malformed or otherwise unparseable input where possible
     private boolean forceParsing;
@@ -147,6 +149,7 @@ public class PDFStreamEngine
         textMatrix = null;
         textLineMatrix = null;
         resources = null;
+        initialMatrix = page.getMatrix();
     }
 
     /**
@@ -292,19 +295,19 @@ public class PDFStreamEngine
         // zero-sized rectangles are not valid
         if (rect.getWidth() > 0 && rect.getHeight() > 0)
         {
-            // transformed appearance box
-            PDRectangle transformedBox = bbox.transform(matrix);
+            // transformed appearance box  fixme: may be an arbitrary shape
+            Rectangle2D transformedBox = bbox.transform(matrix).getBounds2D();
 
             // compute a matrix which scales and translates the transformed appearance box to align
             // with the edges of the annotation's rectangle
             Matrix a = Matrix.getTranslatingInstance(rect.getLowerLeftX(), rect.getLowerLeftY());
-            a.concatenate(Matrix.getScaleInstance(rect.getWidth() / transformedBox.getWidth(),
-                    rect.getHeight() / transformedBox.getHeight()));
-            a.concatenate(Matrix.getTranslatingInstance(-transformedBox.getLowerLeftX(),
-                    -transformedBox.getLowerLeftY()));
+            a.concatenate(Matrix.getScaleInstance((float)(rect.getWidth() / transformedBox.getWidth()),
+                    (float)(rect.getHeight() / transformedBox.getHeight())));
+            a.concatenate(Matrix.getTranslatingInstance((float) -transformedBox.getX(),
+                    (float) -transformedBox.getY()));
 
             // Matrix shall be concatenated with A to form a matrix AA that maps from the appearance€™s
-            // coordinate system to the annotation’s rectangle in default user space
+            // coordinate system to the annotation's rectangle in default user space
             Matrix aa = Matrix.concatenate(matrix, a);
 
             // make matrix AA the CTM
@@ -321,23 +324,61 @@ public class PDFStreamEngine
     }
 
     /**
-     * Processes the given tiling pattern.
+     * Process the given tiling pattern.
      *
-     * @param tilingPattern tiling patten
+     * @param tilingPattern the tiling pattern
+     * @param color color to use, if this is an uncoloured pattern, otherwise null.
+     * @param colorSpace color space to use, if this is an uncoloured pattern, otherwise null.
      */
-    protected final void processTilingPattern(PDTilingPattern tilingPattern) throws IOException
+    protected final void processTilingPattern(PDTilingPattern tilingPattern, PDColor color,
+                                              PDColorSpace colorSpace) throws IOException
+    {
+        processTilingPattern(tilingPattern, color, colorSpace, tilingPattern.getMatrix());
+    }
+
+    /**
+     * Process the given tiling pattern. Allows the pattern matrix to be overridden for custom
+     * rendering.
+     *
+     * @param tilingPattern the tiling pattern
+     * @param color color to use, if this is an uncoloured pattern, otherwise null.
+     * @param colorSpace color space to use, if this is an uncoloured pattern, otherwise null.
+     * @param patternMatrix the pattern matrix, may be overridden for custom rendering.
+     */
+    protected final void processTilingPattern(PDTilingPattern tilingPattern, PDColor color,
+                                              PDColorSpace colorSpace, Matrix patternMatrix)
+            throws IOException
     {
         PDResources parent = pushResources(tilingPattern);
-        saveGraphicsState();
 
-        // note: we don't transform the CTM using the stream's matrix, as TilingPaint handles this
+        Matrix parentMatrix = initialMatrix;
+        initialMatrix = Matrix.concatenate(initialMatrix, patternMatrix);
+
+        // set up a clean state (new clipping path, line path, etc.)
+        Rectangle2D bbox = tilingPattern.getBBox().transform(patternMatrix).getBounds2D();
+        PDRectangle rect = new PDRectangle((float)bbox.getX(), (float)bbox.getY(),
+                (float)bbox.getWidth(), (float)bbox.getHeight());
+        graphicsStack.push(new PDGraphicsState(rect));
+
+        // 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);
+        }
+
+        // transform the CTM using the stream's matrix
+        getGraphicsState().getCurrentTransformationMatrix().concatenate(patternMatrix);
 
         // clip to bounding box
-        PDRectangle bbox = tilingPattern.getBBox();
-        clipToRect(bbox);
+        clipToRect(tilingPattern.getBBox());
 
         processStreamOperators(tilingPattern);
 
+        initialMatrix = parentMatrix;
         restoreGraphicsState();
         popResources(parent);
     }
@@ -395,35 +436,22 @@ public class PDFStreamEngine
      */
     private void processStream(PDContentStream contentStream) throws IOException
     {
-        processStream(contentStream, null);
-    }
-
-    /**
-     * Process a content stream.
-     *
-     * @param contentStream the content stream
-     * @param patternBBox fixme: temporary workaround for tiling patterns
-     * @throws IOException if there is an exception while processing the stream
-     */
-    private void processStream(PDContentStream contentStream, PDRectangle patternBBox)
-            throws IOException
-    {
         PDResources parent = pushResources(contentStream);
         saveGraphicsState();
 
+        Matrix parentMatrix = initialMatrix;
+        initialMatrix = Matrix.concatenate(initialMatrix, contentStream.getMatrix());
+
         // transform the CTM using the stream's matrix
         getGraphicsState().getCurrentTransformationMatrix().concatenate(contentStream.getMatrix());
 
         // clip to bounding box
         PDRectangle bbox = contentStream.getBBox();
-        if (patternBBox != null)
-        {
-            bbox = patternBBox;
-        }
         clipToRect(bbox);
 
         processStreamOperators(contentStream);
 
+        initialMatrix = parentMatrix;
         restoreGraphicsState();
         popResources(parent);
     }
@@ -433,10 +461,6 @@ public class PDFStreamEngine
      */
     private void processStreamOperators(PDContentStream contentStream) throws IOException
     {
-        // fixme: stream matrix
-        Matrix oldSubStreamMatrix = subStreamMatrix;
-        subStreamMatrix = getGraphicsState().getCurrentTransformationMatrix();
-
         List<COSBase> arguments = new ArrayList<COSBase>();
         PDFStreamParser parser = new PDFStreamParser(contentStream.getContentStream(), forceParsing);
         try
@@ -464,9 +488,6 @@ public class PDFStreamEngine
         {
             parser.close();
         }
-
-        // fixme: stream matrix
-        subStreamMatrix = oldSubStreamMatrix;
     }
 
     /**
@@ -510,8 +531,8 @@ public class PDFStreamEngine
     {
         if (rectangle != null)
         {
-            PDRectangle clip = rectangle.transform(getGraphicsState().getCurrentTransformationMatrix());
-            getGraphicsState().intersectClippingPath(new Area(clip.toGeneralPath()));
+            GeneralPath clip = rectangle.transform(getGraphicsState().getCurrentTransformationMatrix());
+            getGraphicsState().intersectClippingPath(clip);
         }
     }
 
@@ -867,14 +888,6 @@ public class PDFStreamEngine
     {
         textMatrix = value;
     }
-
-    /**
-     * Returns the subStreamMatrix.
-     */
-    protected Matrix getSubStreamMatrix()
-    {
-        return subStreamMatrix;
-    }
     
     /**
      * Returns the stream' resources.
@@ -892,6 +905,11 @@ public class PDFStreamEngine
         return currentPage;
     }
 
+    public Matrix getInitialMatrix()
+    {
+        return initialMatrix;
+    }
+
     /**
      * use the current transformation matrix to transformPoint a single point.
      *

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFTextStreamEngine.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFTextStreamEngine.java?rev=1643042&r1=1643041&r2=1643042&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFTextStreamEngine.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFTextStreamEngine.java Wed Dec  3 02:02:13 2014
@@ -150,12 +150,12 @@ public class PDFTextStreamEngine extends
 
         // (modified) text rendering matrix
         Matrix nextTextRenderingMatrix = td.multiply(textMatrix).multiply(ctm); // text space -> device space
-        float nextX = nextTextRenderingMatrix.getXPosition();
-        float nextY = nextTextRenderingMatrix.getYPosition();
+        float nextX = nextTextRenderingMatrix.getTranslateX();
+        float nextY = nextTextRenderingMatrix.getTranslateY();
 
         // (modified) width and height calculations
-        float dxDisplay = nextX - textRenderingMatrix.getXPosition();
-        float dyDisplay = height * textRenderingMatrix.getYScale();
+        float dxDisplay = nextX - textRenderingMatrix.getTranslateX();
+        float dyDisplay = height * textRenderingMatrix.getScaleY();
 
         //
         // start of the original method

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java?rev=1643042&r1=1643041&r2=1643042&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/PDRectangle.java Wed Dec  3 02:02:13 2014
@@ -280,19 +280,28 @@ public class PDRectangle implements COSO
     }
 
     /**
-     * Returns a copy of this rectangle which has been transformed using the given matrix.
+     * Returns a path which represents this rectangle having been transformed by the given matrix.
+     * Note that the resulting path need not be rectangular.
      */
-    public PDRectangle transform(Matrix matrix)
+    public GeneralPath transform(Matrix matrix)
     {
-        Point2D.Float lowerLeft = matrix.transformPoint(getLowerLeftX(), getLowerLeftY());
-        Point2D.Float upperRight = matrix.transformPoint(getUpperRightX(), getUpperRightY());
+        float x1 = getLowerLeftX();
+        float y1 = getLowerLeftY();
+        float x2 = getUpperRightX();
+        float y2 = getUpperRightY();
 
-        PDRectangle rect = new PDRectangle();
-        rect.setLowerLeftX(lowerLeft.x);
-        rect.setLowerLeftY(lowerLeft.y);
-        rect.setUpperRightX(upperRight.x);
-        rect.setUpperRightY(upperRight.y);
-        return rect;
+        Point2D p0 = matrix.transformPoint(x1, y1);
+        Point2D p1 = matrix.transformPoint(x2, y1);
+        Point2D p2 = matrix.transformPoint(x2, y2);
+        Point2D p3 = matrix.transformPoint(x1, y2);
+
+        GeneralPath path = new GeneralPath();
+        path.moveTo((float) p0.getX(), (float) p0.getY());
+        path.lineTo((float) p1.getX(), (float) p1.getY());
+        path.lineTo((float) p2.getX(), (float) p2.getY());
+        path.lineTo((float) p3.getX(), (float) p3.getY());
+        path.closePath();
+        return path;
     }
 
     /**

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java?rev=1643042&r1=1643041&r2=1643042&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDTilingPattern.java Wed Dec  3 02:02:13 2014
@@ -31,6 +31,7 @@ import org.apache.pdfbox.util.Matrix;
 
 /**
  * A tiling pattern dictionary.
+ *
  * @author Andreas Lehmkühler
  */
 public class PDTilingPattern extends PDAbstractPattern implements PDContentStream
@@ -259,6 +260,28 @@ public class PDTilingPattern extends PDA
             matrix.setValue(1, 1, ((COSNumber) array.get(3)).floatValue());
             matrix.setValue(2, 0, ((COSNumber) array.get(4)).floatValue());
             matrix.setValue(2, 1, ((COSNumber) array.get(5)).floatValue());
+
+            // repair mechanism for invalid matrices, this is based on pure guesswork based on the
+            // PoolCompPDFA.pdf from PDFBOX-1265 which renders fine in Acrobat despite having a
+            // scaling factor of zero.
+            if (matrix.getScaleX() == 0)
+            {
+                matrix.setValue(0, 0, ((COSNumber) array.get(1)).floatValue()); // scale x -> skew x
+                matrix.setValue(1, 0, 0); // skew x -> 0
+            }
+            if (matrix.getScaleY() == 0)
+            {
+                matrix.setValue(1, 1, ((COSNumber) array.get(2)).floatValue()); // scale y -> skew y
+                matrix.setValue(0, 1, 0); // skew y -> 0
+            }
+            if (matrix.getScaleX() == 0)
+            {
+                matrix.setValue(0, 0, 1);
+            }
+            if (matrix.getScaleY() == 0)
+            {
+                matrix.setValue(1, 1, 1);
+            }
         }
         else
         {

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=1643042&r1=1643041&r2=1643042&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 Dec  3 02:02:13 2014
@@ -45,7 +45,6 @@ import org.apache.pdfbox.pdmodel.graphic
 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;
@@ -77,7 +76,7 @@ import org.apache.pdfbox.util.Vector;
  * 
  * @author Ben Litchfield
  */
-public class PageDrawer extends PDFGraphicsStreamEngine
+public final class PageDrawer extends PDFGraphicsStreamEngine
 {
     private static final Log LOG = LogFactory.getLog(PageDrawer.class);
 
@@ -181,7 +180,7 @@ public class PageDrawer extends PDFGraph
      * @throws IOException If there is an IO error while drawing the page.
      */
     public void drawTilingPattern(Graphics2D g, PDTilingPattern pattern, PDColorSpace colorSpace,
-                                  PDColor color) throws IOException
+                                  PDColor color, Matrix patternMatrix) throws IOException
     {
         Graphics2D oldGraphics = graphics;
         graphics = g;
@@ -193,21 +192,8 @@ public class PageDrawer extends PDFGraph
         lastClip = null;
 
         setRenderingHints();
-        saveGraphicsState();
+        processTilingPattern(pattern, color, colorSpace, patternMatrix);
 
-        // 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);
-        }
-
-        processTilingPattern(pattern);
-
-        restoreGraphicsState();
         graphics = oldGraphics;
         linePath = oldLinePath;
         lastClip = oldLastClip;
@@ -253,14 +239,8 @@ public class PageDrawer extends PDFGraph
                     LOG.error("shadingPattern is null, will be filled with transparency");
                     return new Color(0,0,0,0);
                 }
+                return shading.toPaint(getInitialMatrix());
 
-                // fixme: shading needs to use the correct matrix
-                Matrix patternMatrix = shadingPattern.getMatrix();
-                if (patternMatrix == null)
-                {
-                    patternMatrix = new Matrix();
-                }
-                return shading.toPaint(patternMatrix);
             }
         }
     }
@@ -860,11 +840,11 @@ public class PageDrawer extends PDFGraph
             Matrix transform = Matrix.concatenate(ctm, form.getMatrix());
 
             // transform the bbox
-            PDRectangle bbox = form.getBBox().transform(transform);
+            GeneralPath transformedBox = form.getBBox().transform(transform);
 
             // clip the bbox to prevent giant bboxes from consuming all memory
             Area clip = (Area)getGraphicsState().getCurrentClippingPath().clone();
-            clip.intersect(new Area(bbox.toGeneralPath()));
+            clip.intersect(new Area(transformedBox));
             Rectangle2D clipRect = clip.getBounds2D();
             this.bbox = new PDRectangle((float)clipRect.getX(), (float)clipRect.getY(),
                                         (float)clipRect.getWidth(), (float)clipRect.getHeight());

Copied: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/TilingPaint.java (from r1642606, 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/rendering/TilingPaint.java?p2=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/TilingPaint.java&p1=pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/TilingPaint.java&r1=1642606&r2=1643042&rev=1643042&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/rendering/TilingPaint.java Wed Dec  3 02:02:13 2014
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.pdfbox.pdmodel.graphics.pattern;
+package org.apache.pdfbox.rendering;
 
 import java.awt.Graphics2D;
 import java.awt.Paint;
@@ -38,7 +38,8 @@ import java.math.RoundingMode;
 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.PageDrawer;
+import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
+import org.apache.pdfbox.util.Matrix;
 
 /**
  * AWT Paint for a tiling pattern, which consists of a small repeating graphical figure.
@@ -46,7 +47,7 @@ import org.apache.pdfbox.rendering.PageD
  * @author Andreas Lehmkühler
  * @author John Hewson
  */
-public class TilingPaint implements Paint
+class TilingPaint implements Paint
 {
     private final PDTilingPattern pattern;
     private final TexturePaint paint;
@@ -64,7 +65,7 @@ public class TilingPaint implements Pain
             throws IOException
     {
         this.paint = new TexturePaint(getImage(drawer, pattern, null, null, xform),
-                                      getAnchorRect(pattern));
+                getAnchorRect(pattern));
         this.pattern = pattern;
     }
 
@@ -82,22 +83,30 @@ public class TilingPaint implements Pain
                        PDColor color, AffineTransform xform) throws IOException
     {
         this.paint = new TexturePaint(getImage(drawer, pattern, colorSpace, color, xform),
-                                      getAnchorRect(pattern));
+                getAnchorRect(pattern));
         this.pattern = pattern;
     }
 
-    // note: this is not called in TexturePaint subclasses, which is why we wrap TexturePaint
+    /**
+     * 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)
     {
-        // todo: use userBounds or deviceBounds to avoid scaling issue with Tracemonkey?
         AffineTransform xformPattern = (AffineTransform)xform.clone();
-        xformPattern.concatenate(pattern.getMatrix().createAffineTransform());
+
+        // applies the pattern matrix with scaling removed
+        AffineTransform patternNoScale = pattern.getMatrix().createAffineTransform();
+        patternNoScale.scale(1 / patternNoScale.getScaleX(), 1 / patternNoScale.getScaleY());
+        xformPattern.concatenate(patternNoScale);
+
         return paint.createContext(cm, deviceBounds, userBounds, xformPattern, hints);
     }
 
-    // gets image in parent stream coordinates
+    /**
+     * Returns the pattern image in parent stream coordinates.
+     */
     private static BufferedImage getImage(PageDrawer drawer, PDTilingPattern pattern,
                                           PDColorSpace colorSpace, PDColor color,
                                           AffineTransform xform) throws IOException
@@ -122,15 +131,44 @@ public class TilingPaint implements Pain
         BufferedImage image = new BufferedImage(cm, raster, false, null);
 
         Graphics2D graphics = image.createGraphics();
-        graphics.transform(xform); // device transform (i.e. DPI)
-        drawer.drawTilingPattern(graphics, pattern, colorSpace, color);
+
+        // flip a -ve YStep around its own axis (see gs-bugzilla694385.pdf)
+        if (pattern.getYStep() < 0)
+        {
+            graphics.translate(0, rasterHeight);
+            graphics.scale(1, -1);
+        }
+
+        // flip a -ve XStep around its own axis
+        if (pattern.getXStep() < 0)
+        {
+            graphics.translate(rasterWidth, 0);
+            graphics.scale(-1, 1);
+        }
+
+        // device transform (i.e. DPI)
+        graphics.transform(xform);
+
+        // apply only the scaling from the pattern transform, doing scaling here improves the
+        // image quality and prevents large scale-down factors from creating huge tiling cells.
+        Matrix patternMatrix = Matrix.getScaleInstance(
+                Math.abs(pattern.getMatrix().getScaleX()),
+                Math.abs(pattern.getMatrix().getScaleY()));
+
+        // move origin to (0,0)
+        patternMatrix.concatenate(
+                Matrix.getTranslatingInstance(-pattern.getBBox().getLowerLeftX(),
+                        -pattern.getBBox().getLowerLeftY()));
+
+        // render using PageDrawer
+        drawer.drawTilingPattern(graphics, pattern, colorSpace, color, patternMatrix);
         graphics.dispose();
 
         return image;
     }
 
     /**
-     * Returns the closest integer which is larger than the given number.
+     * Returns the closest integer which is //larger than the given number.
      * Uses BigDecimal to avoid floating point error which would cause gaps in the tiling.
      */
     private static int ceiling(double num)
@@ -146,8 +184,10 @@ public class TilingPaint implements Pain
         return Transparency.TRANSLUCENT;
     }
 
-    // includes XStep/YStep
-    public static Rectangle2D getAnchorRect(PDTilingPattern pattern)
+    /**
+     * Returns the anchor rectangle, which includes the XStep/YStep and scaling.
+     */
+    private static Rectangle2D getAnchorRect(PDTilingPattern pattern)
     {
         float xStep = pattern.getXStep();
         if (xStep == 0)
@@ -161,7 +201,13 @@ public class TilingPaint implements Pain
             yStep = pattern.getBBox().getHeight();
         }
 
+        float xScale = pattern.getMatrix().getScaleX();
+        float yScale = pattern.getMatrix().getScaleY();
+
+        // returns the anchor rect with scaling applied
         PDRectangle anchor = pattern.getBBox();
-        return new Rectangle2D.Float(anchor.getLowerLeftX(), anchor.getLowerLeftY(), xStep, yStep);
+        return new Rectangle2D.Float(anchor.getLowerLeftX() * xScale,
+                anchor.getLowerLeftY() * yScale,
+                xStep * xScale, yStep * yScale);
     }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java?rev=1643042&r1=1643041&r2=1643042&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/text/TextPosition.java Wed Dec  3 02:02:13 2014
@@ -349,11 +349,11 @@ public final class TextPosition
     {
         if (rotation == 90 || rotation == 270)
         {
-            return Math.abs(endY - textMatrix.getYPosition());
+            return Math.abs(endY - textMatrix.getTranslateY());
         }
         else
         {
-            return Math.abs(endX - textMatrix.getXPosition());
+            return Math.abs(endX - textMatrix.getTranslateX());
         }
     }
 

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java?rev=1643042&r1=1643041&r2=1643042&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/Matrix.java Wed Dec  3 02:02:13 2014
@@ -26,10 +26,9 @@ import java.awt.geom.Point2D;
 /**
  * This class will be used for matrix manipulation.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.14 $
+ * @author Ben Litchfield
  */
-public class Matrix implements Cloneable
+public final class Matrix implements Cloneable
 {
     static final float[] DEFAULT_SINGLE =
     {
@@ -106,7 +105,9 @@ public class Matrix implements Cloneable
      * Set the values of the matrix from the AffineTransform.
      *
      * @param af The transform to get the values from.
+     * @deprecated This method is due to be removed, please contact us if you make use of it.
      */
+    @Deprecated
     public void setFromAffineTransform( AffineTransform af )
     {
         single[0] = (float)af.getScaleX();
@@ -166,7 +167,9 @@ public class Matrix implements Cloneable
      * Return a single dimension array of all values in the matrix.
      *
      * @return The values ot this matrix.
+     * @deprecated Use {@link float[][] #getValues} instead.
      */
+    @Deprecated
     public double[][] getValuesAsDouble()
     {
         double[][] retval = new double[3][3];
@@ -204,7 +207,19 @@ public class Matrix implements Cloneable
     }
 
     /**
-     * This will take the current matrix and multipy it with a matrix that is passed in.
+     * Scales this matrix by the given factors.
+     *
+     * @param sx x-scale
+     * @param sy y-scale
+     */
+    public void scale(float sx, float sy)
+    {
+        Matrix m = Matrix.getScaleInstance(sx, sy);
+        concatenate(m);
+    }
+
+    /**
+     * This will take the current matrix and multiply it with a matrix that is passed in.
      *
      * @param b The matrix to multiply by.
      *
@@ -350,7 +365,9 @@ public class Matrix implements Cloneable
      * Create a new matrix with just the scaling operators.
      *
      * @return A new matrix with just the scaling operators.
+     * @deprecated This method is due to be removed, please contact us if you make use of it.
      */
+    @Deprecated
     public Matrix extractScaling()
     {
         Matrix retval = new Matrix();
@@ -382,7 +399,9 @@ public class Matrix implements Cloneable
      * Create a new matrix with just the translating operators.
      *
      * @return A new matrix with just the translating operators.
+     * @deprecated This method is due to be removed, please contact us if you make use of it.
      */
+    @Deprecated
     public Matrix extractTranslating()
     {
         Matrix retval = new Matrix();
@@ -436,9 +455,13 @@ public class Matrix implements Cloneable
     }
 
     /**
-     * Get the xscaling factor of this matrix.
+     * Get the x-scaling factor of this matrix. This is a deprecated method which actually
+     * returns the x-scaling factor multiplied by the x-shear.
+     *
      * @return The x-scale.
+     * @deprecated Use {@link #getScaleX} instead
      */
+    @Deprecated
     public float getXScale()
     {
         float xScale = single[0];
@@ -469,9 +492,13 @@ public class Matrix implements Cloneable
     }
 
     /**
-     * Get the y scaling factor of this matrix.
+     * Get the y-scaling factor of this matrix. This is a deprecated method which actually
+     * returns the y-scaling factor multiplied by the y-shear.
+     *
      * @return The y-scale factor.
+     * @deprecated Use {@link #getScaleY} instead
      */
+    @Deprecated
     public float getYScale()
     {
         float yScale = single[4];
@@ -484,25 +511,79 @@ public class Matrix implements Cloneable
     }
 
     /**
-     * Get the x position in the matrix.
+     * Returns the x-scaling factor of this matrix.
+     */
+    public float getScaleX()
+    {
+        return single[0];
+    }
+
+    /**
+     * Returns the y-shear factor of this matrix.
+     */
+    public float getShearY()
+    {
+        return single[1];
+    }
+
+    /**
+     * Returns the x-shear factor of this matrix.
+     */
+    public float getShearX()
+    {
+        return single[3];
+    }
+
+    /**
+     * Returns the y-scaling factor of this matrix.
+     */
+    public float getScaleY()
+    {
+        return single[4];
+    }
+
+    /**
+     * Returns the x-translation of this matrix.
+     */
+    public float getTranslateX()
+    {
+        return single[6];
+    }
+
+    /**
+     * Returns the y-translation of this matrix.
+     */
+    public float getTranslateY()
+    {
+        return single[7];
+    }
+
+    /**
+     * Get the x position in the matrix. This method is deprecated as it is incorrectly named.
+     *
      * @return The x-position.
+     * @deprecated Use {@link #getTranslateX} instead
      */
+    @Deprecated
     public float getXPosition()
     {
         return single[6];
     }
 
     /**
-     * Get the y position.
+     * Get the y position. This method is deprecated as it is incorrectly named.
+     *
      * @return The y position.
+     * @deprecated Use {@link #getTranslateY} instead
      */
+    @Deprecated
     public float getYPosition()
     {
         return single[7];
     }
 
     /**
-     * Returns a COS array which represnets this matrix.
+     * Returns a COS array which represents this matrix.
      */
     public COSArray toCOSArray()
     {