PDF Generation with iText

13 Comments

Review: We had to estimate a PDF generation task during our last sprint planning meeting. We received a rough layout template from our costumer and the service classes to provide the required data were also already present. Nevertheless, we estimated the associated tickets amazingly high. No developer in the team had experience with iText before. However, everyone had heard scary stories from other developers about iText. A qoute floated in our ears: “If you work with iText, sooner or later you have to read the specification of the pdf format.”

After some online research and several interviews with other project teams of codecentric I would like to describe a very simple, robust and primarily fast way to generate PDFs with iText. With this approach, the ticket mentioned above was solved in a quarter of the estimated time and the fear of iText in the team disappeared.

iText offers a lot of possibilities to create PDFs completly using its API, containing all lines, pictures, fixed texts and much more. But this approach may get very complex and generates a lot of error-prone code. It’s much easier to create a template with defined content-fields. This Template will be saved as a PDF with a formular and can be watched for example in the Adobe Reader at any time. Another advantage is the possibility to show your customer the empty pdf and discuss the layout before implementing the logic which fills in the data.

Part 1 – Creation of PDF-formulars

PDF-formulars can be created very easy with OpenOffice. I used OpenOffice Draw in my example, but the approach also works with OpenOffice Writer or Calc. Just create a new document and fill it with texts, colours or lines as desired. After the layout has been finished, you have to define the formular fields. Therefore it’s helpful to activate the toolbars for Formular Design und Formular Control Elements via View -> Toolbars (Sorry – I don’t know the exact english translations, because I use the german version of Open Office). You can activate the Formular Design Mode using one of the new icons. After that, you can choose for example a textfield from the Formular Control Elements and insert it into your document. The properties of the textfield can be changed with a right-click. The following properties are interesting:

  • Name : This name will be used in the Java code to reference the control element and fill it with data.
  • Border : Default is 3D-Look – In most cases the setting without Border should work better.
  • Background-Colour, Alignment, Font: You can define the layout with these properties. Layout data in Java code is not necessary!
  • Text-type: Default should be one-line, but if you need to fill in the field with line-breaks from Java code, you have to use multi-line.

It’s very hard to spot the formular fields as soon as they have no border. The Formular-Navigator helps to solve this problem.

After creating layout and formular fields the document can be exported to a PDF. This can be done by File –> Export as PDF. Be sure to activate the checkbox Create PDF-Formular in the following dialog.

OpenOffice

Editing a formular in OpenOffice


OpenOffice - PDF Template


Generated PDF Template


Part 2 – Fill the PDF-Formular with iText

In my example I use iText in version 2.1.7, because in later versions iText has a more strict license.

First read the created PDF template…

PdfReader pdfTemplate = new PdfReader(pdfTemplateFile);

… and create a PdfStamper with a OutputStream.

ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(pdfTemplate, out);

We have to tell the PdfStamper to flatten the form, because there should be no formular fields in the created PDF.

stamper.setFormFlattening(true);

To finish the work we can just fill the fields…

stamper.getAcroFields().setField("name", "Daniel Reuter");
stamper.getAcroFields().setField("adress", "Merscheider Str.1 – 42699 Solingen");
stamper.getAcroFields().setField("dates", "2008\n2009\n2010\n");
stamper.getAcroFields().setField("titles", "JAX\nDevoxx\nJavaOne\n");

…and close all the opened resources.

stamper.close();
pdfTemplate.close();

Conclusion

From my point of view, this is a very simple and easily understandable approach to create PDFs using iText. Certainly there will be scenarios in which the described way won’t work, for example if you have to implement dynamic layouts. However, I would always try to use a PDF template as a basis.



PDF Result

Author

Daniel Reuter

Daniel Reuter

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

  • August 31, 2010 von Appasaheb

    Hi, pretty good example. I like the idea of using the templates to fill values dynamically.

    I want to use template for similar purpose as you have shown in the example. But I also want to show a table in resulting pdf which would show all the rows from a db table. But if the db table does have any data then we dont want to show the table at all in resulting pdf(no header row too).

    Is this possible to achive dynamic growing table with open office pdf templates and itext ?

  • Andreas Ebbert-Karroum

    Hi,

    you can do just about anything to PDFs with iText, which includes modifying PDFs, extending tables, etc.

    The feature, which is discussed in this blog is filling out PDF templates, which means you are bound to the fields that are already present in the PDF template. Hence, you cannot extend a table.

    Andreas

  • September 1, 2010 von Mario Cespedes

    good example! this is the way we prefer to serve PDF at work… for more complex layouts we use iReport & JasperReport…

    both tool produce PDF file very fast!

  • Hi there,

    you seem to follow a similar approach than inforama ( http://www.inforama.org ) – they have a full tool suite using open office to create PDF forms, form letters, etc and then use a transformation to go to the PDF file (I think open office file to fop, then data injection and rendering with iText to PDF).

  • September 3, 2010 von obruening

    you can also start openoffice in headless mode as a server and produce pdf documents with the UNO interface. take a look at http://github.com/obruening/oo_rails

  • November 1, 2010 von Erik Björk

    Very nice article!

    Which license is used with version 2.1.7? I can’t find any information from either their homepage or from Sourceforge. All I see is that newer versions use AGPL.

  • 2.1.7 uses Mozilla Public License / LGPL which is allowing usage of Java libraries in commercial products via dynamic linking.

  • February 22, 2011 von Manuel Vio

    A big BIG Thank you for this article!

  • June 25, 2011 von Laurent Grigorescu

    Excellent post Daniel!

    It saved me a great deal in time and the results are very good looking.

    Thank you!

  • June 29, 2011 von Allen Smith

    Silly question… I am trying to get this to work, and while I get no error I get no pdf either.
    ANy ideas?

    Thanks in advance

    • Daniel Reuter

      Hi Allen,

      the code is only filling the ByteArrayOutputStream. The Stream contains the pdf. You can convert this to an byte array (out.toByteArray()). After that, you can write the byte array to a file (example).

  • Nice article. It really helped me a lot

    Thank you

  • You may want to use a template designer allowing to define areas (bounds + distinctive name + properties), on any existing PDF, where you want to write dynamic/user data (e.g. from Web form) using FPDF.

    Free/open source Dhek can be used to do so. Template is saved in a separate JSON file, easily parsable in PHP: integration example with PHP/FPDF: https://github.com/applicius/dhek#integration .

Comment

Your email address will not be published. Required fields are marked *