Copy PDF with Annotations using iText

2019-01-28 09:30发布

问题:

We need to import existing multiple PDFs into a single new PDF. Part of codes work similar to the sample codes in section 6.2.1 of iText in Action 2nd edition:

Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(
    document, new FileOutputStream(RESULT));
document.open();
PdfPTable table = new PdfPTable(2);
PdfReader reader = new PdfReader(MovieTemplates.RESULT);
int n = reader.getNumberOfPages();
PdfImportedPage page;
for (int i = 1; i <= n; i++) {
    page = writer.getImportedPage(reader, i);
    table.addCell(Image.getInstance(page));
}
document.add(table);
document.close();

However, we just realized when dealing with fill-able PDFs with annotations (in our case, those PDF already have data filled), all the filled data are lost in new PDF.

We found the answer in the same section of the book:

It's important to understand the difference between resources needed to render the content of a page and the interactive features of a page. In general, these features are called annotations. They include links, text annotations, and form fields. Annotations aren't part of the content stream. They aren't listed in the resources dictionary of the page, but in the annotation dictionary. These interactive features aren't copied when using PdfImportedPage, which means that all interactivity is lost when copying a page with the getImportedPage() method of the PdfWriter class.

But what is the solution to keep those annotations?

回答1:

Being the author of the book you refer to, I'd like to point out that the examples in the book are somewhat outdated. The book will advise you to use PdfCopyFields to merge forms, but that class is deprecated in recent versions of iText.

Please take a look at the new examples:

  • MergeForms
  • MergeForms2

In other words: forms can now be copied/merged using the PdfCopy class, but it is imported to tell PdfCopy that the fields need to be merged as is done in the following code snippet:

public void createPdf(String filename) throws IOException, DocumentException {
    PdfReader[] readers = {
        new PdfReader(getFile1()),
        new PdfReader(getFile2())
    };
    createPdf(filename, readers);
}

public void createPdf(String filename, PdfReader[] readers)
    throws IOException, DocumentException {
    Document document = new Document();
    PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
    copy.setMergeFields();
    document.open();
    for (PdfReader reader : readers) {
        copy.addDocument(reader);
    }
    document.close();
    for (PdfReader reader : readers) {
        reader.close();
    }
}

The setMergeFields() method is the method you need to remember.