Hi all,
Since a few people expressed interest, I thought I'd write up a quick tutorial and 
example.   Please send me any feedback you may have.  Hope people find it useful.
------------------
Populating PDF Forms using ColdFusion and the Adobe FDF file format.
The objective is to deliver an PDF form on the fly with values pre-filled on the 
server side with dynamic data.  I'll assume that to get the dynamic data, you'd 
execute a query, say qryGetData as an example.  The data can really be from any 
source.  Example CFML and FDF code is included below, while the sample PDF file can be 
downloaded from <http://www.worlddesign.com/testing/myForm.pdf>.  You can also run the 
example from <http://www.worlddesign.com/testing/returnPDF.cfm>
1) First you will need your PDF form.  Create a regular PDF document, and using the 
full Acrobat (not the reader) "draw" your form fields in it.  Give these form fields 
some meaningful names (I like to give them the same names as my CF variables to keep 
things clear). 
2) For the form default values, put in CF variables!  So for example you have a field 
for First Name-- for it's value, in Acrobat, you could put in #qryGetData.FirstName# 
(the default value for a given field is found in it's Properties/Options dialog).  
Don't forget the # signs. You can actually use ANY CF command/function within the 
field values.
3) From Acrobat, export your form definitions as an FDF file (File/Export/Form 
Data...).  This creates a plain text file containing the field definitions and the 
default field values (ie, all your CF variables).  Save the PDF too.  The PDF will 
need to be accessible via a URL from your site, and the FDF will need to be accessible 
to CF Server (as a CFINCLUDE).  For the example lets call them myForm.fdf and 
myForm.pdf.
4) Open up the FDF file in CF Studio (or your favorite plain text editor).  You'll 
need to make a few minor adjustments here.  The FDF format is very terse and is pretty 
easy to work with.  You don't have to understand it's structure to do any of the 
following.
        a) Scroll down to the end and find the line that has '/F (myForm.pdf)>>' on 
it.  Replace the part inside the parenthesis with a full URL which will point to the 
PDF template on your server.  For example, the line might read like this (w/out the 
quotes):  '/F (http://www.myServer.com/PDF/myForm.pdf)>>'
        b) Wrap  CFOUTPUT tags around the entire contents of the FDF file.
        c) If you used any CF functions within your form field values (such as 
DollarFormat()) you will need to do a search/replace.  Acrobat escapes all '(' and ')' 
by preceding them with a backslash (\).  Replace '\(' with '(' and '\)' with ')' 
globally (this is very quick).
        d) Occasionally Acrobat will put a line break in the middle of your CF 
