Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
2.0.16
-
None
-
Windows 10
Description
PDFBox 2.0.16 as well as the current SNAPSNOT version crashes with a NullPointerException. Attached is a small test that triggers the NPE, as well as the PDF.
The stack trace:
java.lang.NullPointerException at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.applyPadding(AppearanceGeneratorHelper.java:816) at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.insertGeneratedCombAppearance(AppearanceGeneratorHelper.java:611) at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.insertGeneratedAppearance(AppearanceGeneratorHelper.java:505) at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.setAppearanceContent(AppearanceGeneratorHelper.java:374) at org.apache.pdfbox.pdmodel.interactive.form.AppearanceGeneratorHelper.setAppearanceValue(AppearanceGeneratorHelper.java:223) at org.apache.pdfbox.pdmodel.interactive.form.PDTextField.constructAppearances(PDTextField.java:264) at org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField.applyChange(PDTerminalField.java:228) at org.apache.pdfbox.pdmodel.interactive.form.PDTextField.setValue(PDTextField.java:219) at PdfBoxTest.reformatFields(PdfBoxTest.java:67) at PdfBoxTest.flattenDocument(PdfBoxTest.java:52) at PdfBoxTest.flatten(PdfBoxTest.java:42) at PdfBoxTest.fileWithStrangeContent(PdfBoxTest.java:27)
The origin of the error seems to be in AppearanceGeneratorHelper.setAppearanceValue(). A PDAppearanceStream is created, but a bounding box is only set for it if this is false: if (appearance != null && appearance.isStream()). In my case, the conditional is true, and PDFBox takes a path where no bounding box gets set.
The following could be a solution, but I'm not very fluent in the inner workings of PDFs, and it's not directly obvious from looking at the code that this is a good approach.
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java index dc2825d4c..a82236069 100644 --- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java +++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java @@ -201,6 +201,7 @@ class AppearanceGeneratorHelper if (appearance != null && appearance.isStream()) { appearanceStream = appearance.getAppearanceStream(); + setBoundingBoxOnAppearanceStream(widget, appearanceStream); } else { @@ -235,15 +236,9 @@ class AppearanceGeneratorHelper // Calculate the entries for the bounding box and the transformation matrix // settings for the appearance stream - int rotation = resolveRotation(widget); - PDRectangle rect = widget.getRectangle(); - Matrix matrix = Matrix.getRotateInstance(Math.toRadians(rotation), 0, 0); - Point2D.Float point2D = matrix.transformPoint(rect.getWidth(), rect.getHeight()); + setBoundingBoxOnAppearanceStream(widget, appearanceStream); - PDRectangle bbox = new PDRectangle(Math.abs((float) point2D.getX()), Math.abs((float) point2D.getY())); - appearanceStream.setBBox(bbox); - - AffineTransform at = calculateMatrix(bbox, rotation); + AffineTransform at = calculateMatrix(appearanceStream.getBBox(), resolveRotation(widget)); if (!at.isIdentity()) { appearanceStream.setMatrix(at); @@ -252,7 +247,17 @@ class AppearanceGeneratorHelper appearanceStream.setResources(new PDResources()); return appearanceStream; } - + + private void setBoundingBoxOnAppearanceStream(PDAnnotationWidget widget, PDAppearanceStream appearanceStream) { + int rotation = resolveRotation(widget); + PDRectangle rect = widget.getRectangle(); + 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); + } + private PDDefaultAppearanceString getWidgetDefaultAppearanceString(PDAnnotationWidget widget) throws IOException { COSString da = (COSString) widget.getCOSObject().getDictionaryObject(COSName.DA);