Thursday, May 7, 2009

ColdFusion: Debugging CFPDFForm Information (It's never enough)

Previously, I mentioned some gotchas with handling checkboxes and radio buttons with cfpdfform. One of the most common being, using the wrong "value". Which got me to wondering, how would you verify the values are correct or incorrect, other trial and error?

Using <cfpdform action="read" ..> only returns a field's current value. It does not return all of the possible options for fields like lists, checkboxes, etcetera. But you can use iText's AcroFields class to access more detailed information about Acrobat form fields. Using the AcroFields metadata, you could easily put together a great debugging function

There is a good basis for a function in one of the great examples on the iText site. Using it as a foundation, I whipped a quick function and voila: an array of detailed field information like field type, list options/values, page numbers, coordinates, etcetera.



But it could easily be modified to return fewer or more details, if desired. Ahh, the beauty of iText.


<!---
USAGE
--->
<cfset results = pdfFormFieldDump( ExpandPath("./register_form1.pdf") )>
<cfdump var="#results#" label="pdfFormFieldDump">

<!---
FUNCTION
--->
<cffunction name="pdfFormFieldDump" returntype="array">
<cfargument name="path" type="string" required="true">

<cfset var i = "" >
<cfset var prop = "" >
<cfset var name = "" >
<cfset var type = "" >
<cfset var reader = "" >
<cfset var positions = "" >
<cfset var fieldData = "">
<cfset var AcroFields = "" >
<cfset var formData = "" >
<cfset var fieldNames = "" >

<cfscript>
// read in the pdf file and get the form field metadata
reader = createObject("java", "com.lowagie.text.pdf.PdfReader").init( arguments.path );
AcroFields = createObject("java", "com.lowagie.text.pdf.AcroFields");
formData = reader.getAcroFields();
fieldNames = structKeyArray(formData.getFields());

// extract the properties of each field
fieldData = arrayNew(1);
for (i = 1; i lte arrayLen(fieldNames); i = i +1)
{
// get the current field
name = fieldNames[i];
type = formData.getFieldType( name );

// initialize a new structure for storing this field's properties
prop = structNew();
prop.fieldName = name;
positions = formData.getFieldPositions( name );
prop.page = positions[1];
prop.llx = positions[2];
prop.lly = positions[3];
prop.urx = positions[4];
prop.ury = positions[5];

// store the field type and properties
if ( type eq AcroFields.FIELD_TYPE_CHECKBOX )
{
prop.type = "Checkbox";
prop.states = formData.getAppearanceStates( name );
}
else if ( type eq AcroFields.FIELD_TYPE_COMBO )
{
prop.type = "Combobox";
prop.options = formData.getListOptionExport( name );
prop.values = formData.getListOptionDisplay( name );
}
else if ( type eq AcroFields.FIELD_TYPE_LIST )
{
prop.type = "List";
prop.options = formData.getListOptionExport( name );
prop.values = formData.getListOptionDisplay( name );
}
else if ( type eq AcroFields.FIELD_TYPE_NONE )
{
prop.type = "None";
prop.value = formData.getField( name );
}
else if ( type eq AcroFields.FIELD_TYPE_PUSHBUTTON )
{
prop.type = "Pushbutton";
prop.value = formData.getField( name );
}
else if ( type eq AcroFields.FIELD_TYPE_RADIOBUTTON )
{
prop.type = "Radiobutton";
prop.states = formData.getAppearanceStates( name );
}
else if ( type eq AcroFields.FIELD_TYPE_SIGNATURE )
{
prop.type = "Signature";
}
else if ( type eq AcroFields.FIELD_TYPE_TEXT )
{
prop.type = "Text";
prop.value = formData.getField( name );
}
else
{
prop.type = "Unknown";
prop.value = formData.getField( name );
}

// save the properties in the main array
arrayAppend( fieldData, prop );
}
</cfscript>

<cfreturn fieldData >
</cffunction>

2 comments:

Anonymous,  July 10, 2009 at 2:04 AM  

Thanks a lot for this piece of code! I've been trying to use cfpdfform to get fields info but it doesn't do the job. iText looks like a great library, cheers.

cfSearching July 10, 2009 at 11:35 AM  

@Anonymous,

Glad it was helpful. Definitely play around with iText some more if you get a chance. It is a terrific library!

-Leigh

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep