You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2017/10/21 17:08:28 UTC

svn commit: r1812833 - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java test/java/org/apache/pdfbox/multipdf/PDFMergerUtilityTest.java

Author: tilman
Date: Sat Oct 21 17:08:28 2017
New Revision: 1812833

URL: http://svn.apache.org/viewvc?rev=1812833&view=rev
Log:
PDFBOX-3972: keep local destination page index to update page reference after cloning; add test

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/multipdf/PDFMergerUtilityTest.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java?rev=1812833&r1=1812832&r2=1812833&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/multipdf/PDFMergerUtility.java Sat Oct 21 17:08:28 2017
@@ -48,13 +48,17 @@ import org.apache.pdfbox.pdmodel.PDDocum
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.PageMode;
+import org.apache.pdfbox.pdmodel.common.PDDestinationOrAction;
 import org.apache.pdfbox.pdmodel.common.PDMetadata;
 import org.apache.pdfbox.pdmodel.common.PDNumberTreeNode;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDMarkInfo;
 import org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure.PDStructureTreeRoot;
 import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;
+import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
+import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
+import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
 import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
 import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
@@ -330,8 +334,29 @@ public class PDFMergerUtility
             destination.setVersion(srcVersion);
         }
 
+        int pageIndexOpenActionDest = -1;
         if (destCatalog.getOpenAction() == null)
         {
+            // PDFBOX-3972: get local dest page index, it must be reassigned after the page cloning
+            PDDestinationOrAction openAction = srcCatalog.getOpenAction();
+            PDDestination openActionDestination;
+            if (openAction instanceof PDActionGoTo)
+            {
+                openActionDestination = ((PDActionGoTo) openAction).getDestination();
+            }
+            else
+            {
+                openActionDestination = (PDDestination) openAction;
+            }
+            if (openActionDestination instanceof PDPageDestination)
+            {
+                PDPage page = ((PDPageDestination) openActionDestination).getPage();
+                if (page != null)
+                {
+                    pageIndexOpenActionDest = srcCatalog.getPages().indexOf(page);
+                }
+            }
+
             destCatalog.setOpenAction(srcCatalog.getOpenAction());
         }
 
@@ -546,6 +571,7 @@ public class PDFMergerUtility
         }
 
         Map<COSDictionary, COSDictionary> objMapping = new HashMap<>();
+        int pageIndex = 0;
         for (PDPage page : srcCatalog.getPages())
         {
             PDPage newPage = new PDPage((COSDictionary) cloner.cloneForNewDocument(page.getCOSObject()));
@@ -575,6 +601,24 @@ public class PDFMergerUtility
                 // TODO update mapping for XObjects
             }
             destination.addPage(newPage);
+            
+            if (pageIndex == pageIndexOpenActionDest)
+            {
+                // PDFBOX-3972: reassign the page.
+                // The openAction is either a PDActionGoTo or a PDPageDestination
+                PDDestinationOrAction openAction = destCatalog.getOpenAction();
+                PDPageDestination pageDestination;
+                if (destCatalog.getOpenAction() instanceof PDActionGoTo)
+                {
+                    pageDestination = (PDPageDestination) ((PDActionGoTo) openAction).getDestination();
+                }
+                else
+                {
+                    pageDestination = (PDPageDestination) openAction;
+                }
+                pageDestination.setPage(newPage);
+            }
+            ++pageIndex;
         }
         if (mergeStructTree)
         {

Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/multipdf/PDFMergerUtilityTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/multipdf/PDFMergerUtilityTest.java?rev=1812833&r1=1812832&r2=1812833&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/multipdf/PDFMergerUtilityTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/multipdf/PDFMergerUtilityTest.java Sat Oct 21 17:08:28 2017
@@ -23,6 +23,10 @@ import junit.framework.TestCase;
 
 import org.apache.pdfbox.io.MemoryUsageSetting;
 import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
+import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageFitDestination;
 import org.apache.pdfbox.rendering.PDFRenderer;
 
 /**
@@ -110,6 +114,47 @@ public class PDFMergerUtilityTest extend
                 "GlobalResourceMergeTestResult2.pdf",
                 MemoryUsageSetting.setupTempFileOnly());
     }
+    
+    /**
+     * PDFBOX-3972: Test that OpenAction page destination isn't lost after merge.
+     * 
+     * @throws IOException 
+     */
+    public void testPDFMergerOpenAction() throws IOException
+    {
+        try (PDDocument doc1 = new PDDocument())
+        {
+            doc1.addPage(new PDPage());
+            doc1.addPage(new PDPage());
+            doc1.addPage(new PDPage());
+            doc1.save(new File(TARGETTESTDIR,"MergerOpenActionTest1.pdf"));
+        }
+        
+        PDPageDestination dest;
+        try (PDDocument doc2 = new PDDocument())
+        {
+            doc2.addPage(new PDPage());
+            doc2.addPage(new PDPage());
+            doc2.addPage(new PDPage());
+            dest = new PDPageFitDestination();
+            dest.setPage(doc2.getPage(1));
+            doc2.getDocumentCatalog().setOpenAction(dest);
+            doc2.save(new File(TARGETTESTDIR,"MergerOpenActionTest2.pdf"));
+        }
+
+        PDFMergerUtility pdfMergerUtility = new PDFMergerUtility();
+        pdfMergerUtility.addSource(new File(TARGETTESTDIR, "MergerOpenActionTest1.pdf"));
+        pdfMergerUtility.addSource(new File(TARGETTESTDIR, "MergerOpenActionTest2.pdf"));
+        pdfMergerUtility.setDestinationFileName(TARGETTESTDIR + "MergerOpenActionTestResult.pdf");
+        pdfMergerUtility.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
+
+        try (PDDocument mergedDoc = PDDocument.load(new File(TARGETTESTDIR, "MergerOpenActionTestResult.pdf")))
+        {
+            PDDocumentCatalog documentCatalog = mergedDoc.getDocumentCatalog();
+            dest = (PDPageDestination) documentCatalog.getOpenAction();
+            assertEquals(4, documentCatalog.getPages().indexOf(dest.getPage()));
+        }
+    }
 
     // checks that the result file of a merge has the same rendering as the two source files
     private void checkMergeIdentical(String filename1, String filename2, String mergeFilename,