variable.  You can find these later during debugging, and/or quickly eyeball the FDF 
file and look for line breaks in the middle of a variable.  The line break will also 
be escaped with a '\' preceding the break.  Remove the line break and the \.  You can 
also double-check that there are no stray # signs while you're at it.  If you have a 
large FDF, it's easier to fix this during debug since CF will tell you the exact line 
number of the error.
5) After you save the modified FDF file, you're ready for the CF part.  It's pretty 
simple and there are probably several ways to do it.
Here's what I've done.  You have your action template (or whatever), say 
act_returnPDF.cfm.  First you want to make sure that the action which runs this 
template won't generate any other content besides the PDF file (so no other 
headers/footers/etc).  Avoid white space too.  A leading blank line or any other 
content in the results will screw things up.
6) In your action template,  perform your query that returns the variable names you've 
used in the PDF/FDF templates, or otherwise assign values to the variables.
7) FDF uses the parenthesis characters as delimiters (see step 4c, above).  If any of 
your content may have '(' or ')' in it, you need to escape these using '\' in front of 
them.  See the sample code for an example.
8) Then, you basically just CFINCLUDE the FDF file.  Any CFML and all CF variables are 
interpreted by CF and replaced with data.  Since you want to send the FDF file to the 
browser as an FDF (not text/html), you can use CFCONTENT to return the output.  Here's 
an actual example (also see the sample code below for a more complete example):
<CFHEADER NAME="Content-Disposition" VALUE="inline; filename=myForm.fdf">
<CFCONTENT TYPE="application/vnd.fdf">
<CFINCLUDE TEMPLATE="myForm.fdf">
The CFHEADER line sets the file name that will be sent (so IE knows it's an FDF file), 
while the CFCONTENT makes sure Netscape knows what to do (since it uses the MIME type 
like a good little browser should).  
Note:  To debug, comment out, or otherwise exclude, the CFHEADER and CFCONTENT tags.  
This will allow you to see the raw FDF file being returned, and will show any CF 
errors that might be thrown.  Make sure you get a "clean" FDF file being returned 
before continuing.  A clean FDF file will start with '%FDF' and end with  '%%EOF'.
9) Then it gets a touch complicated to follow the flow.  When the browser sees the FDF 
file type, it runs Acrobat (full or Reader) which opens the FDF file and sees the /F 
switch and the URL to the PDF template.  Acrobat then requests the PDF file via that 
URL.  Once Acrobat retrieves the template PDF, it performs the field substitutions, 
replacing the defined form fields in the PDF with the data that is specified in the 
FDF.  The result is a PDF file with the data dynamically populated.
The full range of options for PDF documents applies, such as protecting from editing, 
selecting, printing, etc., etc.
Another cool feature of this is that you can have one FDF file which works for any 
number of PDF templates.  As long as the fields are named the same across the PDFs, 
you can dynamically drive the URL in the /F switch in the FDF file to point to any 
PDF.  For example you have the same basic form that is laid out differently in each 
State.  With just one FDF file you can deliver any State's custom form using different 
PDF templates.
Active-X Method:
BTW, please note that there is a slightly different method for doing this using 
Adobe's ActiveX FDF component.  Stephen Aylor recently posted a good description of 
how to do it that way to CF-Talk [Subject: Re: follow-up question to PDF [sample 
ActiveX], Date: Mon, 13 Nov 2000 20:39:58 -0800].  As Stephen points out in a 
follow-up email, this method might be preferable to the above if your form field 
definitions change often, since you can avoid mucking around in the FDF file 
altogether.  There are probably other methods for accomplishing the same thing, using 
Adobe's FDF tools <http://partners.adobe.com/asn/developer/acrosdk/forms.html>
-------------------------
Code examples:
-------------------------
This is myForm.fdf:  
(Note that it points to a PDF template that's located on my server.  You can 
download/save the PDF to examine it, if you wish, via the URL specified.)
------ start code ------
<CFOUTPUT>%FDF-1.2
%����
1 0 obj
<< 
/FDF << /Fields [ << /V (#variables.Body#)/T (Body)>> << /V (#variables.To#)/T (To)>> 
] 
/F (http://www.worlddesign.com/testing/myForm.pdf)>> 
>> 
endobj
trailer
<<
/Root 1 0 R 
>>
%%EOF
</CFOUTPUT>
----- end code -----
This is returnPDF.cfm:
----- start code ------
<CFSETTING ENABLECFOUTPUTONLY="YES">
<!--- returnPDF.cfm, example/test code.
        Returns an Adobe FDF file to the browser.  The FDF file contains form value 
data and a pointer to a template PDF file.  The FDF file being used is called 
myForm.fdf.  The end result is that the PDF template is displayed to the user using 
the form data dynamically populated in the FDF file.
        See <http://partners.adobe.com/asn/developer/acrosdk/forms.html> for more 
information of Adobe's FDF format.
 --->
<!--- Set a debug flag. A value of 1 will help debug the FDF file if necessary. --->
<CFPARAM NAME="URL.Debug" DEFAULT="0">
 
<!--- Set values for the variables used in myForm.fdf.  
        This could also be a query or whatever. --->
<CFSET variables.To = "[EMAIL PROTECTED]">
<CFSET variables.Body = "This is some text (for) the body of the message.">
<!--- Need to escape any parenthesis using the backslash 
        (the parenthesis are used as control characters in FDF).
        This step is only necessary if your values might contain '(' or ')' 
characters. --->
<CFSET variables.Body = ReplaceList( variables.Body, "(,)", "\(,\)" )>
<!--- If debug is not on, specify the file name and content type for the browser --->
<CFIF NOT URL.Debug> 
        <CFHEADER NAME="Content-Disposition" VALUE="inline; filename=myForm.fdf">
        <CFCONTENT TYPE="application/vnd.fdf">
</CFIF>
<!--- Avoid any white space before the actual content is sent. 
        A leading blank line will cause an Acrobat error. --->
<CFSETTING ENABLECFOUTPUTONLY="NO"><CFINCLUDE TEMPLATE="myForm.fdf">
------ end code --------
Kind regards,
-Max Paperno
11/14/00, all reproduction rights reserved.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Structure your ColdFusion code with Fusebox. Get the official book at 
http://www.fusionauthority.com/bkinfo.cfm

Archives: http://www.mail-archive.com/[email protected]/
Unsubscribe: http://www.houseoffusion.com/index.cfm?sidebar=lists

Reply via email to