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 16:21:06 UTC

svn commit: r1621462 - /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java

Author: tilman
Date: Sat Aug 30 14:21:05 2014
New Revision: 1621462

URL: http://svn.apache.org/r1621462
Log:
PDFBOX-2283: correct transform / clipping for appearance streams

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java

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=1621462&r1=1621461&r2=1621462&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 Sat Aug 30 14:21:05 2014
@@ -183,16 +183,74 @@ public class PageDrawer extends PDFGraph
                     PDAppearanceStream appearance = appearanceMap.get(appearanceName);
                     if (appearance != null)
                     {
-                        Point2D point = new Point2D.Float(rect.getLowerLeftX(), rect.getLowerLeftY());
+                        saveGraphicsState();
+
+                        PDRectangle bBox = appearance.getBoundingBox();
+                        
+                        Rectangle2D rect2D = new Rectangle2D.Float(
+                                rect.getLowerLeftX(), 
+                                rect.getLowerLeftY(), 
+                                rect.getWidth(), 
+                                rect.getHeight());
                         Matrix matrix = appearance.getMatrix();
-                        if (matrix != null)
+                        if (matrix == null)
                         {
-                            matrix.createAffineTransform().transform(point, point);
+                            matrix = new Matrix();
                         }
+                        // a) The appearance's bounding box (specified by its BBox entry) 
+                        // shall be transformed, using Matrix, to produce a quadrilateral 
+                        // with arbitrary orientation.
+                        Point2D p1 = new Point2D.Float(bBox.getLowerLeftX(), bBox.getLowerLeftY());
+                        Point2D p2 = new Point2D.Float(bBox.getUpperRightX(), bBox.getUpperRightY());
+                        matrix.createAffineTransform().transform(p1, p1);
+                        matrix.createAffineTransform().transform(p2, p2);
+                        Rectangle2D transformedBBox = 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()));
+
+                        // Spec 12.5.5:
+                        // b) A matrix A shall be computed that scales and translates 
+                        // the transformed appearance box to align with the edges
+                        // of the annotation?s rectangle
+                        //
+                        // code inspired from
+                        // http://stackoverflow.com/a/14015713/535646
+                        AffineTransform at = new AffineTransform();
+                        at.translate(rect2D.getMinX(), rect2D.getMinY());
+                        at.scale(rect2D.getWidth() / transformedBBox.getWidth(), rect2D.getHeight() / transformedBBox.getHeight());
+                        at.translate(-transformedBBox.getMinX(), -transformedBBox.getMinY());
+                        Matrix matrixA = new Matrix();
+                        matrixA.setFromAffineTransform(at);
+                        
+                        // c) 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
+                        Matrix matrixAA = matrix.multiply(matrixA);
+                        
+                        Point2D point = new Point2D.Float(matrixAA.getXPosition(), matrixAA.getYPosition());
+                        matrixAA.setValue(2, 0, 0);
+                        matrixAA.setValue(2, 1, 0);
+                        
+                        getGraphicsState().setCurrentTransformationMatrix(matrixAA);
+
+                        // Calculate clipping
+                        // As per spec: "a self-contained content stream that 
+                        // shall be rendered inside the annotation rectangle"
+                        Rectangle2D clipRect2D = new Rectangle2D.Float(
+                                (float) (rect2D.getMinX()-point.getX()),
+                                (float) (rect2D.getMinY()-point.getY()),
+                                (float) rect2D.getWidth(),
+                                (float) rect2D.getHeight());
+                        getGraphicsState().intersectClippingPath(new Area(clipRect2D));
+
                         graphics.translate((int) point.getX(), (int) point.getY());
                         lastClip = null;
                         processSubStream(appearance.getResources(), appearance.getStream());
                         graphics.translate(-(int) point.getX(), -(int) point.getY());
+                       
+                        restoreGraphicsState();
                     }
                 }
             }