Saturday, December 22, 2007

Getting started with iText - Part 15 (Register.java)

The next installation in Getting started with iText translates the Register example. It is a simple example that demonstrates how to fill in form fields with iText.

You can run the example "as is" with either MX7 or CF8. Though if you are using CF8 you could use the new cfpdf and cfpdfform tags instead. From what I understand CF8 does make use of iText behind the scenes for some of the PDF functionality. Though I do not know to what extent. For comparison purposes I have also included a CF8 example below.

The iText example fills in a form and creates two output files. The only difference between them is that one of the output files is flattened. Meaning the form field values can no longer be modified.

What you will need for this example


A sample form from the iText site: SimpleRegistrationForm.pdf. Download the file and place it in the same directory as your .cfm script.

Code


Documentation: Manipulating existing PDF documents
Source: Register.java

iText Example

<h1>Fill in Registration Form Fields Example</h1>
<cfscript>
savedErrorMessage = "";

// cfSearching: All file paths are relative to the current directory
fullPathToInputFile = ExpandPath("./SimpleRegistrationForm.pdf");
fullPathToOutputFile1 = ExpandPath("./Registered.pdf");
fullPathToOutputFile2 = ExpandPath("./Registered_Flat.pdf");

try {
// we create a reader for a certain document
pdfReader1 = createObject("java", "com.lowagie.text.pdf.PdfReader").init(fullPathToInputFile);
//cfSearching: fill in the form fields but do not flatten the form
outputStream1 = createObject("java", "java.io.FileOutputStream").init(fullPathToOutputFile1);
pdfStamper1 = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(pdfReader1, outputStream1);
form1 = pdfStamper1.getAcroFields();
form1.setField("name", "Bruno Lowagie");
form1.setField("address", "Baeyensstraat 121, Sint-Amandsberg");
form1.setField("postal_code", "BE-9040");
form1.setField("email", "bruno@lowagie.com");

//cfSearching: fill in the form fields AND flatten the form
pdfReader2 = createObject("java", "com.lowagie.text.pdf.PdfReader").init(fullPathToInputFile);
outputStream2 = createObject("java", "java.io.FileOutputStream").init(fullPathToOutputFile2);
pdfStamper2 = createObject("java", "com.lowagie.text.pdf.PdfStamper").init(pdfReader2, outputStream2);
form2 = pdfStamper2.getAcroFields();
form2.setField("name", "Bruno Lowagie");
form2.setField("address", "Baeyensstraat 121, Sint-Amandsberg");
form2.setField("postal_code", "BE-9040");
form2.setField("email", "bruno@lowagie.com");
pdfStamper2.setFormFlattening(true);

WriteOutput("Finished!");

}
catch (java.language.Exception de) {
savedErrorMessage = de;
}
// cfSearching: close the stamper and output stream objects
pdfStamper1.close();
outputStream1.close();
pdfStamper2.close();
outputStream2.close();
</cfscript>


<!--- show any errors --->
<cfif len(savedErrorMessage) gt 0>
Error - unable to create document
<cfdump var="#savedErrorMessage#">
</cfif>


ColdFusion 8 Example

<h1>Fill in Registration Form Fields CF8 Example</h1>

<cfset fullPathToInputFile = ExpandPath("./SimpleRegistrationForm.pdf")>
<cfset fullPathToOutputFile1 = ExpandPath("./Registered.pdf")>
<cfset fullPathToOutputFile2 = ExpandPath("./Registered_Flat.pdf")>

<!--- fill in the form fields. will NOT overwrite existing file ---->
<cfpdfform action="populate" source="#fullPathToInputFile#" destination="#fullPathToOutputFile1#">
<cfpdfformparam name="name" value="Bruno Lowagie">
<cfpdfformparam name="address" value="Baeyensstraat 121, Sint-Amandsberg">
<cfpdfformparam name="postal_code" value="BE-9040">
<cfpdfformparam name="email" value="bruno@lowagie.com">
</cfpdfform>

<!--- use completed form created in previous step and flatten it ---->
<cfpdf action="write" source="#fullPathToOutputFile1#"
destination="#fullPathToOutputFile2#"
flatten="true" >
Finished!

14 comments:

Jason July 6, 2008 at 9:16 PM  

Hi

I've created a PDF form template with pre-populated fields and I used setfield to prepopulate again with data from the DB (MS-SQL). It worked (with the new data from DB) if I did not "setFormFlattening" to true but the fields remain editable. If I flattened the form, all the form fields became blank/empty. Any idea why?

http://rapidshare.com/files/127765260/Bill2.pdf

