How to tell iText which fields to flatten first?

Tags: formsfill formflatten formpartial flatteningiText 7

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<String, PdfFormField> 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<String, PdfFormField> 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
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 this link if you want to see how to answer this question in iText 5.