You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ms...@apache.org on 2016/05/01 21:43:15 UTC

svn commit: r1741883 - /pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java

Author: msahyoun
Date: Sun May  1 19:43:15 2016
New Revision: 1741883

URL: http://svn.apache.org/viewvc?rev=1741883&view=rev
Log:
PDFBOX-3333: calculate bbox and transformation matrix respecting rotation

Modified:
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java?rev=1741883&r1=1741882&r2=1741883&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java Sun May  1 19:43:15 2016
@@ -17,6 +17,7 @@
 package org.apache.pdfbox.pdmodel.interactive.form;
 
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -126,14 +127,28 @@ class AppearanceGeneratorHelper
                 else
                 {
                     appearanceStream = new PDAppearanceStream(field.getAcroForm().getDocument());
-                    appearanceStream.setBBox(widget.getRectangle().createRetranslatedRectangle());
+
+                    PDRectangle rect = widget.getRectangle();
+
+                    // Calculate the entries for the bounding box and the transformation matrix
+                    // settings for the appearance stream
+                    int rotation = resolveRotation(widget);
+                    Matrix matrix = Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0);
+                    Point2D.Float point2D = matrix.transformPoint(rect.getWidth(), rect.getHeight());
+
+                    PDRectangle bbox = new PDRectangle(Math.abs((float) point2D.getX()), Math.abs((float) point2D.getY()));
+                    appearanceStream.setBBox(bbox);
+
+                    appearanceStream.setMatrix(calculateMatrix(bbox, rotation));
+                    appearanceStream.setFormType(1);
+                    
                     appearanceDict.setNormalAppearance(appearanceStream);
                     // TODO support appearances other than "normal"
                 }
                 
                 /*
                  * Adobe Acrobat always recreates the complete appearance stream if there is an appearance characteristics
-                 * entry (the widget dictionaries MK entry). In addition if there is no content yet also create the apperance
+                 * entry (the widget dictionaries MK entry). In addition if there is no content yet also create the appearance
                  * stream from the entries.
                  * 
                  */
@@ -146,7 +161,20 @@ class AppearanceGeneratorHelper
             }
         }
     }
-    
+
+
+    private int resolveRotation(PDAnnotationWidget widget)
+    {
+        PDAppearanceCharacteristicsDictionary  characteristicsDictionary = widget.getAppearanceCharacteristics();
+        if (characteristicsDictionary != null)
+        {
+            // 0 is the default value if the R key doesn't exist
+            return characteristicsDictionary.getRotation();
+        }
+        return 0;
+    }
+
+
     /**
      * Initialize the content of the appearance stream.
      * 
@@ -262,16 +290,9 @@ class AppearanceGeneratorHelper
     {
         PDPageContentStream contents = new PDPageContentStream(field.getAcroForm().getDocument(),
                                                                appearanceStream, output);
-        
-        // Set an identity transformation in case there is no Matrix entry
-        Matrix matrix = appearanceStream.getMatrix();
-        if (matrix == null)
-        {
-            appearanceStream.setMatrix(new AffineTransform());
-        }
-        
-        appearanceStream.setFormType(1);
-        
+
+        PDRectangle bbox = resolveBoundingBox(widget, appearanceStream);
+
         // Acrobat calculates the left and right padding dependent on the offset of the border edge
         // This calculation works for forms having been generated by Acrobat.
         // The minimum distance is always 1f even if there is no rectangle being drawn around.
@@ -280,7 +301,6 @@ class AppearanceGeneratorHelper
         {
             borderWidth = widget.getBorderStyle().getWidth();
         }
-        PDRectangle bbox = resolveBoundingBox(widget, appearanceStream);
         PDRectangle clipRect = applyPadding(bbox, Math.max(1f, borderWidth));
         PDRectangle contentRect = applyPadding(clipRect, Math.max(1f, borderWidth));
         
@@ -384,6 +404,36 @@ class AppearanceGeneratorHelper
         contents.restoreGraphicsState();
         contents.close();
     }
+
+    private AffineTransform calculateMatrix(PDRectangle bbox, int rotation)
+    {
+        if (rotation == 0)
+        {
+            return new AffineTransform();
+        }
+        else
+        {
+            float tx=0, ty=0;
+
+            if (rotation == 90)
+            {
+                tx = bbox.getUpperRightY();
+            }
+            else if (rotation == 180)
+            {
+                tx = bbox.getUpperRightY();
+                ty = bbox.getUpperRightX();
+            }
+                else if (rotation == 270)
+            {
+                ty = bbox.getUpperRightX();
+            }
+
+            Matrix matrix = Matrix.getRotateInstance(Math.toRadians(rotation), tx, ty);
+            return matrix.createAffineTransform();
+        }
+    }
+
     
     private boolean isMultiLine()
     {