Tuesday, January 30, 2007

Grails -- How to Add Binary PDFs Into a PdfDocument Using iText

We created an application using Grails framework. This application would allow registered users to submit application forms in PDF format. For some special reasons, we have to store all the PDFs into a relational database. Then we need to create a controller, such that the admin user is able to generate a PDF report which includes all the application forms that users had submitted.

The key issue for this task is to retrieve PDF files from the relational database and merge them into a single PDF file. Inspired by the post by Abni, we solved the problem by using iText in the following steps:

Step 1: Create a PdfDocument and PdfWriter:


Document document = new Document(PageSize.A4, 50, 50, 50, 50);
PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream())


Step 2: Retrieve a binary pdf file from database and write into a byte array:

Suppose I have a domain class like this:

class Application {
Long id
ong version

String username //Primary key
byte[] application
...
...
}


In grails, it is easy to retrieve a pdf file out of database and write into a byte array , eg:

def app = Application.findByUsername(userName) //here userName is the primary key
if (app != null && app.application.size() > 0){

def byte[] app_letter = app.application
...
...
}


Step 3: Create a PdfReader from a byte array which represents a PDF file:


PdfReader pdfReader= new PdfReader(app_letter)


Please note that the byte array must represent a valid PDF file, otherwise, an exception is thrown.

Step 4: Create a page from PdfReader and add the page to PdfDocument:

PdfImportedPage applicationPage
PdfContentByte

//the pdf file may contain more than one pages
for (pageNumber in 0..pdfReader.getNumberOfPages()-1){
pageNumber++

applicationPage = writer.getImportedPage(pdfReader, pageNumber) //Create page from PdfReader

cb.addTemplate(applicationPage, 0, 0) // add page to PdfDocument
....
....
}

The snippets above just show how to retrieve one PDF file from database and add it into a PdfDocument. For multiple PDF files, we can do the same thing for each of them and update page number correspondingly.

Discussion:

1. In step 3, the byte array used to create PdfReader must represent a valid PDF file, otherwise, an exception throws. The program should handle the exception.

2. PDF files are all hold in memory. If file number is huge, then we need to consider memory issues.

Reference:

1. Merge PDF files with iText (Abhi on Java)
2. Grails online tutorial
3. Tutorial: iText By Example

2 comments:

Graeme Rocher said...

Hey, nice blog posts about Grails. Make sure you add your blog to http://groovyblogs.org

Cheers
Graeme

Xiaoyun Tang said...

Thanks Graeme, I had added my blog to the site you had mentioned.

Cheers

Xiaoyun