Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

iText: Generate PDFs in Java

  
  
  

iText is a free, open source library that lets you create and deal with PDF files in Java. While you can use it for Java that you compile and run from the command line, the library is really in its element when used within a Java servlet, serving PDFs dynamically to users from a browser. iText is fantastic for situations where you need to produce PDFs in large numbers (so it's not practical to generate them manually), or from dynamic real-time information, as is often required online. iText offers support for a wide range of advanced PDF features, including digital signatures, forms, and encryption.



As iText is a Java library, setup is straightforward: Just download the libraries and either put them in your system's additional libraries directory, or edit your library path (the CLASSPATH variable in your .bashrc or .tcshrc file) to point to them. You may as well download the extra JAR files available while you're at it, although you won't need them for the basic usage we'll cover here. They include some Asian character maps, and some cryptography JARs.



Here's a simple example of some Java code that uses iText to produce one portrait and one landscape page saved as sample.pdf:



public class PageSample {
public static final String RESULT = "sample.pdf";

public static void main(String[] args)
throws DocumentException, IOException {
new PageSample().createPdf(RESULT);
}

public void createPdf(String filename)
throws DocumentException, IOException {
Document doc = new Document(PageSize.A4);
PdfWriter.getInstance(doc, new FileOutputStream(filename));

doc.open();
doc.add(new Paragraph("This is the first page."));
Paragraph paraRight = new Paragraph();
paraRight.setAlignment(Element.ALIGN_RIGHT);
paraRight.add("This paragraph is right-aligned");
doc.add(paraRight);

doc.setPageSize(PageSize.A4.rotate());
doc.setMargins(72, 72, 180, 180);
doc.newPage();
doc.add(new Paragraph("This is a landscape page with bigger margins"));

doc.close();
}
}


The first couple of lines of createPdf() set up the Document (the basic foundation of each iText-generated PDF) and a PdfWriter to write it out. We then open the document and start adding paragraphs. For a basic paragraph, you can just do this inline, as with the first one. If you want to set paragraph alignment or do anything else complicated, you can declare a Paragraph object, then set its alignment and content (and other properties; see the API documentation for more things you can do to Paragraphs) before adding it to the Document.



The default orientation is portrait. To create a landscape page, set a rotated page size, as shown here. This setting only affects content added after the setPageSize() call, so it's possible to change page sizes, layouts, and structures throughout a document. Here, we've also altered the margins, using setMargins(leftmargin, rightmargin, topmargin, bottommargin), with all values given in points.



Once you're finished, remember to close the document; if you don't, then when your class runs, the output document will be empty.



Manipulating PDF Content Directly



For simple PDFs, using the provided objects to add content is the best option. For more complicated formatting, such as columns, you'll need to manipulate PDF output more directly. Here's one way to set up columns (the LOREM variable is a Phrase created from lorem ipsum text):




public void createPdf(String filename)
throws DocumentException, IOException {
Document doc = new Document();
PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream(filename));

doc.open();
doc.add(new Paragraph("After this paragraph there are some columns."));
Paragraph paraRight = new Paragraph();

PdfContentByte canvas = writer.getDirectContentUnder();
ColumnText ct = new ColumnText(canvas);
ct.setSimpleColumn(LOREM, 72, 750, 270, 500, 10, Element.ALIGN_JUSTIFIED);
ct.go();
ct.setSimpleColumn(LOREM, 342, 750, 540, 500, 10, Element.ALIGN_JUSTIFIED);
ct.go();

doc.close();
}


This time we need to actually get a PdfWriter, rather than use the method statically, then use that PdfWriter to get a PdfContentByte object, with which we can interact directly with the PDF content.



The ColumnText class allows you to do various things with columns. Here we're just using setSimpleColumn:



 
setSimpleColumn(Phrase phrase,
float lower_left_x_corner,
float lower_left_y_corner,
float upper_right_x_corner,
float upper_right_y_corner,
float leading,
int alignment)


To use this method, you need to know how the PDF coordinate system works. The origin (0,0) is in the lower left corner of the page (as it is on a normally oriented graph). The x-axis runs left to right, and the y-axis bottom to top, as you'd expect. Coordinates are measured in points, where 1 inch = 72 points.



The setSimpleColumn() method creates a rectangular box, bounded by the given coordinates, in which it will lay out your text, with the given alignment. To work out where the corners of your box are, you'll probably need to do a bit of sketching and then a bit of math. Try changing the coordinates and recompiling a few times to get a handle on how it works.



