Class PdfMerger


  • public final class PdfMerger
    extends java.lang.Object
    Public entry point of the PD4ML PDF merge API. Combines page ranges selected independently from two (or more) existing PDF files into one output document, built entirely on the pd4ml com.pd4ml.pdf.cos object model/parser (no PDFBox, no other PDF library) -- the same foundation com.pd4ml.pdf.sign is built on.

    Every selected page is deep-cloned into a fresh object-numbering space (see COSObjectImporter), so the two sources' indirect object numbers never collide, regardless of how much they overlap in the originals. Each selected page's accessibility structure (tagging) is reconciled into a single merged /StructTreeRoot on a best-effort basis (see StructureTreeMerger): pages from a tagged source keep their structure, pages from an untagged source are simply included without any, and the merged document is tagged overall only if at least one selected page contributed structure.

    Encrypted source PDFs are supported: pass the source's user or owner password to the password-taking addSource overload (an empty or omitted password is tried too, covering the common case of a document that only restricts permissions with an owner password). The pd4ml COS reader decrypts transparently while parsing, so every page cloned from an encrypted source is handled exactly like one from a plain PDF; a source is only rejected if the given password fails to open it.

    The merged output itself can also be encrypted -- see encryptOutput(String, String) / encryptOutput(PdfEncryptor.Options).

    With exactly one source added, calling selectPages(...) is optional: with no selection, the result is that source's own pages, in their original order (decrypted, if the source was encrypted, unless encryptOutput(java.lang.String, java.lang.String) was also called) -- i.e. a filter/decrypt/re-encrypt pass rather than a true merge. With two or more sources, every source still requires an explicit selectPages(...) call.

    Not supported (v1): merging /AcroForm field hierarchies, named destinations, or outlines (their absence doesn't corrupt the output -- widget annotations still come along fine as ordinary page /Annots -- only the document-level field tree/outline tree is not reconciled).

    Thread-safety: a single PdfMerger instance may safely be shared across threads -- addSource(...)/encryptOutput(...) may be called concurrently (e.g. to add several sources in parallel), and mergeToBytes()/merge(...) always reads a consistent snapshot of whatever sources had been fully added by the time it runs. A source is only guaranteed to be included in a merge call that starts after its addSource(...) call has returned; racing addSource(...) against an in-flight mergeToBytes() call on the same instance may or may not pick it up, but never corrupts either call's result. Each PdfMergeSource returned by addSource(...) is likewise safe to hand off to another thread before that thread calls selectPages(...) on it.

    Example

    
     PdfMerger merger = new PdfMerger();
     merger.addSource(pdfABytes).selectPages("2-5,odd");
     merger.addSource(pdfBBytes, "sourceBPassword").selectPages("1,3,6+");
     merger.encryptOutput("openPassword", "ownerPassword");
     byte[] merged = merger.mergeToBytes();
     
    • Constructor Summary

      Constructors 
      Constructor Description
      PdfMerger()  
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      PdfMergeSource addSource​(byte[] pdfBytes)  
      PdfMergeSource addSource​(byte[] pdfBytes, java.lang.String password)  
      PdfMergeSource addSource​(java.io.File pdfFile)  
      PdfMergeSource addSource​(java.io.File pdfFile, java.lang.String password)  
      PdfMergeSource addSource​(java.io.InputStream pdfStream)  
      PdfMergeSource addSource​(java.io.InputStream pdfStream, java.lang.String password)  
      PdfMerger encryptOutput​(PdfEncryptor.Options options)  
      PdfMerger encryptOutput​(java.lang.String userPassword, java.lang.String ownerPassword)
      Configures the merged output to be encrypted with AES-256, the modern default.
      PdfMerger info​(java.lang.String key, java.lang.String value)
      Sets (or, if value is null, leaves unset) one /Info dictionary entry (e.g.
      void merge​(java.io.File outputFile)  
      void merge​(java.io.OutputStream out)  
      PdfMerger mergeOutlines​(boolean enabled)
      Opt-in (default false, so no existing caller's output changes): splice each source's own outline (bookmark) tree onto the merged output's, in source-processing order -- see OutlineMerger's own javadoc for the exact splice semantics and its one documented scope limitation (a source outline node pointing at a page that wasn't itself selected for the merge is not pruned -- only safe to enable when every page of every outline-contributing source is included in the merge).
      byte[] mergeToBytes()  
      • Methods inherited from class java.lang.Object

        equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • PdfMerger

        public PdfMerger()
    • Method Detail

      • encryptOutput

        public PdfMerger encryptOutput​(java.lang.String userPassword,
                                       java.lang.String ownerPassword)
        Configures the merged output to be encrypted with AES-256, the modern default. For finer control (algorithm choice, permission bits) use encryptOutput(PdfEncryptor.Options) instead.
      • mergeOutlines

        public PdfMerger mergeOutlines​(boolean enabled)
        Opt-in (default false, so no existing caller's output changes): splice each source's own outline (bookmark) tree onto the merged output's, in source-processing order -- see OutlineMerger's own javadoc for the exact splice semantics and its one documented scope limitation (a source outline node pointing at a page that wasn't itself selected for the merge is not pruned -- only safe to enable when every page of every outline-contributing source is included in the merge).
      • info

        public PdfMerger info​(java.lang.String key,
                              java.lang.String value)
        Sets (or, if value is null, leaves unset) one /Info dictionary entry (e.g. "Title", "Author") on the merged output. A merge builds a brand-new document from scratch and, unlike a single source's own trailer, has no /Info of its own to start from -- callers that want the merged file to carry over a document's existing metadata (e.g. PdfDocumentBase#append, which treats the document append(...) was called on as the one that "continues") must copy the values across explicitly via this method before calling mergeToBytes().