How to tell iText which fields to flatten first?
I have a PDF with text form fields at are layered one on top of the other. When I fill the fields via iText and flatten the form, the form field that I had created on top of the other form field is now on the bottom.
For instance, I have a text field named "number_field" and that is underneath a second text field that is titled "name_field". When I set the value for those fields via iText (so '10' for "number_field" and 'John' for "name_field"), the number_field is now on top of the name_field.
How do I change the order on the page of these fields with iText?
Posted on StackOverflow on Apr 14, 2015 by Matt
The easiest way to solve this problem, is to fill out the form in two passes! This is shown in the FillFormFieldOrder example. We fill out the form src
resulting in the flattened form dest
like this:
public void manipulatePdf(String src, String dest) throws Exception {
go2(go1(src), dest);
}
As you can see, we execute the go1()
method first:
public byte[] go1(String src) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(baos));
Document doc = new Document(pdfDoc);
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, false);
Map fields = form.getFormFields();
fields.get("sunday_1").setValue("1");
fields.get("sunday_2").setValue("2");
fields.get("sunday_3").setValue("3");
fields.get("sunday_4").setValue("4");
fields.get("sunday_5").setValue("5");
fields.get("sunday_6").setValue("6");
form.partialFormFlattening("sunday_1");
form.partialFormFlattening("sunday_2");
form.partialFormFlattening("sunday_3");
form.partialFormFlattening("sunday_4");
form.partialFormFlattening("sunday_5");
form.partialFormFlattening("sunday_6");
form.flattenFields();
doc.close();
return baos.toByteArray();
}
This fills out all the sunday_x
fields and uses partial form flattening to flatten only those fields. The go1()
method takes src
as parameter and returns a byte[]
will the partially flattened form.
The byte[]
will be used as a parameter for the go2()
method, that takes dest
as its second parameter. Now we are going to fill out the sunday_x_notes
fields:
public void go2(byte[] src, String dest) throws Exception {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(new RandomAccessSourceFactory().createSource(src),
new ReaderProperties()), new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
Map fields = form.getFormFields();
fields.get("sunday_1_notes").setValue("It's Sunday today, let's go to the sea");
fields.get("sunday_2_notes").setValue("It's Sunday today, let's go to the park");
fields.get("sunday_3_notes").setValue("It's Sunday today, let's go to the beach");
fields.get("sunday_4_notes").setValue("It's Sunday today, let's go to the woods");
fields.get("sunday_5_notes").setValue("It's Sunday today, let's go to the lake");
fields.get("sunday_6_notes").setValue("It's Sunday today, let's go to the river");
form.flattenFields();
pdfDoc.close();
}
As you can see, we now flatten all the fields. The result looks like this:
Screenshot
Now, you no longer have to worry about the order of the fields, not in the /Fields
array, not in the /Annots
array. The fields are filled out in the exact order you want to. The notes cover the dates now, instead of the other way round.
Click How to tell iText which fields to flatten first? if you want to see how to answer this question in iText 5.