Tuesday, December 18, 2007

Creating a wicked Film Festival VIP Pass with iText - Part 2 (Code)

Here is the complete code for Creating a wicked Film Festival VIP Pass with iText - Part 2


UPDATE: I wanted to re-emphasize an issue that is mentioned in the instructions for this entry. MX users that are running the JavaLoader.cfc must read the article Using a Java URLClassLoader in CFMX Can Cause a Memory Leak.

In summary it is recommended that you store a single instance of the javaLoader in the server scope, rather than creating a new object each time. This prevents a memory leak caused by a bug in ColdFusion MX. I do not know if this bug exists in ColdFusion 8.

The code for this example creates a new instance of the JavaLoader on each request. This was intended only to demonstrate how to use the JavaLoader. To avoid any confusion, future code examples will use a server scoped object instead.



<!---
filmFestivalForm.cfm
--->
<style type="text/css">
tr.unity { font-family: verdana,arial,helvetica; }
td { padding: 5px 5px 7px 8px; }
</style>

<h1>Accreditation Card Example - Step 2A (FillForm)</h1>
<form action="FilmFestivalFormAction.cfm" method="POST" enctype="multipart/form-data">
<fieldset>
<table>
<tr class="unity">
<td>Name:</td>
<td><input type="Text" name="name"></td>
</tr>
<tr class="unity">
<td>Number:</td>
<td><input type="Text" name="number"></td>
</tr>
<tr class="unity">
<td>Type:</td>
<td><select name="type">
<option value="1">Guest</option>
<option value="2">Student</option>
<option value="3">Press</option>
<option value="4">Jury</option>
<option value="5">Vip Pass</option>
<option value="6">Crew</option>
</select><br>
<select name="color">
<option value="1">No admittance</option>
<option value="2">Press screenings only</option>
<option value="3">All screenings, no priority</option>
<option value="4">All screenings, priority</option>
<option value="5">Top priority</option>
</select>
</td>
</tr>
<tr class="unity">
<td>Photo:</td>
<td><input type="File" name="photo"></td>
</tr>
<tr class="unity">
<td>Flatten:</td>
<td><input type="Checkbox" name="flatten" value="1"></td>
</tr>
<tr class="unity"><td> </td><td><input type="Submit" value="Generate the PDF"></td></tr>
</table>
</fieldset>
</form>

<!---
filmFestivalFormAction.cfm
--->
<h1>Accreditation Card Example - Step 2B (FillForm)</h1>

<!--- sets default if flatten box was not checked --->
<cfparam name="form.flatten" default="0">
<!---
cfSearching: all file paths are relative to the current
directory. Your file paths may be different
--->
<cfset fileSeparator = "/">
<cfset fullPathToPhotoFile = "">
<cfset fullPathToTemplateForm = ExpandPath("./accreditation_form.pdf")>
<cfset fullPathToOutputFile = ExpandPath("./accreditation_1.pdf")>
<cfset fullPathToITextJar = ExpandPath("./iText-2.0.7.jar") >
<cfset dotNotationPathToJavaLoader = "javaloader.JavaLoader" >

<!--- if a file was submitted, upload it to the current directory --->
<cfif structKeyExists(form, "photo") AND len(trim(form.photo))>
<cftry>
<cffile action="upload" filefield="form.photo"
accept="image/jpeg, image/pjpeg, image/gif, image/png"
destination="#ExpandPath('.')#"
nameconflict="makeunique"
result="savedTo">

<cfset fullPathToPhotoFile = savedTo.serverDirectory & fileSeparator & savedTo.serverFile >

<cfcatch type="any">
<!--- ignoring upload errors --->
</cfcatch>
</cftry>
</cfif>

