logo

Generating PDF Documents From Templates

Generating PDF documents on the fly isn't exactly rocket science and - with the help of tools like iText - is easily done in Java and something I've talked about before.

The trouble is that creating them is a cumbersome and often tedious task if what you want is anything other than a set of plain text paragraphs added in series. Unlike creating HTML everything in PDF-land is of absolute size and position. I find that getting the result you want is often a case of repetitive, pixel by pixel tweaking to get it right. You need a lot of patience.

If you had a complicated document to create with logos and background images then you're in for a rough ride. What would make more sense is to use a GUI tool to author a base template and then just have your code add the text bits where necessary. This is the situation I found myself in recently and after a bit of digging I worked out how to take an existing PDF and add to it. PDF templating if you will.

Creating a Template

First thing to do, assuming you've not already been provided with a template is to create one. Let's look at creating a letter head. I did this in Word, as you can see below and simply pasted in some images, moved them about and added some company details to the footer in an off grey colour.

image

Once I was happy with it I used the File - Save As - PDF menu option to save the file in PDF format.

image  

You can see the resulting PDF below:

image 

What I did with the PDF is attached it to a document in the same Notes database as we're generating the PDFs from. In reality I had been provided with a PDF template by my client's design agency, so that's what I attached. I could skip the bit above about creating a template, but went through it here in case you need help or inspiration.

The idea behind adding it as an attachment to a document is that the client has control over the template and can change it as and when they please. That being another benefit of this approach - if they happened to change the design of the letterhead then I'd have to go back to messing with the code each time. With this approach there should be no need to.

All we need to do now is add the actual content. Here's an example of what the generated PDF looks like once we've done adding to it with our own code:

image

Let's look at how we'd do that.

Adding To The Template

The code below is the Java needed to create a new PDF document, import the existing template and then add our own text atop of it.

//Setup a new PDF Document
Document document = new Document();
ByteArrayOutputStream os = new ByteArrayOutputStream();

PdfWriter writer = PdfWriter.getInstance(document, os);

document.open();
document.newPage();

//Get the template PDF as the starting point!
View files = db.getView("files");
lotus.domino.Document filestore =
    settings.getDocumentByKey("pdf_template.pdf", true);

String filename = filestore.getItemValueString("FileName");

EmbeddedObject file = filestore.getAttachment(filesname);
InputStream is = file.getInputStream();

//Here's the key part. Let's turn the template in to
//usable PDF object
PdfReader reader = new PdfReader(is);
PdfImportedPage page = writer.getImportedPage(reader, 1);

//Now, add it to the blank PDF document we've opened
PdfContentByte cb = writer.getDirectContent();
cb.addTemplate(page, 0, 0);

//Now do the usual addition of text atop the template
document.add(
    new Paragraph("Here some text added to the template")
);
//Etc, etc

//Done!
document.close();

//Tidy up
is.close();
file.recycle(); //Make SURE you do this!!!

//Attach the resuling PDF to the Notes document
Stream stream = session.createStream();
stream.write(os.toByteArray());

MIMEEntity m = doc.createMIMEEntity("Files");

MIMEHeader header = m.createHeader("content-disposition");
header.setHeaderVal("attachment;filename=\""+filename+"\"");

m.setContentFromBytes(stream,
    "application/pdf",
    MIMEEntity.ENC_IDENTITY_BINARY);

m.decodeContent();

Code's boring though. What you want is a demo and a download, no?

A Demo

Here's the demo form. Fill in the fields and submit to see what gets generated. Here's an example of an outputted PDF file.

The working download will be in form of DEXT 20091123, which will be in the Sandbox in the next few minutes.

