How to merge forms from different files into one PDF?
I currently have a PdfReader and a PdfStamper that I am using to fill out a form. I now have to add another PDF to the end of the form I have been filling out, but when I do this, I lose all the interactive fields. This is what I currently have:
public static void addSectionThirteenPdf( PdfStamper stamper, Rectangle pageSize, int pageIndex){ PdfReader reader = new PdfReader("section13.pdf"); AcroFields fields = reader.getAcroFields(); fields.renameField("field", "field" + pageIndex); stamper.insertPage(pageIndex, pageSize); stamper.replacePage(reader, 1, pageIndex); }
PdfReader pdfTemplate = new PdfReader(pathToPdf); PdfStamper stamper = new PdfStamper(pdfTemplate, output); stamper.setFormFlattening(true); AcroFields fields = stamper.getAcroFields(); fields.setField(key, value); stamper.close();
Is there a way to merge using the first piece of code and merge both of the forms together?
Posted on StackOverflow on Feb 17, 2015 by user3585563
Depending on what you want exactly, different scenarios are possible, but in any case: you are doing it wrong. You should use either PdfCopy
or PdfSmartCopy
to merge documents.
The different scenarios are explained in the following video tutorial.
Merging different forms (having different fields)
If you want to merge different forms without flattening them, you should use PdfCopy
as is done in the MergeForms example:
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();
}
}
In this case, readers
is an array of PdfReader
instances containing different forms (with different field names), hence we use PdfCopy
and we make sure that we don't forget to use the setMergeFields()
method, or the fields won't be copied.
Merging identical forms (having identical fields)
In this case, we need to rename the fields, because we probably want different values on different pages. In PDF a field can only have a single value. If you merge identical forms, you have multiple visualizations of the same field, but each visualization will show the same value (because in reality, there is only one field).
Let's take a look at the MergeForms2 example:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
copy.setMergeFields();
document.open();
List readers = new ArrayList();
for (int i = 0; i keys = new HashSet(form.getFields().keySet());
for (String key : keys) {
form.renameField(key, String.format("%s_%d", key, i));
}
stamper.close();
reader.close();
return baos.toByteArray();
}
As you can see, the renameFields()
method creates a new document in memory. That document is merged with other documents using PdfSmartCopy
. If you'd use PdfCopy
here, your document would be bloated (as we'll soon find out).
Merging flattened forms
In the FillFlattenMerge1, we fill out the forms using PdfStamper
. The result is a PDF file that is kept in memory and that is merged using PdfCopy
. While this example is fine if you'd merge different forms, this is actually an example on how not to do it (as explained in the video tutorial).
The FillFlattenMerge2 shows how to merge identical forms that are filled out and flattened correctly:
public void manipulatePdf(String src, String dest)
throws DocumentException, IOException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
ByteArrayOutputStream baos;
PdfReader reader;
PdfStamper stamper;
AcroFields fields;
StringTokenizer tokenizer;
BufferedReader br = new BufferedReader(new FileReader(DATA));
String line = br.readLine();
while ((line = br.readLine()) != null) {
// create a PDF in memory
baos = new ByteArrayOutputStream();
reader = new PdfReader(SRC);
stamper = new PdfStamper(reader, baos);
fields = stamper.getAcroFields();
tokenizer = new StringTokenizer(line, ";");
fields.setField("name", tokenizer.nextToken());
fields.setField("abbr", tokenizer.nextToken());
fields.setField("capital", tokenizer.nextToken());
fields.setField("city", tokenizer.nextToken());
fields.setField("population", tokenizer.nextToken());
fields.setField("surface", tokenizer.nextToken());
fields.setField("timezone1", tokenizer.nextToken());
fields.setField("timezone2", tokenizer.nextToken());
fields.setField("dst", tokenizer.nextToken());
stamper.setFormFlattening(true);
stamper.close();
reader.close();
// add the PDF to PdfCopy
reader = new PdfReader(baos.toByteArray());
copy.addDocument(reader);
reader.close();
}
br.close();
document.close();
}
Now it's up to you to decide which scenario fits your specific requirement.