You are on page 1of 55

Creating PDFs with Java

What we will cover


• Using the API to create PDFs from scratch.
• Writing to Acrobat forms.
• Building a sample application.
• Deploying PDFs in a Web application.
What is iText?
• Java library for creating and manipulating
PDFs
• Open source
• Free
iText Features
• Create PDFs
• Populate PDF forms
• Tables
• JPEG, GIF and PNG images
• PDF encryption
• Headers, footers
• Barcodes
Key Classes
• Document - The document to write to.
• PdfWriter - A writer for the document.
Creates a PDF representation of every
element in the document.
Example 1 (Hello World)
import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfWriter;
public class HelloWorld{
public static void main(String[] args) {

// step 1: creation of a document-object


Document document = new Document();
try {
// step 2: we create a writer that listens to the document and directs
// a PDF-stream to a file
PdfWriter.getInstance(document,
new FileOutputStream("c:\\itext\\Hello.pdf"));

// step 3: we open the document


document.open();

// step 4: we add a paragraph to the document


document.add(new Paragraph("Hello World"));
}
catch(Exception ex) {System.err.println(ex.getMessage());}

// step 5: we close the document


document.close();
}
}
Output
Example 2 (Image )
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

public class ImageTest {


public static void main(String[] args) {
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
try {
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("c:\\itext\\imageTest.pdf"));
document.open();
Image img = Image.getInstance("c:\\itext\\linux.gif");
document.add(img);
img.scalePercent(20);
img.setRotationDegrees(190);
img.setAlignment(Image.RIGHT);
document.add(img);
img.scalePercent(25);
img.setRotationDegrees(0);
img.setAbsolutePosition(171, 250);
document.add(img);
document.close();
}catch (Exception de) {de.printStackTrace();}
}
}
Example 3 (Table)
import java.io.*;
import java.awt.Point;

import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfWriter;

public class Chap0503 {

public static void main(String[] args) {

// step 1: creation of a document-object


Document document = new Document();
try {
// step 2:
// we create a writer that listens to the document
// and directs a PDF-stream to a file
PdfWriter.getInstance(document, new FileOutputStream("Chap0503.pdf"));

// step 3: we open the document


document.open();
Example 3 (cont)
// step 4: we create a table and add it to the document
Table aTable = new Table(4,4); // 4 rows, 4 columns
aTable.setAutoFillEmptyCells(true);
aTable.addCell("2.2", new Point(2,2));
aTable.addCell("3.3", new Point(3,3));
aTable.addCell("2.1", new Point(2,1));
aTable.addCell("1.3", new Point(1,3));
aTable.addCell("5.2", new Point(5,2));
aTable.addCell("6.1", new Point(6,1));
aTable.addCell("5.0", new Point(5,0));
document.add(aTable);
}
catch(Exception ex) { System.err.println(de.getMessage());}
// step 5: we close the document
document.close();
}
}
Acrobat Forms
• Why use Acrobat forms?
• Forms are editable
• Forms can be written to or read from using
iText API
Typical Form
Acrobat Forms
• Why use Acrobat forms?
• Forms are editable
• Forms can be written to or read from using
iText API
Editable Form
Acrobat Forms
• Why use Acrobat forms?
• Forms are editable
• Form fields can be written to or read using
iText API
Underlying Form Fields
Talking to a PDF
Key Classes
• PDFReader - Reads a PDF from a file, byte
array, or URL.
• PdfStamper - Lets you add things to an
existing PDF.
• AcroFields - Contains information on the
form fields. Can also remove or rename
fields and set field values.
How to get the Fieldnames
SomeForm.pdf

PDFReader

PDFStamper

AcroForms

set/get fields
Example 5
(Set, Get, Rename Fields)
import java.io.*;
import java.util.*;
import com.lowagie.text.pdf.*;

