Provide online users with a copy of their completed form to save.
Adobe Reader enables a user to add, change, view, and print form data, but it does not enable a user to save the filled-in PDF form to disk. Saving the file produces a lovely copy of an empty form. How annoying!
Correct this problem server-side by merging the PDF form and its data. Then, offer this filled-in form as a download for the user's records. After merging, the form fields remain interactive, even though they display the user's data. Go a step further and flatten this form so that field data becomes a permanent part of the PDF pages. After flattening, filled-in fields are no longer interactive. You can merge and flatten forms using the iText library or our command-line pdftk. Both are free software.
The iText library (http://www.lowagie.com/iText/ or http://itextpdf.sf.net) is a remarkable tool for manipulating PDF documents. The following Java program, merge_pdf_fdf, demonstrates how to merge or flatten a PDF and its form data FDF [Hack #77] using iText. Run this code from your command line, or integrate it into your web application.
/* merge_pdf_fdf, version 1.0 merge an input PDF file with an input FDF file to create a filled-in PDF; optionally flatten the FDF data so that it becomes part of the page http://www.pdfhacks.com/merge_pdf_fdf/ invoke from the command line like this: java -classpath ./itext-paulo.jar:. \ merge_pdf_fdf input.pdf input.fdf output.pdf or: java -classpath ./itext-paulo.jar:. \ merge_pdf_fdf input.pdf input.fdf output.pdf flatten adjust the classpath to the location of your iText jar */ import java.io.*; import com.lowagie.text.pdf.*; public class merge_pdf_fdf extends java.lang.Object { public static void main(String args[]) { if ( args.length == 3 || args.length == 4 ) { try { // the input PDF PdfReader reader = new PdfReader( args[0] ); reader.consolidateNamedDestinations( ); reader.removeUnusedObjects( ); // the input FDF FdfReader fdf_reader= new FdfReader( args[1] ); // PdfStamper acts like a PdfWriter PdfStamper pdf_stamper= new PdfStamper( reader, new FileOutputStream( args[2] ) ); if( args.length == 4 ) { // "flatten" // filled-in data becomes a permanent part of the page pdf_stamper.setFormFlattening( true ); } else { // filled-in data will 'stick' to the form fields, // but it will remain interactive pdf_stamper.setFormFlattening( false ); } // sets the form fields from the input FDF AcroFields fields= pdf_stamper.getAcroFields( ); fields.setFields( fdf_reader ); // closing the stamper closes the underlying // PdfWriter; the PDF document is written pdf_stamper.close( ); } catch( Exception ee ) { ee.printStackTrace( ); } } else { // input error System.err.println("arguments: file1.pdf file2.fdf destfile [flatten]"); } } }
To create a command-line Java program, copy the preceding code into a file named merge_pdf_fdf.java. Then, compile merge_pdf_fdf.java using javac, setting the classpath to the name and location of your iText jar:
javac -classpath ./itext-paulo.jar merge_pdf_fdf.java
Finally, invoke merge_pdf_fdf like so:
java -classpath ./itext-paulo.jar :. \ merge_pdf_fdf input.pdf input.fdf output.pdf
Use pdftk [Hack #79] to merge a form with an FDF datafile [Hack #77] and create a new PDF. The fields will display the given data, but they also remain interactive. pdftk's fill_form operation takes the filename of an FDF file as its argument. For example:
pdftk form.pdf fill_form data.fdf output filled_form.pdf
You can't combine the fill_form operation with any other operation (e.g., cat), but you can supply additional output options for encryption [Hack #52] .
Flatten form data permanently into the page by adding the flatten_form output option. The resulting PDF data will no longer be interactive.
pdftk form.pdf fill_form data.fdf output filled_form.pdf flatten_form
Or, if your PDF form already has field data, just flatten it:
pdftk filled_form.pdf output flattened_form.pdf flatten_form
After installing pdftk on your web server, you can invoke it from your PHP scripts to merge PDF forms with FDF data. Use our PHP script forge_fdf [Hack #77] to cast your data into FDF. Then, save this FDF data into a temporary file. Finally, call pdftk to create a new PDF from your PDF form and FDF data.
The following PHP code could be used for this purpose:
<?php // session_fdf is your function for converting // the user's session state into an FDF string $fdf_ss= session_fdf( $_GET['id'] ); $temp_fn= tempnam( '/tmp', 'tempfdf' ); $temp_fp= fopen( $temp_fn, 'wb' ); if( $temp_fp ) { fwrite( $temp_fp, $fdf_ss ); fclose( $temp_fp ); header( 'Content-type: application/pdf' ); passthru( '/usr/local/bin/pdftk form.pdf fill_form '.$temp_fn. ' output - flatten' ); // output to stdout (-) unlink( $temp_fn ); } ?>