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 2020/09/28 19:37:50 UTC
svn commit: r1882099 - in /pdfbox/trunk/pdfbox/src:
main/java/org/apache/pdfbox/pdmodel/interactive/form/
test/java/org/apache/pdfbox/pdmodel/interactive/form/
test/resources/org/apache/pdfbox/pdmodel/interactive/form/
Author: msahyoun
Date: Mon Sep 28 19:37:50 2020
New Revision: 1882099
URL: http://svn.apache.org/viewvc?rev=1882099&view=rev
Log:
PDFBOX-4958 change calculation of transformation as suggested by mkl
Added:
pdfbox/trunk/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/PDFBOX-4958.pdf (with props)
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFlattenTest.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java?rev=1882099&r1=1882098&r2=1882099&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroForm.java Mon Sep 28 19:37:50 2020
@@ -16,6 +16,9 @@
*/
package org.apache.pdfbox.pdmodel.interactive.form;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Rectangle2D;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -28,14 +31,11 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.contentstream.operator.Operator;
-import org.apache.pdfbox.contentstream.operator.OperatorName;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -49,7 +49,6 @@ import org.apache.pdfbox.pdmodel.fdf.FDF
import org.apache.pdfbox.pdmodel.fdf.FDFDocument;
import org.apache.pdfbox.pdmodel.fdf.FDFField;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
-import org.apache.pdfbox.pdmodel.graphics.PDXObject;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget;
@@ -330,56 +329,15 @@ public final class PDAcroForm implements
contentStream.saveGraphicsState();
- //TODO read this: https://stackoverflow.com/a/54091766/535646
-
- // translate the appearance stream to the widget location if there is
- // not already a transformation in place
- boolean needsTranslation = resolveNeedsTranslation(appearanceStream);
-
- // scale the appearance stream - mainly needed for images
- // in buttons and signatures
- boolean needsScaling = resolveNeedsScaling(annotation, page.getRotation());
+ // see https://stackoverflow.com/a/54091766/1729265 for an explanation
+ // of the steps required
+ // this will transform the appearance stream form object into the rectangle of the
+ // annotation bbox and map the coordinate systems
+ Matrix transformationMatrix = resolveTransformationMatrix(annotation, appearanceStream);
+ Matrix appearanceStreamMatrix = appearanceStream.getMatrix();
+ appearanceStreamMatrix.concatenate(transformationMatrix);
- Matrix transformationMatrix = new Matrix();
- boolean transformed = false;
-
- if (needsTranslation)
- {
- transformationMatrix.translate(annotation.getRectangle().getLowerLeftX(),
- annotation.getRectangle().getLowerLeftY());
- transformed = true;
- }
-
- Matrix m = appearanceStream.getMatrix();
- int angle = (int) Math.round(Math.toDegrees(Math.atan2(m.getShearY(), m.getScaleY())));
- int rotation = (angle + 360) % 360;
-
- if (needsScaling)
- {
- PDRectangle bbox = appearanceStream.getBBox();
- PDRectangle fieldRect = annotation.getRectangle();
-
- float xScale;
- float yScale;
- if (rotation == 90 || rotation == 270)
- {
- xScale = fieldRect.getWidth() / bbox.getHeight();
- yScale = fieldRect.getHeight() / bbox.getWidth();
- }
- else
- {
- xScale = fieldRect.getWidth() / bbox.getWidth();
- yScale = fieldRect.getHeight() / bbox.getHeight();
- }
- transformationMatrix.scale(xScale, yScale);
- transformed = true;
- }
-
- if (transformed)
- {
- contentStream.transform(transformationMatrix);
- }
-
+ contentStream.transform(appearanceStreamMatrix);
contentStream.drawForm(fieldObject);
contentStream.restoreGraphicsState();
contentStream.close();
@@ -755,99 +713,32 @@ public final class PDAcroForm implements
{
dictionary.setFlag(COSName.SIG_FLAGS, FLAG_APPEND_ONLY, appendOnly);
}
-
- /**
- * Check if there is a translation needed to place the annotations content.
- *
- * @param appearanceStream
- * @return the need for a translation transformation.
- */
- private boolean resolveNeedsTranslation(PDAppearanceStream appearanceStream)
- {
- PDResources resources = appearanceStream.getResources();
- if (resources == null || !resources.getXObjectNames().iterator().hasNext())
- {
- return true;
- }
- Iterator<COSName> xObjectNames = resources.getXObjectNames().iterator();
- List<Object> tokens;
- try
- {
- tokens = new PDFStreamParser(appearanceStream).parse();
- }
- catch (IOException ex)
- {
- LOG.debug("Couldn't not parse appearance content stream - content might be misplaced", ex);
- return true;
- }
- while (xObjectNames.hasNext())
- {
- try
- {
- // if the BBox of the PDFormXObject does not start at 0,0
- // there is no need do translate as this is done by the BBox definition.
- COSName name = xObjectNames.next();
- PDXObject xObject = resources.getXObject(name);
- if (xObject instanceof PDFormXObject)
- {
- PDRectangle bbox = ((PDFormXObject) xObject).getBBox();
- float llX = bbox.getLowerLeftX();
- float llY = bbox.getLowerLeftY();
- if (Float.compare(llX, 0) != 0 && Float.compare(llY, 0) != 0)
- {
- // PDFBOX-4955: only if used
- for (int i = 0; i < tokens.size(); ++i)
- {
- if (tokens.get(i).equals(name) && i < tokens.size() - 1 &&
- tokens.get(i + 1).equals(Operator.getOperator(OperatorName.DRAW_OBJECT)))
- {
- return false;
- }
- }
- }
- }
- }
- catch (IOException e)
- {
- // we can safely ignore the exception here
- // as this might only cause a misplacement
- LOG.debug("Couldn't resolve possible need for translation - ignoring, content might be misplaced", e);
- }
- }
- // a field without specific settings typically needs to be translated
- // to the correct position
- return true;
+ private Matrix resolveTransformationMatrix(PDAnnotation annotation, PDAppearanceStream appearanceStream)
+ {
+ Rectangle2D transformedAppearanceBox = getTransformedAppearanceBBox(appearanceStream);
+ PDRectangle annotationRect = annotation.getRectangle();
+ Matrix transformationMatrix = new Matrix();
+ transformationMatrix.translate((float) (annotationRect.getLowerLeftX()-transformedAppearanceBox.getX()), (float) (annotationRect.getLowerLeftY()-transformedAppearanceBox.getY()));
+ transformationMatrix.scale((float) (annotationRect.getWidth()/transformedAppearanceBox.getWidth()), (float) (annotationRect.getHeight()/transformedAppearanceBox.getHeight()));
+ return transformationMatrix;
}
-
+
/**
- * Check if there needs to be a scaling transformation applied.
+ * Calculate the transformed appearance box.
+ *
+ * Apply the Matrix (or an identity transform) to the BBox of
+ * the appearance stream
*
- * @param annotation
- * @param rotation
- * @return the need for a scaling transformation.
- */
- private boolean resolveNeedsScaling(PDAnnotation annotation, int rotation)
+ * @param appearanceStream
+ * @return the transformed rectangle
+ */
+ private Rectangle2D getTransformedAppearanceBBox(PDAppearanceStream appearanceStream)
{
- PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
- // Check if there is a transformation within the XObjects content
- PDResources resources = appearanceStream.getResources();
- if (resources != null && resources.getXObjectNames().iterator().hasNext())
- {
- return true;
- }
- PDRectangle bbox = appearanceStream.getBBox();
- PDRectangle fieldRect = annotation.getRectangle();
- if (rotation == 90 || rotation == 270)
- {
- return Float.compare(bbox.getWidth(), fieldRect.getHeight()) != 0 ||
- Float.compare(bbox.getHeight(), fieldRect.getWidth()) != 0;
- }
- else
- {
- return Float.compare(bbox.getWidth(), fieldRect.getWidth()) != 0 ||
- Float.compare(bbox.getHeight(), fieldRect.getHeight()) != 0;
- }
+ Matrix appearanceStreamMatrix = appearanceStream.getMatrix();
+ PDRectangle appearanceStreamBBox = appearanceStream.getBBox();
+ GeneralPath transformedAppearanceBox = appearanceStreamBBox.transform(appearanceStreamMatrix);
+ return transformedAppearanceBox.getBounds2D();
}
private Map<COSDictionary,Set<COSDictionary>> buildPagesWidgetsMap(List<PDField> fields) throws IOException
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFlattenTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFlattenTest.java?rev=1882099&r1=1882098&r2=1882099&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFlattenTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFlattenTest.java Mon Sep 28 19:37:50 2020
@@ -230,7 +230,7 @@ public class PDAcroFormFlattenTest
*
* @throws IOException
*/
- // @Test
+ @Test
public void testFlattenOpenOfficeFormFilled() throws IOException
{
String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12840280/OpenOfficeForm_filled.pdf";
@@ -245,7 +245,7 @@ public class PDAcroFormFlattenTest
*
* @throws IOException
*/
- // @Test
+ @Test
public void testFlattenPDFBox4157() throws IOException
{
String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12976553/PDFBOX-4157-filled.pdf";
@@ -259,7 +259,7 @@ public class PDAcroFormFlattenTest
*
* @throws IOException
*/
- // @Test
+ @Test
public void testFlattenPDFBox4172() throws IOException
{
String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12976552/PDFBOX-4172-filled.pdf";
@@ -273,7 +273,7 @@ public class PDAcroFormFlattenTest
*
* @throws IOException
*/
- // @Test
+ @Test
public void testFlattenPDFBox4615() throws IOException
{
String sourceUrl = "https://issues.apache.org/jira/secure/attachment/12976452/resetboundingbox-filled.pdf";
@@ -339,6 +339,20 @@ public class PDAcroFormFlattenTest
flattenAndCompare(sourceUrl, targetFileName);
}
+ /**
+ * PDFBOX-4958 text and button with image.
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testFlattenPDFBox4958() throws IOException
+ {
+ String sourceUrl = "https://issues.apache.org/jira/secure/attachment/13012242/PDFBOX-4958.pdf";
+ String targetFileName = "PDFBOX-4958-flattened.pdf";
+
+ flattenAndCompare(sourceUrl, targetFileName);
+ }
+
/*
* Flatten and compare with generated image samples.
*
@@ -370,7 +384,7 @@ public class PDAcroFormFlattenTest
// cleanup input and output directory for matching files.
removeAllRenditions(inputFile);
inputFile.delete();
- outputFile.delete();
+ //outputFile.delete();
}
}
Added: pdfbox/trunk/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/PDFBOX-4958.pdf
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/PDFBOX-4958.pdf?rev=1882099&view=auto
==============================================================================
Binary file - no diff available.
Propchange: pdfbox/trunk/pdfbox/src/test/resources/org/apache/pdfbox/pdmodel/interactive/form/PDFBOX-4958.pdf
------------------------------------------------------------------------------
svn:mime-type = application/pdf