Author: msahyoun Date: Sun Oct 11 15:19:57 2020 New Revision: 1882407 URL: http://svn.apache.org/viewvc?rev=1882407&view=rev Log: PDFBOX-4985: add form fields from widget annotations
Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFromAnnotsTest.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java?rev=1882407&r1=1882406&r2=1882407&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocumentCatalog.java Sun Oct 11 15:19:57 2020 @@ -41,11 +41,15 @@ import org.apache.pdfbox.pdmodel.graphic import org.apache.pdfbox.pdmodel.interactive.action.PDActionFactory; import org.apache.pdfbox.pdmodel.interactive.action.PDDocumentCatalogAdditionalActions; import org.apache.pdfbox.pdmodel.interactive.action.PDURIDictionary; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDNamedDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination; import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDField; +import org.apache.pdfbox.pdmodel.interactive.form.PDTerminalField; import org.apache.pdfbox.pdmodel.interactive.pagenavigation.PDThread; import org.apache.pdfbox.pdmodel.interactive.viewerpreferences.PDViewerPreferences; @@ -111,6 +115,20 @@ public class PDDocumentCatalog implement { COSDictionary dict = (COSDictionary)root.getDictionaryObject(COSName.ACRO_FORM); cachedAcroForm = dict == null ? null : new PDAcroForm(document, dict); + + // PDFBOX-4985 AcroForm with NeedAppearances true and empty fields array + // but Widgets in page annotations + if (cachedAcroForm != null && cachedAcroForm.getNeedAppearances() && cachedAcroForm.getFields().isEmpty()) + { + resolveFieldsFromWidgets(cachedAcroForm); + } + + // PDFBOX-4985 + // build the visual appearance as there is none for the widgets + if (cachedAcroForm != null && cachedAcroForm.getNeedAppearances()) + { + rebuildAppearances(cachedAcroForm); + } } return cachedAcroForm; } @@ -617,4 +635,47 @@ public class PDDocumentCatalog implement document.setVersion(1.5f); } } + + private void resolveFieldsFromWidgets(PDAcroForm acroForm) + { + LOG.debug("rebuilding fields from widgets"); + COSArray fields = acroForm.getCOSObject().getCOSArray(COSName.FIELDS); + for (PDPage page : document.getPages()) + { + try + { + List<PDAnnotation> annots = page.getAnnotations(); + for (PDAnnotation annot : annots) + { + if (annot instanceof PDAnnotationWidget) + { + fields.add(annot.getCOSObject()); + } + } + } + catch (IOException ioe) + { + LOG.debug("coukdn't read annotations for page " + ioe.getMessage()); + } + } + } + + private void rebuildAppearances(PDAcroForm acroForm) + { + for (PDField field : acroForm.getFieldTree()) + { + if (!field.getValueAsString().isEmpty()) + { + try + { + field.setValue(field.getValueAsString()); + } + catch (IOException ioe) + { + LOG.debug("couldn't generate appearance stream for field " + field.getFullyQualifiedName()); + LOG.debug(ioe.getMessage()); + } + } + } + } } Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java?rev=1882407&r1=1882406&r2=1882407&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java Sun Oct 11 15:19:57 2020 @@ -112,7 +112,7 @@ class AppearanceGeneratorHelper { throw new IOException("Could not process default appearance string '" + field.getDefaultAppearance() + "' for field '" + - field.getFullyQualifiedName() + "'", ex); + field.getFullyQualifiedName() + "': " + ex.getMessage(), ex); } } Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFromAnnotsTest.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFromAnnotsTest.java?rev=1882407&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFromAnnotsTest.java (added) +++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/PDAcroFormFromAnnotsTest.java Sun Oct 11 15:19:57 2020 @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.pdfbox.pdmodel.interactive.form; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +import java.io.IOException; +import java.net.URL; + + +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSDictionary; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.pdmodel.PDDocument; +import org.apache.pdfbox.pdmodel.PDDocumentCatalog; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test for the PDButton class. + * + */ +public class PDAcroFormFromAnnotsTest +{ + + private PDDocument document; + private PDAcroForm acroForm; + + @Before + public void setUp() + { + document = new PDDocument(); + acroForm = new PDAcroForm(document); + document.getDocumentCatalog().setAcroForm(acroForm); + } + + /** + * PDFBOX-4985 AcroForms entry but empty Fields array + * + * @throws IOException + */ + + @Test + public void testFromAnnots4985() throws IOException + { + + String sourceUrl = "https://issues.apache.org/jira/secure/attachment/13013354/POPPLER-806.pdf"; + + try (PDDocument testPdf = Loader.loadPDF(new URL(sourceUrl).openStream())) + { + PDDocumentCatalog catalog = testPdf.getDocumentCatalog(); + // need to do a low level cos access as the PDModel access will build the AcroForm + COSDictionary cosAcroForm = (COSDictionary) catalog.getCOSObject().getDictionaryObject(COSName.ACRO_FORM); + COSArray cosFields = (COSArray) cosAcroForm.getDictionaryObject(COSName.FIELDS); + assertEquals("Initially there shall be 0 fields", cosFields.size(), 0); + PDAcroForm acroForm = catalog.getAcroForm(); + assertTrue("After rebuild there shall be > 0 fields", acroForm.getFields().size() > 0); + } + } + + + @After + public void tearDown() throws IOException + { + document.close(); + } +}