Tuesday, October 07, 2008

A simple java library for creating pdfs

Here is a free, lightweight, simple to use library that sits on top of the iText library and which helps you quickly create PDF documents with java code.

I've created this library for my own applications and was toying with what to do with the library. After listening to Taking Notes Episode 86 I have decided to give it away and make it open source. After all, I'd found this useful so someone else might. So here I am, a guy sitting at a desk writing code, throwing it at a wall.

What is iText ?

If you've not heard of iText, it's a comprehensive open source Java library that you can use to create and manipulate PDF documents. You can use it to do pretty much anything from creating a regular document, to reports to creating maps and bar charts.

Why did you create another layer on iText ?

In the course of using the library I found that there were some simple and common things that I always wanted to do that were a little more complicated than I'd like. Things like adding page numbers, or calculating margins when you change the page orientation.

So I started adding a layer that would shield me from that complexity for the simple documents that I needed to create.

My library is fairly simplistic, for example, I only support Helvetica, Times Roman and Courier fonts. I only supports A4 and Letter page sizes. I didn't want to rewrite the entire iText library, just provide a little quicker access to the stuff I would need to change on a regular basis.

If you need to create A4 (or Letter) Pdf documents that are either Landscape or Portrait. If you need to have a header with an image and footers with page numbers and If you need to include paragraphs and tables with basic fonts and formatting (such a bold, italics and colors) then this library might help you.

If you have much more complex requirements then you should probably look at using iText directly or using one of the many Pdf libraries that are available.

However, if this almost meets your needs and hits that sweet spot, like it did for me, then it will save a bit of time. If it is almost what you need, then you have access to the source code to make your own variation.

Show me how I can use it

A simple example and the result.

/*

* Create a config object to contain file location and

* some meta data settings

*/

config = new PdfDocumentConfig("Example 3","example3.pdf","examples");

config.setReportSubject("Example 3 - Image banner");

config.setReportAuthor("Scius and iText");

/*

* Creating a header image

*/

headerImage = new HeaderImage();

headerImage.addImage(new String("examples/top.jpg"));

headerImage.setImageScale(HeaderImage.IMAGE_PAGE_SCALE, true);

/*

* Create a layout, size, orientation, margins, header and footer

*/

layout = new LayoutElement(

LayoutElement.PAGESIZE_A4,

LayoutElement.ORIENTATION_PORTRAIT,

20,20,10,10,100,100

);

// add the image to the layout

layout.setHeaderImage(headerImage);

/*

* Create the PDF content, the data written to the PDF

*/

data = new PdfData();

data.add(new ParagraphElement("Hello World"));

/*

* Create a instance of the PDF Document writer, using

* the config, data and layout

*/

pdf = new PdfDocument(config, data, layout);

/*

* generate the document

*/

pdf.createDocument();



A more complicated example and the result

/*

* Create a config object to contain file location and

* some meta data settings.

*/

config = new PdfDocumentConfig("Example 5","example5.pdf","examples");

config.setReportSubject("Example 4 - Tables");

config.setReportAuthor("Scius and iText");

/*

* Creating a header image.

*/

headerImage = new HeaderImage();

headerImage.addImage(new String("examples/top.jpg"));

headerImage.setImageScale(HeaderImage.IMAGE_PAGE_SCALE, true);

/*

* Set the default style and page numbers style.

*/

Style defaultStyle = new Style("default",Style.TYPEFACE_TIMES_ROMAN,15);

// styles for the table

Style tableStyle = new Style("default", Style.TYPEFACE_HELVETICA, 10);

tableStyle.setColor(Color.BLUE);

Style tableHeaderStyle = new Style("default", Style.TYPEFACE_HELVETICA, 10);

tableHeaderStyle.setDecoration(Style.DECORATION_BOLD);

tableHeaderStyle.setBackgroundColour(192, 192, 192);

Style stylePageNumbers = new Style("pagenumbers", Style.TYPEFACE_TIMES_ROMAN, 15);

stylePageNumbers.setAlign(Style.ALIGN_RIGHT);


/*

* Create a two column footer.

*/

footer = new FooterTwoColumns(50,50);

footer.setLeftColumn(new CellElement("Example 4"));

footer.setRightColumn(new CellElement("",stylePageNumbers));

footer.setStyle(defaultStyle);

footer.setPageNum(new PageNumbersElement(stylePageNumbers));

footer.includePageNumbers(true,FooterTwoColumns.PAGE_NUMBERS_RIGHT);

/*

* Create a layout, size, orientation, margins, header and footer

*/

layout = new LayoutElement(

LayoutElement.PAGESIZE_A4,

LayoutElement.ORIENTATION_PORTRAIT,

20,20,10,10,100,100

);

layout.setHeaderImage(headerImage);

layout.setFooter(footer);

/*

* Create the PDF content, the data written to the PDF.

*/

data = new PdfData();

data.add(new ParagraphElement("Hello World", defaultStyle));

data.add(new ParagraphElement("table of authors\n\n", defaultStyle));

// add tabular information

TableElement table = new TableElement(3);

// define the column widths