cfSearching July 7, 2008 at 5:23 AM  

@Jason,

AFAIK, iText has limited support for non-Acrobat forms, and it sounds like that is what you are using.
http://itext.ugent.be/library/question.php?id=30

Even with ColdFusion 8, the cfpdf tag supports flattening with Acrobat forms only.

... Applies to forms created in Acrobat only (not forms created in LiveCycle)...
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=Tags_p-q_02.html

Merritt Chapman,  August 21, 2009 at 9:21 AM  

Is it possible to only flatten some of the form fields and not all of them? I would like some fields to remain editable.

cfSearching August 21, 2009 at 11:05 AM  

@Merritt,

Yes. Use the partialFormFlattening() method.

// enable flattening
pdfStamper.setFormFlattening(true);
//call for _each_ field you want to flatten
pdfStamper.partialFormFlattening("name");
pdfStamper.partialFormFlattening("address");

-Leigh

Webpointz August 24, 2009 at 11:58 AM  

I have code in CFMX using iText that creates a PDF with acrofields.

Here is an example of one:

name1.setOptions = (TextField.READ_ONLY);

They are set as readonly because I am using javascript to populate the fields from a browser and everything works great except for one thing.

One of them is a MULTILINE comment box which needs to be both multiline AND readonly. When I try to use the following according to iText:

name1.setOptions = (TextField.READ_ONLY | TextField.MULTILINE);

it throws the following error in CF:

"coldfusion.compiler.TokenMgrError: Invalid token &nbsp found on line"

Any ideas on how to set this acrofield for both options?

cfSearching August 24, 2009 at 12:14 PM  

@Webpointz,

Try using the BitOr(opt1, opt2) function instead of "|".

-Leigh

cfSearching August 24, 2009 at 12:17 PM  

@Webpointz,

Also, verify your syntax. You should probably be using:

name.setOptions(...)

.. instead of

name.setOptions = (...)

-Leigh

Webpointz September 1, 2009 at 6:02 AM  

Excellent advise...many thanks.

Replaced
name.setOptions(TextField.MULTILINE);

with

name.setOptions(BitOr(TextField.MULTILINE,TextField.READ_ONLY));

Webpointz September 1, 2009 at 6:09 AM  

I have one remaining piece of the puzzle left that maybe you might know the answer to...

My PDF has a "signature" field. When signing, if you check the box that says "Lock after signing" the doc level javascript I have under the signature field never fires. Is there any way to negate the checkbox if the user selects it?

cfSearching September 1, 2009 at 1:07 PM  

@Webpointz,

Not without invalidating, no. Unless you were using psuedo-locking mechanism.

-Leigh

Webpointz September 2, 2009 at 8:39 AM  

Thanks

Is there any way to extract/read any part or parts of the signature on the signed document?

I can't find any information on checking some basic information from the signature to check the signer.

Webpointz September 3, 2009 at 1:18 PM  

Thanks...found the way around the issue which is related to changes made to Reader in v9.1.

The newest version allows a person to "lock" the document after signing, however, if you add an additional "invisible" signature field, the checkbox option disappears when signing.

Webpointz December 7, 2009 at 8:41 AM  

I have a signature field which contains a MOUSEUP javascript which performs perfectly, however, in order to change text below the signature field before signing I also require the field to have a ONFOCUS script so that the text changes before the MOUSEUP...would you have any ideas on how to do this?

Can't find any examples and the folks at iText keep saying use OnFocus but refuse to elaborate.

cfSearching December 7, 2009 at 11:53 AM  

@Webpointz,

Did you see Leonard and Bruno's responses? It looks like you just need to grab a reference to your signature field. Then use field.setAdditionalActions to add the javascript focus event. I do not have time to write up anything right now. But let me know if later if you get stuck with it.

Can't find any examples and the folks at iText keep saying use OnFocus but refuse to elaborate

I can sympathize with being in the dark and just searching for an entry point. Sometimes that is the best way to phrase it. ie I just need a hint / chapter number / etcetera and can take it from there. That tends to get a better response on free lists with a higher volume/complexity level like iText.

People are very helpful, but given the sheer volume of questions, responses tend to be blunt, usually consisting more of concept than code. (There is just not enough time in the day for anything else.)

Because there are so many examples out there, the expectations on doing your research are a lot higher. Truthfully, I have to say the iText examples are some of the most comprehensive I have seen for an open source project. Unfortunately, the examples (like the list) is all java. That puts some of us CF'ers at a bit of a disadvantage. But, it is as a good opportunity to expand our programming repertoire ;-)

-Leigh

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep