1 31 package org.pdfbox.util; 32 33 import java.io.File ; 34 import java.io.IOException ; 35 import java.util.ArrayList ; 36 import java.util.HashMap ; 37 import java.util.Iterator ; 38 import java.util.List ; 39 import java.util.Map ; 40 41 import org.pdfbox.cos.COSArray; 42 import org.pdfbox.cos.COSBase; 43 import org.pdfbox.cos.COSDictionary; 44 import org.pdfbox.cos.COSInteger; 45 import org.pdfbox.cos.COSName; 46 import org.pdfbox.cos.COSNumber; 47 import org.pdfbox.cos.COSObject; 48 import org.pdfbox.cos.COSStream; 49 import org.pdfbox.exceptions.COSVisitorException; 50 import org.pdfbox.pdmodel.PDDocument; 51 import org.pdfbox.pdmodel.PDDocumentCatalog; 52 import org.pdfbox.pdmodel.PDDocumentInformation; 53 import org.pdfbox.pdmodel.PDDocumentNameDictionary; 54 import org.pdfbox.pdmodel.PDPage; 55 import org.pdfbox.pdmodel.common.COSArrayList; 56 import org.pdfbox.pdmodel.common.COSObjectable; 57 import org.pdfbox.pdmodel.common.PDStream; 58 import org.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline; 59 import org.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem; 60 import org.pdfbox.pdmodel.interactive.form.PDAcroForm; 61 import org.pdfbox.pdmodel.interactive.form.PDField; 62 import org.pdfbox.pdmodel.interactive.form.PDFieldFactory; 63 64 71 public class PDFMergerUtility 72 { 73 74 private List sources; 75 private String destinationFileName; 76 77 80 public PDFMergerUtility() 81 { 82 sources = new ArrayList (); 83 } 84 85 89 public String getDestinationFileName() 90 { 91 return destinationFileName; 92 } 93 94 99 public void setDestinationFileName(String destination) 100 { 101 this.destinationFileName = destination; 102 } 103 104 109 public void addSource(String source) 110 { 111 sources.add(new File (source)); 112 } 113 114 119 public void addSource(File source) 120 { 121 sources.add(source); 122 } 123 124 130 public void mergeDocuments() throws IOException , COSVisitorException 131 { 132 PDDocument destination = null; 133 File sourceFile; 134 PDDocument source; 135 if (sources != null && sources.size() > 0) 136 { 137 try 138 { 139 Iterator sit = sources.iterator(); 140 sourceFile = (File ) sit.next(); 141 destination = PDDocument.load(sourceFile); 142 while (sit.hasNext()) 143 { 144 sourceFile = (File ) sit.next(); 145 source = PDDocument.load(sourceFile); 146 try 147 { 148 appendDocument(destination, source); 149 } 150 finally 151 { 152 if (source != null) 153 { 154 source.close(); 155 } 156 } 157 } 158 destination.save(destinationFileName); 159 } 160 finally 161 { 162 if (destination != null) 163 { 164 destination.close(); 165 } 166 } 167 } 168 } 169 170 171 179 public void appendDocument(PDDocument destination, PDDocument source) throws IOException 180 { 181 if( destination.isEncrypted() ) 182 { 183 throw new IOException ( "Error: destination PDF is encrypted, can't append encrypted PDF documents." ); 184 } 185 if( source.isEncrypted() ) 186 { 187 throw new IOException ( "Error: source PDF is encrypted, can't append encrypted PDF documents." ); 188 } 189 PDDocumentInformation destInfo = destination.getDocumentInformation(); 190 PDDocumentInformation srcInfo = source.getDocumentInformation(); 191 destInfo.getDictionary().mergeInto( srcInfo.getDictionary() ); 192 193 PDDocumentCatalog destCatalog = destination.getDocumentCatalog(); 194 PDDocumentCatalog srcCatalog = source.getDocumentCatalog(); 195 196 if( destCatalog.getOpenAction() == null ) 197 { 198 destCatalog.setOpenAction( srcCatalog.getOpenAction() ); 199 } 200 201 PDAcroForm destAcroForm = destCatalog.getAcroForm(); 202 PDAcroForm srcAcroForm = srcCatalog.getAcroForm(); 203 if( destAcroForm == null ) 204 { 205 cloneForNewDocument( destination, srcAcroForm ); 206 destCatalog.setAcroForm( srcAcroForm ); 207 } 208 else 209 { 210 mergeAcroForm(destination, destAcroForm, srcAcroForm); 211 } 212 213 COSArray destThreads = (COSArray)destCatalog.getCOSDictionary().getDictionaryObject( 214 COSName.getPDFName( "Threads" )); 215 COSArray srcThreads = (COSArray)cloneForNewDocument( 216 destination, 217 destCatalog.getCOSDictionary().getDictionaryObject( COSName.getPDFName( "Threads" ))); 218 if( destThreads == null ) 219 { 220 destCatalog.getCOSDictionary().setItem( COSName.getPDFName( "Threads" ), srcThreads ); 221 } 222 else 223 { 224 destThreads.addAll( srcThreads ); 225 } 226 227 COSName names = COSName.getPDFName( "Names" ); 228 PDDocumentNameDictionary destNames = destCatalog.getNames(); 229 PDDocumentNameDictionary srcNames = srcCatalog.getNames(); 230 if( srcNames != null ) 231 { 232 if( destNames == null ) 233 { 234 destCatalog.getCOSDictionary().setItem( names, cloneForNewDocument( destination, srcNames ) ); 235 } 236 else 237 { 238 destNames.getCOSDictionary().mergeInto( (COSDictionary)cloneForNewDocument( destination, srcNames ) ); 240 } 241 } 242 243 PDDocumentOutline destOutline = destCatalog.getDocumentOutline(); 244 PDDocumentOutline srcOutline = srcCatalog.getDocumentOutline(); 245 if( srcOutline != null ) 246 { 247 if( destOutline == null ) 248 { 249 PDDocumentOutline cloned = 250 new PDDocumentOutline( (COSDictionary)cloneForNewDocument( destination, srcOutline ) ); 251 destCatalog.setDocumentOutline( cloned ); 252 } 253 else 254 { 255 PDOutlineItem first = srcOutline.getFirstChild(); 256 PDOutlineItem clonedFirst = new PDOutlineItem( (COSDictionary)cloneForNewDocument( 257 destination, first )); 258 destOutline.appendChild( clonedFirst ); 259 } 260 } 261 262 String destPageMode = destCatalog.getPageMode(); 263 String srcPageMode = srcCatalog.getPageMode(); 264 if( destPageMode == null ) 265 { 266 destCatalog.setPageMode( srcPageMode ); 267 } 268 269 COSName pageLabels = COSName.getPDFName( "PageLabels" ); 270 COSDictionary destLabels = (COSDictionary)destCatalog.getCOSDictionary().getDictionaryObject( pageLabels ); 271 COSDictionary srcLabels = (COSDictionary)srcCatalog.getCOSDictionary().getDictionaryObject( pageLabels ); 272 if( srcLabels != null ) 273 { 274 int destPageCount = destination.getNumberOfPages(); 275 COSArray destNums = null; 276 if( destLabels == null ) 277 { 278 destLabels = new COSDictionary(); 279 destNums = new COSArray(); 280 destLabels.setItem( COSName.getPDFName( "Nums" ), destNums ); 281 destCatalog.getCOSDictionary().setItem( pageLabels, destLabels ); 282 } 283 else 284 { 285 destNums = (COSArray)destLabels.getDictionaryObject( COSName.getPDFName( "Nums" ) ); 286 } 287 COSArray srcNums = (COSArray)srcLabels.getDictionaryObject( COSName.getPDFName( "Nums" ) ); 288 for( int i=0; i<srcNums.size(); i+=2 ) 289 { 290 COSNumber labelIndex = (COSNumber)srcNums.getObject( i ); 291 long labelIndexValue = labelIndex.intValue(); 292 destNums.add( new COSInteger( labelIndexValue + destPageCount ) ); 293 destNums.add( cloneForNewDocument( destination, srcNums.getObject( i+1 ) ) ); 294 } 295 } 296 297 COSName metadata = COSName.getPDFName( "Metadata" ); 298 COSStream destMetadata = (COSStream)destCatalog.getCOSDictionary().getDictionaryObject( metadata ); 299 COSStream srcMetadata = (COSStream)srcCatalog.getCOSDictionary().getDictionaryObject( metadata ); 300 if( destMetadata == null && srcMetadata != null ) 301 { 302 PDStream newStream = new PDStream( destination, srcMetadata.getUnfilteredStream(), false ); 303 newStream.getStream().mergeInto( srcMetadata ); 304 newStream.addCompression(); 305 destCatalog.getCOSDictionary().setItem( metadata, newStream ); 306 } 307 308 List pages = source.getDocumentCatalog().getAllPages(); 310 Iterator pageIter = pages.iterator(); 311 while( pageIter.hasNext() ) 312 { 313 PDPage page = (PDPage)pageIter.next(); 314 PDPage newPage = 315 new PDPage( (COSDictionary)cloneForNewDocument( destination, page.getCOSDictionary() ) ); 316 destination.addPage( newPage ); 317 } 318 } 319 Map clonedVersion = new HashMap (); 320 321 private COSBase cloneForNewDocument( PDDocument destination, Object base ) throws IOException 322 { 323 if( base == null ) 324 { 325 return null; 326 } 327 COSBase retval = (COSBase)clonedVersion.get( base ); 328 if( retval != null ) 329 { 330 } 332 else if( base instanceof List ) 333 { 334 COSArray array = new COSArray(); 335 List list = (List )base; 336 for( int i=0; i<list.size(); i++ ) 337 { 338 array.add( cloneForNewDocument( destination, list.get( i ) ) ); 339 } 340 retval = array; 341 } 342 else if( base instanceof COSObjectable && !(base instanceof COSBase) ) 343 { 344 retval = cloneForNewDocument( destination, ((COSObjectable)base).getCOSObject() ); 345 clonedVersion.put( base, retval ); 346 } 347 else if( base instanceof COSObject ) 348 { 349 COSObject object = (COSObject)base; 350 retval = cloneForNewDocument( destination, object.getObject() ); 351 clonedVersion.put( base, retval ); 352 } 353 else if( base instanceof COSArray ) 354 { 355 COSArray newArray = new COSArray(); 356 COSArray array = (COSArray)base; 357 for( int i=0; i<array.size(); i++ ) 358 { 359 newArray.add( cloneForNewDocument( destination, array.get( i ) ) ); 360 } 361 retval = newArray; 362 clonedVersion.put( base, retval ); 363 } 364 else if( base instanceof COSStream ) 365 { 366 COSStream originalStream = (COSStream)base; 367 List keys = originalStream.keyList(); 368 PDStream stream = new PDStream( destination, originalStream.getFilteredStream(), true ); 369 clonedVersion.put( base, stream.getStream() ); 370 for( int i=0; i<keys.size(); i++ ) 371 { 372 COSName key = (COSName)keys.get( i ); 373 stream.getStream().setItem( key, cloneForNewDocument(destination,originalStream.getItem(key))); 374 } 375 retval = stream.getStream(); 376 } 377 else if( base instanceof COSDictionary ) 378 { 379 COSDictionary dic = (COSDictionary)base; 380 List keys = dic.keyList(); 381 retval = new COSDictionary(); 382 clonedVersion.put( base, retval ); 383 for( int i=0; i<keys.size(); i++ ) 384 { 385 COSName key = (COSName)keys.get( i ); 386 ((COSDictionary)retval).setItem( key, cloneForNewDocument(destination,dic.getItem(key))); 387 } 388 } 389 else 390 { 391 retval = (COSBase)base; 392 } 393 clonedVersion.put( base, retval ); 394 return retval; 395 } 396 397 private int nextFieldNum = 1; 398 399 408 private void mergeAcroForm(PDDocument destination, PDAcroForm destAcroForm, PDAcroForm srcAcroForm) 409 throws IOException 410 { 411 List destFields = destAcroForm.getFields(); 412 List srcFields = srcAcroForm.getFields(); 413 if( srcFields != null ) 414 { 415 if( destFields == null ) 416 { 417 destFields = new COSArrayList(); 418 destAcroForm.setFields( destFields ); 419 } 420 Iterator srcFieldsIterator = srcFields.iterator(); 421 while (srcFieldsIterator.hasNext()) 422 { 423 PDField srcField = (PDField)srcFieldsIterator.next(); 424 PDField destField = 425 PDFieldFactory.createField( 426 destAcroForm, 427 (COSDictionary)cloneForNewDocument(destination, srcField.getDictionary() )); 428 if ( destAcroForm.getField(destField.getFullyQualifiedName()) != null ) 431 { 432 destField.setPartialName("dummyFieldName"+(nextFieldNum++)); 433 } 434 destFields.add(destField); 435 } 436 } 437 } 438 439 } 440 | Popular Tags |