Hi,

when I merge to PDFs into one using PDFMerger the Destinations of the second PDF given are being lost.

I looked into PDFMergerUtility class and found that mergeInto called on Names' COSDictionary doesn't work as intended.

I tried to solve this problem, see the attached patch. Now I get both Destinations in the result PDF. My questions and annotations are prefixed with "###". Any feedback will be appreciated since my experience with PDFBox is just one working day young :-)

Wulf
Index: PDFMergerUtility.java
===================================================================
--- PDFMergerUtility.java       (revision 828085)
+++ PDFMergerUtility.java       (working copy)
@@ -224,9 +224,17 @@
             }
             else
             {
-                //warning, potential for collision here!!
-                destNames.getCOSDictionary().mergeInto( 
(COSDictionary)cloneForNewDocument( destination, srcNames ) );
-            }
+//               ### outcommented original code
+              //warning, potential for collision here!!
+//                COSDictionary x = (COSDictionary)cloneForNewDocument( 
destination, srcNames );
+                
+//                destNames.getCOSDictionary().mergeInto( x ); // ### this 
will just keep the destNames and not add x's Kids
+//                destNames.getCOSDictionary().addAll( x ); // ### alt: will 
will replace destNames Kids with x's
+              
+                cloneMerge(destination, srcNames, destNames);
+                
+            }   
+                
         }
 
         PDDocumentOutline destOutline = destCatalog.getDocumentOutline();
@@ -313,6 +321,14 @@
     }
     Map clonedVersion = new HashMap();
 
+
+  /**
+   * 
+   * @param destination
+   * @param base
+   * @return
+   * @throws IOException
+   */
     private COSBase cloneForNewDocument( PDDocument destination, Object base ) 
throws IOException
     {
         if( base == null )
@@ -389,6 +405,97 @@
         return retval;
     }
 
+
+    /**
+     * Deep clone and Merge from Base to Target.<br/>
+     * base and target must be instances of the same class.
+     * @param destination
+     * @param base
+     * @param target
+     * @throws IOException
+     */
+    private void cloneMerge( PDDocument destination, COSObjectable base, 
COSObjectable target) throws IOException
+    {
+        if( base == null )
+        {
+            return;
+        }
+        COSBase retval = (COSBase)clonedVersion.get( base );
+        if( retval != null )
+        {
+          return;
+          //we are done, it has already been converted. // ### Is that correct 
for cloneMerge???
+        }
+        else if( base instanceof List )
+        {
+            COSArray array = new COSArray();
+            List list = (List)base;
+            for( int i=0; i<list.size(); i++ )
+            {
+                array.add( cloneForNewDocument( destination, list.get( i ) ) );
+            }
+            ((List)target).add(array);
+        }
+        else if( base instanceof COSObjectable && !(base instanceof COSBase) )
+        {
+            cloneMerge(destination, ((COSObjectable)base).getCOSObject(), 
((COSObjectable)target).getCOSObject() );
+            clonedVersion.put( base, retval );
+        }
+        else if( base instanceof COSObject )
+        {
+          cloneMerge(destination, ((COSObject) base).getObject(),((COSObject) 
target).getObject() );
+          clonedVersion.put( base, retval );
+            
+        }
+        else if( base instanceof COSArray )
+        {
+            COSArray array = (COSArray)base;
+            for( int i=0; i<array.size(); i++ )
+            {
+              ((COSArray)target).add( cloneForNewDocument( destination, 
array.get( i ) ) );
+            }
+            clonedVersion.put( base, retval );
+        }
+        else if( base instanceof COSStream )
+        {
+          // does that make sense???
+            COSStream originalStream = (COSStream)base;
+            List keys = originalStream.keyList();
+            PDStream stream = new PDStream( destination, 
originalStream.getFilteredStream(), true );
+            clonedVersion.put( base, stream.getStream() );
+            for( int i=0; i<keys.size(); i++ )
+            {
+                COSName key = (COSName)keys.get( i );
+                stream.getStream().setItem( key, 
cloneForNewDocument(destination,originalStream.getItem(key)));
+            }
+            retval = stream.getStream(); 
+            target = retval;
+        }
+        else if( base instanceof COSDictionary )
+        {
+            COSDictionary dic = (COSDictionary)base;
+            List keys = dic.keyList();
+            clonedVersion.put( base, retval );
+            for( int i=0; i<keys.size(); i++ )
+            {
+                COSName key = (COSName)keys.get( i );
+                if (((COSDictionary)target).getItem(key)!=null){
+                   cloneMerge(destination, 
dic.getItem(key),((COSDictionary)target).getItem(key));
+                } else {
+                  ((COSDictionary)target).setItem( key, 
cloneForNewDocument(destination,dic.getItem(key)));
+                }
+            }
+        }
+        else
+        {
+            retval = (COSBase)base;
+        }
+        clonedVersion.put( base, retval );
+        
+    }
+
+    
+    
     private int nextFieldNum = 1;
 
     /**
@@ -430,5 +537,6 @@
             }
         }
     }
+    
 
 }

Reply via email to