float[] wd = {50f, 25f,25f};

table.setColumnWidths(wd);

// start adding data

RowElement row = new RowElement();

row.addCell(new CellElement("Author",tableHeaderStyle));

CellElement ce = new CellElement("Book Details",tableHeaderStyle);

ce.setCellspan(2);

row.addCell(ce);

table.AddRow(row);

RowElement row2 = new RowElement();

row2.addCell(new CellElement("Bruno Lowgie", tableStyle));

row2.addCell(new CellElement("iText in Action", tableStyle));

row2.addCell(new CellElement("http://www.lowagie.com/iText",tableStyle));

table.AddRow(row2);

RowElement row3 = new RowElement();

row3.addCell(new CellElement("Bruce Eckel", tableStyle));

row3.addCell(new CellElement("Thinking in Java", tableStyle));

row3.addCell(new CellElement("http://mindview.net/Books/TIJ4",tableStyle));

table.AddRow(row3);

// add the table to the data transfer object

data.add(table);

/*

* Create a instance of the PDF Document writer, using

* the config, data and layout.

*/

pdf = new PdfDocument(config, data, layout);

/*

* creates the pdf document file.

*/

pdf.createDocument();


Where can I get it ?

Here...

What's in the zip file ?

The zip file contains;

  • A source folder, complete with 5 examples.
  • A library folder with my library (scius-pdfdoc-beta6.jar) and the iText jar,
  • A doc folder with a document that describes the library and how to get started with it in eclipse,
  • A javadoc foder with the javadoc for the source code.

What's next ?


If I get enough interest then I'll write a step by step guide, similar to the eclipse one, showing you how to using the library in Notes and Domino.

16 comments:

  1. Brilliant!
    I've been doing quite a bit with iText recently too and also found it a drag to do many repeated tasks.
    I'd been planning a "beyond hello world" article for codestore. When I get round to it I'll be sure to point to this too.
    I don't know about you but I found I had to learn PDF layout techniques from scratch. I'd imagined that knowing about HTML table-based layout would help, but it didn't seem to.

    ReplyDelete
  2. Great job Tony!
    I also did some work with iText and found that PDF is very complex. Your code makes it much easier for the simple tasks.
    Thanks for sharing.

    ReplyDelete
  3. Jake,

    Yes, there were somethings that were counter intuative to what I would have expected, alignment was one and where 0,0 is located. On the plus side though, there is a great deal of power that you can tap into once you're over that initial learning curve. The maps/graphs examples, and the template system for storing images once, spring to mind. I forked out for the book and it was worth every penny.

    glad you like the library and I'm looking forward to your take on the iText library.

    ReplyDelete
  4. Vitor,

    Thanks for the comment. The aim was to make the regular stuff easier. I figure that it might encourage a few ND developers, that haven't started using java, to give it a go.

    ReplyDelete
  5. Hi Tony,

    Thanks, really helps making things easier.
    How about putting it on OpenNTF? :)

    Vince

    ReplyDelete
  6. Michael Marcavage12:18 am

    Maybe you should submit your version to the iText people.
    This way it becomes a standard....

    Just an idea

    ReplyDelete
  7. Anonymous12:33 am

    For Template based letter generation we can use Jasperreports with servlets, its very easy tool for creating layouts.

    ReplyDelete
  8. Vince,

    I was thinking about putting it on openntf, but the library is pure java - not really ND specific, which is why I haven't. If enough people were interested in modifying it then maybe I'd put it onto one of the open source web based scm services. Down the track (when I have time), I'm thinking of creating a few examples of its use in ND and those NTFs would most definitely end up in openntf.

    I guess there is nothing stopping the library being integrated into SuperNTF or any of the other projects right now.

    ReplyDelete
  9. Michael,

    Yes, I did think about it. Haven't done anything about it yet.

    ReplyDelete
  10. Craig Vertigan11:29 am

    Cool, I've been looking at doing this in Domino at some stage.

    PS: I met you at the recent Lotus Tech University in Sydney - I'm the guy from Hobart, Tasmania. ;)

    ReplyDelete
  11. Craig,

    Thanks for the comment - yep I remember. I hope that you find the library a useful starting point.

    ReplyDelete
  12. Anonymous6:43 pm

    This looks great, thanks, Sean

    ReplyDelete
  13. Tony, this is impressive. I have been struggling to get one of our documents into PDF (It has many tables and the only we I have found to do it reliably is to print to pdf which does not lend itself to automation - I think.)

    Would you be willing to speak with me or exchange email about this?

    Eric

    ReplyDelete
  14. @Sean, thanks.

    @Eric,

    Yes, happy to talk further. I'll send through my contact details shortly.

    ReplyDelete
  15. Anonymous7:28 pm

    Hello!
    I have downloaded the package with your library and iText.
    I am not very good at licences.
    Can i use it in a comercial application that i will sell, without having to publish any of my own code?

    ReplyDelete
  16. Anonymous,

    I would seek the advice of someone who understands licenses better than I do, especially if you plan to sell it. I purposely chose the same license model as iText as I'm not selling the software - my scenario is simpler.

    ReplyDelete