After each call to setSimpleColumn(), you'll need to call go() on the ColumnText object. Every time you call setSimpleColumn() again, any leftover text from the previous column will spill over into the new one before your new text starts. (If you don't provide a new phrase at all, it'll just use the text from the previous column, then stop when it runs out.) That's normally what you want, but if not, you can create a new ColumnText object first.



Again, remember to close your document once you're done!



Using iText with Servlets



Probably the most useful aspect of iText is that it can be used in a Java servlet context to generate and serve PDFs online:



public class ITextServlet extends HttpServlet {

protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/pdf");
OutputStream out=response.getOutputStream();
try {
Document doc = new Document();
PdfWriter.getInstance(doc, out);
doc.open();
doc.add(new Paragraph("Hi Mum I'm on the Internet!"));
Paragraph paraJustified = new Paragraph();
paraJustified.setAlignment(Element.ALIGN_JUSTIFIED);
paraJustified.setSpacingBefore(50);
paraJustified.add("This paragraph is justified.");
paraJustified.add(LOREM);
doc.add(paraJustified);
doc.close();
} catch (DocumentException exc){
throw new IOException(exc.getMessage());
} finally {
out.close();
}
}

@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}


You need to get the OutputStream from the passed-in HttpServletResponse parameter before you can set up the output Document, and before you can use PdfWriter to link the Document to the OutputStream. The rest of this code is the same kind of syntax as in the examples above (note the newly added paragraph spacing line, as another example of things you can do with Paragraphs). Finally, as well as closing the Document, you need to close the OutputStream.



This example is static, but you could add whatever phrases and other parts of the document you want, and these could easily be generated on-the-fly from other information.



(Note: If you're using Tomcat, you may need to restart the server to flush the cache when you edit and recompile the code; or look at the caching settings.)


19a98812-f823-48dc-841e-bf029c63c6d7

Forms



iText also allows you to create forms. Here's a basic example that shows a set of radio buttons:



public static final String[] ANIMALS = { "dog", "cat", "rat", "snake", "hamster" }; protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// most of method is as in the above example
try {
writer = PdfWriter.getInstance(outputDoc, out);
generateForm();
} // rest of method as above
}

public void generateForm() throws IOException, DocumentException {
outputDoc.open();
PdfContentByte canvas = writer.getDirectContent();
Rectangle rect;
PdfFormField field;
PdfFormField radiogroup = PdfFormField.createRadioButton(writer, true);
radiogroup.setFieldName("animals");
RadioCheckField radio;
for (int i = 0; i < ANIMALS.length; i++) {
rect = new Rectangle(40, 806 - i * 40, 60, 788 - i * 40);
radio = new RadioCheckField(writer, rect, null, ANIMALS[i]);
radio.setCheckType(RadioCheckField.TYPE_CIRCLE);
field = radio.getRadioField();
radiogroup.addKid(field);
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT,
new Phrase(ANIMALS[i], font), 70, 790 - i * 40, 0);
}
writer.addAnnotation(radiogroup);
outputDoc.close();
}
}


As with the columns example above, this uses a PdfContentByte canvas to directly manipulate the PDF content. The API is set up to make most of this code straightfoward; we create a radio button group, then loop through the ANIMALS array, adding one RadioCheckField to the group for each item in the array.



To create a RadioCheckField, you need to provide the location and size of the field, using a Rectangle (specified as with setSimpleColumn above, using the coordinates of the left lower and right upper corners). You can also set the border and background colors of the radio field if you want (using setBorderColor() and setBackgroundColor; check the API for RadioCheckField for more options). Here we just set the type of buttons to use (circles). getRadioField() returns a PdfFormField, and that, with its ID, is added to the radio group PdfFormField.



Note that while all of that code generates the buttons themselves and associates them with a value, you need to generate the labels separately using ColumnText (and to manually make sure that they're correctly aligned, as here).



Going Further with iText



This article only scratches the surface of what you can do with iText. You can also set up document metadata, tables, images, headers and footers, and forms as complicated as you can think of. For a thorough introduction to iText, turn to the comprehensive and readable book iText in Action, which includes some great examples. Poking through the online API documentation can also give you an idea of what's possible. Finally, if you're a C# person, the iTextSharp project page may be of interest to you.




This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

The Java servlet example for serving PDFs was just what I needed.  
 
Thanks. 
 
Rick
Posted @ Thursday, August 02, 2012 9:20 AM by Rick
da
Posted @ Saturday, May 03, 2014 9:04 PM by ad
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics