How to merge documents correctly?

Using the Document and PdfWriter class in combination with the addTemplate() method to merge documents is a bad idea. That’s not what the addTemplate() method is meant for. You have explicitly or implicitly defined the page size for the Document you are working with. With the addTemplate() method, you add PdfImportedPage instances, and

  • when you add a new page with the same page size and rotation, you throw away all interactivity that exists in that page, but otherwise all is well,
  • when you add a new page with a different page size and rotation, you get the result you describe. Because of the difference in size, the imported page and the new page do not match. Parts get cut off, extra margins appear, rotations are different, etc.

This is all explained in chapter 6 of my book. You should use PdfCopy instead of PdfWriter. See for instance the FillFlattenMerge2 example:

Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
PdfReader reader;
String line = br.readLine();
// loop over readers
    // add the PDF to PdfCopy
    reader = new PdfReader(baos.toByteArray());
    copy.addDocument(reader);
    reader.close();
// end loop
document.close();

In your case, you also need to add page numbers, you can do this in a second go, as is done in the StampPageXofY example:

PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
PdfContentByte pagecontent;
for (int i = 0; i < n; ) {
    pagecontent = stamper.getOverContent(++i);
    ColumnText.showTextAligned(pagecontent, Element.ALIGN_RIGHT,
            new Phrase(String.format("page %s of %s", i, n)), 559, 806, 0);
}
stamper.close();
reader.close();

Or you can add them while merging, as is done in the MergeWithToc example.

Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
PageStamp stamp;
document.open();
int n;
int pageNo = 0;
PdfImportedPage page;
Chunk chunk;
for (Map.Entry<String, PdfReader> entry : filesToMerge.entrySet()) {
    n = entry.getValue().getNumberOfPages();
    for (int i = 0; i < n; ) {
        pageNo++;
        page = copy.getImportedPage(entry.getValue(), ++i);
        stamp = copy.createPageStamp(page);
        chunk = new Chunk(String.format("Page %d", pageNo));
        if (i == 1)
            chunk.setLocalDestination("p" + pageNo);
        ColumnText.showTextAligned(stamp.getUnderContent(),
                Element.ALIGN_RIGHT, new Phrase(chunk),
                559, 810, 0);
        stamp.alterContents();
        copy.addPage(page);
    }
}
document.close();
for (PdfReader r : filesToMerge.values()) {
    r.close();
}
reader.close();

I strongly advise against using PdfWriter to merge documents! It’s not impossible if you change the page size and the rotation of the page in the Document class, but you’re making it harder on yourself. Moreover: using PdfWriter also throws away all interactivity (links, annotations,…) that exists in the pages you’re merging. Your customer may experience that as a bug.

Leave a Comment