Change data on PDF master page with iText

Question: I am using Adobe LiveCycle ES2 to design multipaged and taylor made PDF documents containing interactive forms. We build JAVA web server applications to manipulate these online PDF documents with iText 5.0 API library. By using LiveCycle I created a static XFA form with one master page and some watermark and text fields on the footer. I want to change these on the fly. I got a strange result. I added some text fields like TextWatermark, TextFieldDate and TextFieldName. The form I have created contains 10 pages so I expected Adobe Reader to present those fields on all the pages. The first page looks OK but my iText solution does not automatically update all other associated pages. What’s wrong? Answer: You are trying to format an Adobe Reader PDF document by using a master page. Master pages specify the layout and background for the XFA form design. XFA stands for XML Forms Architecture, a family of XML specifications. You add objects to the master page that will occupy the same position throughout the form. Your problem is that the new value of these text fields on the master page you have manipulated through iText do not carry on to the pages. You’re attempting to use iText to parse the PDF, populate the XFA form fields and then save the modified PDF back to your web server. You need to process XFA form data. The iText, you use, is an open-source Java library written to support the creation and manipulation of PDF document. Before writing the first line of code you should understand that XFA is not PDF, so the iText library has limited functions to manipulate your file. The good news is that the latest iText can both support XFA Dynamic Forms and XFA Static Forms created by Adobe Live Cycle Designer ES2. For details and sample codes visit iText web site. Adobe Live Cycle forum for developers can be found here. Look at this XFA form in the Live Cycle:
<?xml version="1.0" encoding="UTF-8"?>
<?xfa generator="AdobeLiveCycleDesignerES_V9.0.0.0.20091029.1.612548" APIVersion="3.1.9277.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/" timeStamp="2010-07-14T23:19:07Z" uuid="7b2544ce-7914-45ef-8a04-06c61ab070d0">

<template xmlns="http://www.xfa.org/schema/xfa-template/2.8/">

   <subform name="form1" layout="tb" locale="en_US">

      <pageSet>

         <pageArea name="Page1" id="Page1" numbered="0">

            <contentArea x="0.25in" y="0.25in" w="203.2mm" h="266.7mm"/>
            <medium stock="letter" short="215.9mm" long="279.4mm"/>
            <field name="MyTextField" y="273.05mm" x="6.35mm" w="203.2mm" h="5.2331mm">
               <ui>
                  <textEdit/>
               </ui>
               <font typeface="Myriad Pro">
                  <fill>
                     <color value="153,153,153"/>
                  </fill>
               </font>
               <margin topInset="0.5mm" bottomInset="0.5mm" leftInset="0.5mm" rightInset="0.5mm"/>
               <para hAlign="center"/>
               <bind match="global"/>
            </field>

         </pageArea>

      </pageSet>

.................
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
<annots/>
</xfdf></xdp:xdp>
It is XML, isn’t it? Identify the nodes and the route to your form fields. Pay attention to the comments of the following sample code:
    // Stamper is already created
    private void ChangeTextFieldOnMasterPage(PdfStamper stamper, String newData )
    {

        try {
            AcroFields form = stamper.getAcroFields();
            XfaForm xfaForm = form.getXfa();
           
            // IT MUST BE an XFA FORM!
            if( xfaForm !=null && xfaForm.isXfaPresent()){
                    // Controls of a Master page are copied to all pages. You must find them.
                    // This is what Master Page does exactly in a PDF file
                    int numpages = stamper.getReader().getNumberOfPages();
                    for( int i=0; i<numpages; i++){
                        // XML tree to your text field on the given page
                        String strKeyField = "form1[0].#pageSet[0].Page1[" + i + "].MyTextField[0]";
                        form.setField(strKeyField, newData);
                        // You can change other properties here
                        // form.setFieldProperty(strKeyField, "textcolor", BaseColor.GRAY, null);
                        // form.setFieldProperty(strKeyField, "bgcolor", BaseColor.RED, null);
                        // form.setFieldProperty(strKeyField, "setfflags", PdfFormField.FF_READ_ONLY, null);
                    }

                    xfaForm.setChanged( true );
                    xfaForm.setXfa( stamper.getWriter() );
             }

        }

        catch (DocumentException de)
        {
        }

        catch (IOException e)
        {
        }
    }
In the Live Cycle editor set the data binding property of your text fields to global at the Master Pages tab. Otherwise the changes you make on the master page may not be propagated through the document. See:
PDF form manipulation with LiveCycle for iText solution
Object settings on an Adobe Live Cycle XFA form