<!--- fix the file paths. the "/" separator *should* work on all O/S --->
<cfset fullPathToTemplateForm = replace(fullPathToTemplateForm, "\", fileSeparator, "all")>
<cfset fullPathToOutputFile = replace(fullPathToOutputFile, "\", fileSeparator, "all")>
<cfset fullPathToPhotoFile = replace(fullPathToPhotoFile, "\", fileSeparator, "all")>

<!--- utility function --->
<cffunction name="mmToPoints" returntype="numeric" access="public" output="false"
hint="Converts millimeters to PostScript points">

<cfargument name="millimeters" type="numeric" required="true">
<cfreturn javacast("float", (arguments.millimeters * 2.8346456)) />
</cffunction>

<cfscript>
savedErrorMessage = "";

// cfSearching: the array positions are signifigant. they correspond to the
// cfSearching: select list values in the HTML form
passType = listToArray("Guest,Student,Press,Jury,VIP Pass,Crew");

color = createObject("java", "java.awt.Color");
BLUE = color.init( javacast("int", 0), javacast("int", 173), javacast("int", 205));

// cfSearching: array colors are GRAY, GREEN, RED, BLUE, ORANGE
passColor = arrayNew(1);
arrayAppend(passColor, color.init( javacast("int", 192), javacast("int", 192), javacast("int", 192)) );
arrayAppend(passColor, color.init( javacast("int", 192), javacast("int", 222), javacast("int", 30)) );
arrayAppend(passColor, color.init( javacast("int", 255), javacast("int", 0), javacast("int", 80)) );
arrayAppend(passColor, BLUE );
arrayAppend(passColor, color.init( javacast("int", 241), javacast("int", 165), javacast("int", 1)) );

try {

// cfSearching: Create an instance of the javaLoader
pathsForJavaLoader = arrayNew(1);
arrayAppend(pathsForJavaLoader, fullPathToITextJar);
javaLoader = createObject("component", dotNotationPathToJavaLoader).init(pathsForJavaLoader);

// cfSearching: create a reader and stamper for manipulating the template form
pdfReader = javaLoader.create("com.lowagie.text.pdf.PdfReader").init( fullPathToTemplateForm );
outStream = createObject("java", "java.io.FileOutputStream").init( fullPathToOutputFile );
pdfStamper = javaLoader.create("com.lowagie.text.pdf.PdfStamper").init(pdfReader, outStream);

// cfSearching: FORM is a reserved CF word so we will use "formFields" instead
formFields = pdfStamper.getAcroFields();
formFields.setField("name", javacast("string", FORM.name) );
formFields.setFieldProperty("type", "textcolor", passColor[FORM.color], javacast("null", "") );
formFields.setField("type", javacast("string", passType[FORM.type]) );
formFields.setField("number", "N° "& FORM.number );
formFields.setFieldProperty("filmfestival", "bgcolor", BLUE, javacast("null", "") );
formFields.regenerateField("filmfestival");

PushbuttonField = javaLoader.create("com.lowagie.text.pdf.PushbuttonField");

if ( FileExists(fullPathToPhotoFile) ) {
PhotoImage = javaLoader.create("com.lowagie.text.Image").getInstance( fullPathToPhotoFile );
bt = formFields.getNewPushbuttonFromField("photo");
bt.setLayout( PushbuttonField.LAYOUT_ICON_ONLY );
bt.setProportionalIcon(true);
bt.setImage( PhotoImage );
formFields.replacePushbuttonField("photo", bt.getField());
}

try {
code = javaLoader.create("com.lowagie.text.pdf.BarcodeInter25").init();
code.setGenerateChecksum(true);
code.setBarHeight( mmToPoints(3) );
// cfSearching: pad the number with leading zeroes
barCodeNumber = trim(FORM.number);
offset = 13 - len(barCodeNumber);
if ( offset LT 13) {
barCodeNumber = right(repeatString("0", offset) & barCodeNumber, 13);
}
code.setCode( javacast("string", barCodeNumber) );
code.setFont( javacast("null", "") );
cb = javaLoader.create("com.lowagie.text.pdf.PdfContentByte").init(pdfStamper.getWriter());
template = code.createTemplateWithBarcode(cb, javacast("null", ""), javacast("null", ""));
bt = formFields.getNewPushbuttonFromField("barcode");
bt.setLayout(PushbuttonField.LAYOUT_ICON_ONLY);
bt.setProportionalIcon(false);
bt.setTemplate(template);
formFields.replacePushbuttonField("barcode", bt.getField());
} catch (java.lang.Exception e) {
// not a valid code, do nothing
}

pdfStamper.setFormFlattening( javacast("boolean", FORM.flatten) );
pdfStamper.close();
WriteOutput("Finished!");
}
catch (com.lowagie.text.DocumentException de) {
savedErrorMessage = de;
}
catch (java.io.IOException ioe) {
savedErrorMessage = ioe;
}

outStream.close();
</cfscript>

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

0 comments:

  © Blogger templates The Professional Template by Ourblogtemplates.com 2008

Header image adapted from atomicjeep