You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xmlgraphics.apache.org by ss...@apache.org on 2023/03/29 14:49:39 UTC

[xmlgraphics-fop] branch main updated: FOP-1722: Values in PDF Number Trees must be indirect references by Dave Roxburgh

This is an automated email from the ASF dual-hosted git repository.

ssteiner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/xmlgraphics-fop.git


The following commit(s) were added to refs/heads/main by this push:
     new 120b50fdf FOP-1722: Values in PDF Number Trees must be indirect references by Dave Roxburgh
120b50fdf is described below

commit 120b50fdf64cf9c2a52c86d9ca4e9340dbd2715f
Author: Simon Steiner <ss...@apache.org>
AuthorDate: Wed Mar 29 15:49:27 2023 +0100

    FOP-1722: Values in PDF Number Trees must be indirect references by Dave Roxburgh
---
 .../main/java/org/apache/fop/pdf/PDFNumsArray.java | 72 +++++++++++++++++++++-
 .../fop/render/pdf/PDFLogicalStructureHandler.java |  8 ---
 .../org/apache/fop/pdf/PDFLibraryTestSuite.java    |  1 +
 .../org/apache/fop/pdf/PDFNumsArrayTestCase.java   | 17 +++--
 .../org/apache/fop/pdf/PDFParentTreeTestCase.java  |  6 +-
 5 files changed, 87 insertions(+), 17 deletions(-)

diff --git a/fop-core/src/main/java/org/apache/fop/pdf/PDFNumsArray.java b/fop-core/src/main/java/org/apache/fop/pdf/PDFNumsArray.java
index e9e1855b0..aafff37fc 100644
--- a/fop-core/src/main/java/org/apache/fop/pdf/PDFNumsArray.java
+++ b/fop-core/src/main/java/org/apache/fop/pdf/PDFNumsArray.java
@@ -50,13 +50,83 @@ public class PDFNumsArray extends PDFObject {
         return this.map.size();
     }
 
+    /**
+     * Determines whether a value object should be converted to an indirect reference for inclusion in a Number Tree
+     * array according to the PDF spec.
+     * PDF1.0 - 1.2 - Spec is silent on this subject (as Number Trees don't exist).
+     * PDF1.3 & 1.4 - Values must be indirect object refs.
+     * PDF1.5       - Recommended: stream, dictionary, array, and string values be indirect object refs.
+     * PDF1.6 - 2.0 - Stream values must be indirect object refs.
+     *                Recommended: dictionary, array, and string values be indirect object refs.
+     * Method signals for values that must be, and those recommended to be indirect object refs.
+     * @param obj The object to be considered.
+     * @return True iff the object should be converted.
+     */
+    private boolean shouldConvertToRef(PDFObject obj) {
+        boolean retval = false;
+        if (getDocument() != null && getDocument().getPDFVersion() != null) {
+            switch (getDocument().getPDFVersion()) {
+                case V1_0: // fall-through
+                case V1_1: // fall-through
+                case V1_2:
+                    log.error("Number Tree used in PDF version " + getDocument().getPDFVersion());
+                    break;
+                case V1_3: // fall-through
+                case V1_4:
+                    retval = true;
+                    break;
+                case V1_5: // fall-through
+                case V1_6: // fall-through
+                case V1_7: // fall-through
+                case V2_0:
+                    if (obj instanceof PDFStream
+                            || obj instanceof PDFDictionary
+                            || obj instanceof PDFArray
+                            || obj instanceof PDFText) {
+                        retval = true;
+                    }
+                    break;
+                default:
+                    log.error("Unrecognised PDF version " + getDocument().getPDFVersion());
+                    break;
+            }
+        }
+        return retval;
+    }
+
+    /**
+     * This method provides conformance with the different PDF specs which require or recommend different types be used
+     * for Number Tree array values. Method indirects objects where indicated.
+     * @param obj The object to be considered for indirection.
+     * @return Either the object or a reference to the object.
+     */
+    private Object indirectIfReq(Object obj) {
+        PDFDocument doc = getDocument();
+        Object retval = obj;
+        if (obj instanceof PDFObject) {
+            PDFObject pdfObj = (PDFObject) obj;
+            PDFObject parent = pdfObj.getParent();
+            if (shouldConvertToRef(pdfObj)) {
+                if (!pdfObj.hasObjectNumber()) { // Needs registering with the doc.
+                    pdfObj.setParent(null); // Can't register if it has a parent.
+                    pdfObj = doc.registerObject(pdfObj);
+                    if (parent != null) {
+                        pdfObj.setParent(parent); // Reinstate original parent.
+                    }
+                }
+                retval = pdfObj.makeReference();
+            }
+        }
+        return retval;
+    }
+
     /**
      * Sets an entry.
      * @param key the key of the value to set
      * @param obj the new value
      */
     public void put(Integer key, Object obj) {
-        this.map.put(key, obj);
+        this.map.put(key, indirectIfReq(obj));
     }
 
     /**
diff --git a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
index 318892ba3..12bb7a85c 100644
--- a/fop-core/src/main/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
+++ b/fop-core/src/main/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
@@ -119,14 +119,6 @@ public class PDFLogicalStructureHandler {
      * Receive notification of the end of the current page.
      */
     void endPage() {
-        // TODO
-        // Values in a number tree must be indirect references to the PDF
-        // objects associated to the keys. To enforce that the array is
-        // registered to the PDF document. Unfortunately that can't be done
-        // earlier since a call to PDFContentGenerator.flushPDFDoc can be made
-        // before the array is complete, which would result in only part of it
-        // being output to the PDF.
-        // This should really be handled by PDFNumsArray
         pdfDoc.registerObject(pageParentTreeArray);
         parentTree.addToNums(currentPage.getStructParents(), pageParentTreeArray);
     }
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
index 2f7fccc3a..374540355 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFLibraryTestSuite.java
@@ -40,6 +40,7 @@ import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileAttachmentTestCase;
         PDFDocumentTestCase.class,
         PDFNullTestCase.class,
         PDFNumsArrayTestCase.class,