public class SetupExample {

public void processFields(){


try{
//Reads a PDF document named "f1040.pdf".
PdfReader reader = new PdfReader("f1040.pdf");
PdfStamper stamp = new PdfStamper(reader,
new FileOutputStream("Altered1040.pdf"));
//rename the fields
AcroFields form = stamp.getAcroFields();
form.renameField("f1-4", "firstName");
form.renameField("f1-5", "lastName");
form.renameField("f1-11", "ssn1");
form.renameField("f1-12", "ssn2");
form.renameField("f1-13", "ssn3");
form.setField("f1-6", ”spouse first name");
String spouseLastName = form.getField("f1-7");
//Writes the result to a file named "Altered1040.pdf"
stamp.close();
Creating a Wrapper Class
• Why a wrapper class?
• We need to know the document name and
the key value pairs.
• I wrote the following utility to generate a
wrapper class for a PDF form.
Code Generation Tool
import java.io.*;
import java.util.*;
import com.lowagie.text.pdf.*;

public class PdfFormGenerator {

private String className;


private String formName;
private StringBuffer generatedClass = new StringBuffer();

public PdfFormGenerator(String formName, String className){


this.formName = formName;
this.className = className;
try{
//get the field names
PdfReader reader = new PdfReader(formName);
PdfStamper stamp = new PdfStamper(reader,
new ByteArrayOutputStream());
AcroFields form = stamp.getAcroFields();
HashMap formFields = form.getFields();
Code Generation Tool (cont)
// generate a class
Set formFieldNames = new TreeSet(formFields.keySet());
Iterator nameIterator = formFieldNames.iterator();
generatedClass.append(clsStart()); // Top of class code
generatedClass.append(construct());
StringBuffer methods = new StringBuffer();
String initMembers = new String();
// loop through all fieldnames in the pdf template
while(nameIterator.hasNext()){
String pdfFieldName = (String) nameIterator.next();
String javaName = pdfFieldName;
//convert irs fieldnames into something java can use in a method name
if(javaName.indexOf('-')>0){
javaName = javaName.replaceAll("-", "Field");
}
methods.append(setMethod(javaName, pdfFieldName));
initMembers += initMember(javaName);
}
methods.append("\n public HashMap getData() {\n return data;\n }\n");
methods.append("\n public String getPdfTemplateName() {\n return
pdfTemplateName;\n }\n");
methods.append("\n public void setPdfTemplateName(String pdfTemplateName) {\n
Code Generation Tool (cont)
generatedClass.append(methods);
generatedClass.append("}");
}catch(Exception ex){ex.printStackTrace(); }

clsStart();
}
private String clsStart() {
String s ="\n\nimport java.util.*;";
s+="\n\npublic class " + className + " implements PdfForm{";
s+="\n\n private HashMap data = new HashMap();";
s+="\n private String pdfTemplateName = \""+formName+"\";\n";
return s;
}

private String construct() {


String s = "\n public " + className + "() {\n }";
return s;
}

public String initMember(String fieldName) {


String s = "\n " + fieldName + " = new String();";
return s;
}
Code Generation Tool (cont)
public String getMethod(String javaName, String value) {
String s = new String();
s = headerComment("Returns the value of "+value);
s += "\n public String get"+ cap(javaName)+"() {";
s += "\n return (String)data.get(\""+value + "\");\n }";
return s;
}
private String cap(String s) {
return s.substring(0,1).toUpperCase() + s.substring(1);
}
private String headerComment(String text) {
return " \n /**\n *"+text+"\n */";
}
public String setMethod(String javaName, String value) {
String z = new String();
z = headerComment("Sets the value of "+value);
z += "\n public void set"+ cap(javaName) +"(String value) {";
z += "\n data.put(\""+value+"\", value);\n }\n";
return z;
}
Code Generation Tool (cont)
public void writeToFiles() throws Exception {
FileWriter fw = new FileWriter(className + ".java");
fw.write(generatedClass.toString());
fw.close();
return;
}

public static void main(String[] args){


try{
PdfFormGenerator gen = new PdfFormGenerator(args[0], args[1]);
gen.writeToFiles();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
The Wrapper Classes Implement

Public interface PdfForm {


public HashMap getData();
public String getPdfTemplateName();
}
Sample Generated Class
Import java.util.*;
public class Irs1040 implements PdfForm{
private HashMap data = new HashMap();
private String pdfTemplateName = "Altered1040.pdf";

public Irs1040() {}
public void setFirstName(String value) {
data.put("firstName", value);
}
public void setLastName(String value) {
data.put("lastName", value);
}
A First Full Example
• Write the data to the wrapper classes
• Use the original PDF forms as templates
• Use PdfStamper to get the PDF fields
• Set the field values in the form.
• Set form flattening to make the data fields
no longer editable.
Populating the PDF
Wrapper SomeForm.pdf

PDFReader

PDFStamper

AcroForms

Key/Value set fields


Example 6 (Writing to a Form)
import java.io.*;
import java.util.*;

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

public class FormWriter {

public FormWriter(PdfForm pdfForm, String outputPDF){

try{
String templateName = pdfForm.getPdfTemplateName();
PdfReader reader = new PdfReader(templateName);
PdfStamper stamp = new PdfStamper(reader,
new FileOutputStream(outputPDF));
AcroFields acroFields = stamp.getAcroFields();

//This is our data


Map valueMap = pdfForm.getData();
//get a list of fields in the pdf
HashMap formFields = acroFields.getFields();
Set formFieldNames = formFields.keySet();
Iterator nameIterator = formFieldNames.iterator();
Example 6 (cont.)
//loops through all field names in the pdf template
while(nameIterator.hasNext()){
// pdf template field name
String fieldName = (String) nameIterator.next();
// value for field, if any
Object value = valueMap.get(fieldName);

// set our value in the form


if(value != null){
String fieldStringValue = (String) value;
acroFields.setField(fieldName, fieldStringValue);
}
}
//gets rid of editable fields, makes them part of the document
stamp.setFormFlattening(true);

//Closes the document. No more content can be written


stamp.close();
} catch (Exception ex) {ex.printStackTrace();}
}
Example 6 (cont.)
public static void main(String[] args) {
Irs1040SchedDCont irs1040SD = new Irs1040SchedDCont();
irs1040SD.setName("Test");
irs1040SD.setSsn1("999");
irs1040SD.setSsn2("11");
irs1040SD.setSsn3("1234");

new FormWriter(irs1040SD, "C:\\itext\\1040Out.pdf");


}
}
Output
Merging PDFs
• iText can merge many PDFs into a single
document.
• Conversely, individual pages can be
selected from a document to create new
PDFs
• Key API classes are:
– PDFCopy - Makes copies of PDF Documents
– PdfImportedPage - Selects a page out of a PDF
Merging PDFs
Import java.io.*;
import java.util.*;
import java.net.*;

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

public class PdfProcessor {

public PdfProcessor(Vector pdfForms, OutputStream outStream){

try{
// this is a blank document we will be adding pages to
Document mergedPDF = new Document();
// makes copies of PDF documents.
PdfCopy writer = new PdfCopy(mergedPDF, outStream);
// open the document so we can add content
mergedPDF.open();

Iterator iterator = pdfForms.iterator();


Merging PDFs
// do this for each form
while(iterator.hasNext()){
Object object = iterator.next();
PdfForm pdfForm = (PdfForm)object;
// get the name of the pdf template
String templateName = pdfForm.getPdfTemplateName();
// get our data
Map valueMap = pdfForm.getData();

PdfReader singlePDF = new PdfReader(templateName);


ByteArrayOutputStream pdfStream = new ByteArrayOutputStream();
PdfStamper stamp = new PdfStamper(singlePDF, pdfStream);

// Acrofields can query and change fields in existing documents


AcroFields form = stamp.getAcroFields();
// get a list of fields in the pdf
HashMap formFields = form.getFields();
Set formFieldNames = formFields.keySet();
Iterator nameIterator = formFieldNames.iterator();
Merging PDFs
// loops through all field names in the PDF template
while(nameIterator.hasNext()){
//pdf template field name
String fieldName = (String) nameIterator.next();
//value for field, if any
Object value = valueMap.get(fieldName);

if(value != null){
String fieldStringValue = (String) value;
form.setField(fieldName, fieldStringValue);
}
}
//gets rid of editable fields, makes them part of the document
stamp.setFormFlattening(true);

//Closes the document.


stamp.close();

PdfReader completedPDF = new PdfReader(pdfStream.toByteArray());


int numPages = completedPDF.getNumberOfPages();
Merging PDFs
// copy each page of the document
for (int i = 0; i < numPages; ++i){
// Gets the specified page from the input document
PdfImportedPage page = writer.getImportedPage(completedPDF, i+1);
// Add an imported page to our output
writer.addPage(page);
}
PRAcroForm completedform = completedPDF.getAcroForm();
if (completedform != null){
// Copy the acroform for an input document.
writer.copyAcroForm(completedPDF);
}
}
// close document (and output stream).
mergedPDF.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Build a Sample Application
• Simulate a tax application that uses multiple
pdf’s, writes data, and produces a single
non-editable pdf using the code we have
shown.
Example 7 (Tax application)
import java.util.*;
import java.io.*;
public class TaxTool {
private String firstName = new String();
private String lastName = new String();
private String ssn1 = new String();
private String ssn2 = new String();
private String ssn3 = new String();
Vector forms = new Vector();

public Vector getFormData(){


Irs1040 irs1040 = new Irs1040();
irs1040.setFirstName(firstName);
irs1040.setLastName(lastName);
irs1040.setSsn1(ssn1);
irs1040.setSsn2(ssn2);
irs1040.setSsn3(ssn3);
forms.add(irs1040);
Example 7 (cont)
Irs1040SchedD irs1040SD = new Irs1040SchedD();
irs1040SD.setName(firstName+" "+lastName);
irs1040SD.setSsn1(ssn1);
irs1040SD.setSsn2(ssn2);
irs1040SD.setSsn3(ssn3);
forms.add(irs1040SD);

Irs1040SchedDCont irs1040SD1 = new Irs1040SchedDCont();


irs1040SD1.setName(firstName+" "+lastName);
irs1040SD1.setSsn1(ssn1);
irs1040SD1.setSsn2(ssn2);
irs1040SD1.setSsn3(ssn3);
irs1040SD1.setNamePage2(firstName+" "+lastName);
irs1040SD1.setSsn1Page2(ssn1);
irs1040SD1.setSsn2Page2(ssn2);
irs1040SD1.setSsn3Page2(ssn3);
forms.add(irs1040SD1);
Example 7 (cont)
Irs1040SchedE irs1040SE = new Irs1040SchedE();
irs1040SE.setName(firstName+" "+lastName);
irs1040SE.setSsn1(ssn1);
irs1040SE.setSsn2(ssn2);
irs1040SE.setSsn3(ssn3);
irs1040SE.setNamePage2(firstName+" "+lastName);
irs1040SE.setSsn1Page2(ssn1);
irs1040SE.setSsn2Page2(ssn2);
irs1040SE.setSsn3Page2(ssn3);
forms.add(irs1040SE);
Irs1040SchedEIC irs1040SEI = new Irs1040SchedEIC();
irs1040SEI.setName(firstName+" "+lastName);
irs1040SEI.setSsn1(ssn1);
irs1040SEI.setSsn2(ssn2);
irs1040SEI.setSsn3(ssn3);
forms.add(irs1040SEI);
return forms;
}
Example 7 (cont)
public static void main(String[] args){
TaxTool taxTool = new TaxTool();
taxTool.setFirstName("Mark");
taxTool.setLastName("Stark");
taxTool.setSsn1("123");
taxTool.setSsn2("45");
taxTool.setSsn3("6789");
Vector forms = taxTool.getFormData();

try{
PdfProcessor processor = new PdfProcessor(forms,
new FileOutputStream("C:\\itext\\myResults", false));
}catch(FileNotFoundException ex){
ex.printStackTrace();
}

}
Output Demo
PDFs in a Web Application
• Create the document using the iText API
and a ByteArrayOutputStream
• Set HTTP response headers
• Get ServletOutputStream object
• Write document bytes to the
ServletOutputStream
• Flush the ServletOutputStream
Example 8 (Servlet Code)
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class ItextExampleServlet extends HttpServlet {

protected void processRequest(HttpServletRequest request,


HttpServletResponse response) throws ServletException, IOException {
//get data from the request page
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
String ssn1 = request.getParameter("ssn1");
String ssn2 = request.getParameter("ssn2");
String ssn3 = request.getParameter("ssn3");
Example 8 (cont)
//populate forms with the data
TaxTool taxTool = new TaxTool();
taxTool.setFirstName(firstName);
taxTool.setLastName(lastName);
taxTool.setSsn1(ssn1);
taxTool.setSsn2(ssn2);
taxTool.setSsn3(ssn3);
Vector forms = taxTool.getFormData();

ByteArrayOutputStream baos = new ByteArrayOutputStream();

//merge the forms into one document


PdfProcessor processor = new PdfProcessor(forms, baos);
Example 8 (cont)
//let the browser know it is a pdf
response.setContentType("application/pdf");
//Set the content-length header to the number of bytes in the PDF file.
response.setContentLength(baos.size());
//let the browser know how to display it and what to name the file
response.setHeader("Content-disposition",
" inline; filename=yourTaxes.pdf");

ServletOutputStream sos = response.getOutputStream();


baos.writeTo(sos);
//send all bytes to the client.
sos.flush();
}
Demonstration
Further Information
• iText lead developers: Bruno Lowagie,
Paulo Soares
• Website: http://www.lowagie.com/iText
• Beta: http://itextpdf.sourceforge.net/
Questions?

You might also like