Comments

    • avatar
    • Dragon Cotterill
    • Mon 23 Nov 2009 04:21 AM

    Once again, you're flying ahead of the curve. Lovely stuff.

  1. My good pal Dragon bet me to it - Jake, you're my hero! Haha. Amazing stuff. The black art of PDF generation might finally be demystified!

    Now I'm annoyed ... I'm scheduled up on work all week but want to go and play instead!!!

    :-)

    Thanks

  2. Thanks Jake. Another great demo. We can put this directly to work!

    -- Jeff

  3. Thanks Jake, another great suggestion. In the sandbox area, perhaps you linked the previous database.

    Thanks again

      • avatar
      • Jake Howlett
      • Mon 23 Nov 2009 08:25 AM

      Woops. You're right Renato. I uploaded the wrong Zip file. Should be the right one now...

  4. Excellent Jake, this is incredibly useful as I often have the need to create pdfs on the fly and have been looking for a less cumbersome solution.

  5. Very helpful Jake to know this is possible. I'm a bit confused, however.

    --

    First I think you've got a typo here:

    String filename = filestore.getItemValueString("FileName");

    EmbeddedObject file = filestore.getAttachment(filesname);

    You have "filename" first and then "filesname" second.

    --

    I don't find any definition for "doc" in this line of code.

    MIMEEntity m = doc.createMIMEEntity("Files");

    --

    When you add the template into the blank PDF the code looks like this:

    cb.addTemplate(page, 0, 0);

    I'm guessing the "0,0" is the coordinates of where to add the template page. The code to add the new paragraph looks like this:

    //Now do the usual addition of text atop the template

    document.add(

    new Paragraph("Here some text added to the template")

    But this codes has no coordinates. How do you know where it's going to land on the PDF page?

    --

    In fact the relationship between these variables is confusing:

    "document" appears to be a Notes document;

    "writer" a PdfWriter associated with "document";

    "os" a ByteArrayOutputStream associates with "writer";

    "cb" a PdfContentByte seems to be a temp to hold template page but I never see it used again once written to.

    I guess they are all different ways to write to the same document.

    Is "document" a Notes document?

    It appears that "os" is only used when creating the final attached PDF while "writer" gets used in creating the PDF.

    Well, I'm stopping right here because I'm not where I can access the documentation that might clear up some of my questions. Clearly you've put a lot of work into figuring out how to do this and I know it's asking a lot, but please consider could walking us through the convoluted transformations happening in this code.

    Thanks again for sharing this.

    Peace,

    Rob:-]

      • avatar
      • Jake Howlett
      • Mon 23 Nov 2009 09:30 AM

      The code you see above isn't working code, as such. It's code I pasted from working code and then altered to make it "read better". Being an idiot I've made a few typos while doing that. If you want to better understand the code then you'll need to download the NSF demo file and see the Java in there. It should make more sense. I also left out things I thought it safe to assume - like that the "doc" is the DocumentContext etc. Although I can see the confusion with the "document" object which is the PDF document and not a Notes one. My variable naming has never been that clear really.

      Truth is I don't really understand the interplay between all the objects you mentioned enough to feel qualified to document it that well. All I'm good at is getting stuff to work. You don't always need to understand it to do that ;o)

      Jake

      Show the rest of this thread

    • avatar
    • Carlos
    • Tue 24 Nov 2009 02:42 AM

    A very nice, simple solution. It would be great to see this merged with the good work that Tony Palmer has done http://palmerweb.blogspot.com/search/label/PDF

    Anyone with good Java skills and some free time want to take this on?

      • avatar
      • Jake Howlett
      • Tue 24 Nov 2009 03:12 AM

      I was going to reply and say "thanks for the link, not seen that before" but then I noticed I was the first person to respond to his post here:

      http://palmerweb.blogspot.com/2008/10/simple-java-library-for-creating-pdfs.html

      As I said there, what he's done is a brilliant idea. Like I mentioned above, working with iText is tedious to say the least. Using Tony's extra layer removes some of this tedium so well worth using if you're planning on creating PDFs.

      Show the rest of this thread

    • avatar
    • Martin Perrie
    • Tue 24 Nov 2009 03:14 AM

    I've used a couple of techniques to generate PDFs on the fly. The first one used a Java agent with the iText library. Everything was hand-cranked - the whole content of the PDF was generated by the Java agent and whilst it worked pretty well it was a long-winded job.

    The second method used a Word template with bookmarks as described in this post by Jakob Majkilde (http://blog.majkilde.com/2008/12/word-integration.html). The Word document was then saved as a PDF also described by Jakob (http://blog.majkilde.com/2009/09/creating-pdf-files-with-office-2007.html). Again this worked pretty well, although I seem to remember that images on the Word template appeared to degrade when the document was saved to PDF.

    I need to do this again in the near future, so I think I'll take a look at the technique you've described here. Thanks, Jake.

      • avatar
      • Jake Howlett
      • Tue 24 Nov 2009 03:30 AM

      Have a look at the PdfStamper class in iText too. Something I'll try and look in to and write about at some point too...

    • avatar
    • Edward Lee
    • Tue 24 Nov 2009 07:30 AM

    Great work Jake. Thanks for sharing

  6. Well done, Jake. This was the subject of a customer requirement last year (the customer I'm presently working for) and at that time the solution came down to OLE automating the population of an Excel template and routing to a PDF print driver. Your solution is much cleaner even though getting the same sort of output from iText would be difficult in our case... it is worth building on, though. Thanks for the ongoing and outstanding contributions to the community tool-box!

  7. iText HeaderFooter class works nicely when you want to change the header/footer in multi-page docs (which you usually do)

      • avatar
      • Martin Perrie
      • Fri 27 Nov 2009 06:34 AM

      I'm no iText expert (and I haven't used the HeaderFooter class), but my understanding is that the recommended method of handling a change of page is to use the PDFPageEventHelper class that has onEndPage and onStartPage events.

  8. Anyone that has an idea of how to use this with "landscape" oriented template, just can't figure it out. Anyone ?

    • avatar
    • Anand
    • Mon 31 May 2010 07:54 AM

    Want to know which .jar files used. Urgent please reply.

    • avatar
    • Raj
    • Thu 4 Nov 2010 09:16 PM

    I downloaded the dext demo.zip but lotus notes contents to pdf is not working...although excel & text conversion happened....please advise what is wrong in that getting below messages in log.

    domino version 6.5.3

    Regards

    Raj

    05/11/2010 12:00:16 PM HTTP JVM: java.lang.UnsupportedClassVersionError: Unsupported major.minor version 48.0

      • avatar
      • Jake Howlett
      • Fri 5 Nov 2010 03:18 AM

      The domino version you're using uses a version of Java to low to support the classes needed for this demo.

      Hide the rest of this thread

        • avatar
        • Matt
        • Mon 6 Dec 2010 07:15 AM

        Do you need to buy a license to use the iText jar file?

    • avatar
    • Ramesh
    • Mon 7 May 2012 04:11 AM

    Hi,

    I want to view pdf file in jframe using swings(corejava),is there any possiblity let me know,thanks advance

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Mon 23 Nov 2009

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

More Content