+        PDFNumsArrayPDFV17TestCase.class,
         PDFRectangleTestCase.class,
         PDFReferenceTestCase.class,
         PDFResourcesTestCase.class,
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFNumsArrayTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFNumsArrayTestCase.java
index d36775cda..035912a95 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFNumsArrayTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFNumsArrayTestCase.java
@@ -25,20 +25,25 @@ import org.junit.Before;
 import org.junit.Test;
 
 /**
- * Test case for {@link PDFNumsArray}.
+ * Test case for {@link PDFNumsArray}. Uses default PDF doc (version 1.4) - requires text values and number values to be
+ * included as refs.
  */
 public class PDFNumsArrayTestCase extends PDFObjectTestCase {
+    private static final String TEST_NAME = "Test name";
+    private static final int TEST_NUMBER = 10;
     private PDFNumsArray numsArray;
-    private String expectedString = "[0 /Test#20name 1 10]";
+    private String expectedString = "[0 1 0 R 1 2 0 R]";
+    private String expectedStringName = "/Test#20name";
+    private String expectedStringNumber = Integer.valueOf(TEST_NUMBER).toString();
 
     @Before
     public void setUp() {
         numsArray = new PDFNumsArray(parent);
-        numsArray.put(0, new PDFName("Test name"));
+        numsArray.setDocument(doc);
+        numsArray.put(0, new PDFName(TEST_NAME));
         PDFNumber num = new PDFNumber();
-        num.setNumber(10);
+        num.setNumber(TEST_NUMBER);
         numsArray.put(1, num);
-        numsArray.setDocument(doc);
 
         pdfObjectUnderTest = numsArray;
     }
@@ -50,5 +55,7 @@ public class PDFNumsArrayTestCase extends PDFObjectTestCase {
     @Test
     public void testOutput() throws IOException {
         testOutputStreams(expectedString, numsArray);
+        testOutputStreams(expectedStringName, doc.objects.get(1));
+        testOutputStreams(expectedStringNumber, doc.objects.get(2));
     }
 }
diff --git a/fop-core/src/test/java/org/apache/fop/pdf/PDFParentTreeTestCase.java b/fop-core/src/test/java/org/apache/fop/pdf/PDFParentTreeTestCase.java
index 6fa5d6a42..acb888e4e 100644
--- a/fop-core/src/test/java/org/apache/fop/pdf/PDFParentTreeTestCase.java
+++ b/fop-core/src/test/java/org/apache/fop/pdf/PDFParentTreeTestCase.java
@@ -24,7 +24,7 @@ import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 
 /**
  * Tests that the nums array in the ParentTree dictionary is correctly being split into
@@ -76,7 +76,7 @@ public class PDFParentTreeTestCase {
      */
     @Test
     public void testOutOfOrderSplit() throws Exception {
-        PDFStructElem structElem = mock(PDFStructElem.class);
+        PDFStructElem structElem = spy(PDFStructElem.class);
         for (int num = 50; num < 53; num++) {
             parentTree.addToNums(num, structElem);
         }
@@ -98,7 +98,7 @@ public class PDFParentTreeTestCase {
      * @throws Exception
      */
     private int getArrayNumber(int elementNumber) throws Exception {
-        PDFStructElem structElem = mock(PDFStructElem.class);
+        PDFStructElem structElem = spy(PDFStructElem.class);
         for (int structParent = 0; structParent < elementNumber; structParent++) {
             parentTree.addToNums(structParent, structElem);
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: commits-help@xmlgraphics.apache.org