Wednesday, July 7, 2010

iText - Inserting New Pages

We might want to add a new blank page to a document, or import a page from an existing pdf to a new one.

New Pages

Inserting a new blank page using PdfStamper is really easy.

PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("NewPdf.pdf");
stamper.insertPage(1, PageSize.A4); //insert a new blank A4 page

Its important to note that with the PdfStamper the whole Pdf is read in. By using the insertPage method we are inserting as if it was into the original document. There is no need to iterate over pages or anything like that - it's all immediately read in as soon as the stamper is declared.

If you want to stamp content onto it, that's also really easy too:

PdfContentByte overContent = stamper.getOverContent(1);
overContent.beginText();
.. //add content
overContent.endText();

Things get a little bit more complicated when you want to insert selected pages from an existing pdf into a new document.

Importing Pages - PdfStamper

Sometimes you might want to import an existing page from a pdf and insert it into a new pdf document you have are creating. You might think that PdfReader would do all this, but the problem is PdfReader access the content stream of a page, which includes external objects like fonts etc. It is much safer to pass the PdfReader to another class such as the PdfStamper or PdfWriter, so that they can retrieve any resources behind the scenes and return the full pdf page.

To achieve this, we use PdfImportPage which zips up all the necessary resources and returns an object representing an existing pdf page.

PdfReader reader = new PdfReader("OriginalPdf.pdf"); //reads the original pdf
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("StampedPdf.pdf"));
PdfImportedPage page; //writes the new pdf to file

page = stamper.getImportedPage(reader,2); //retrieve the second page of the original pdf
PdfContentByte newPageContent = stamper.getOverContent(1); //get the over content of the first page of the new pdf
newPageContent.addTemplate(page, 0,0); //add the original page as a "template" for the new one with no transformations

You can use transformations to downsize pages, rotate them or whatever you want.

The problem with PdfStamper for importing pages is that it only works for importing pages from one and only one pdf. If you want to import pages from several pdfs then you will need to use a PdfWriter.

Importing Pages - PdfWriter

Remember that when we use PdfWriter, we need to declare a new document to work with. This isn't necessary with PdfStamper.

PdfReader reader = new PdfReader("OriginalPdf.pdf"); //reads the original pdf
Document document = new Document(); //new pdf document
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("ModifiedPdf.pdf")); //writes the new pdf to file

document.open(); //open the document
page = writer.getImportedPage(reader,2); //retrieve the second page of the original pdf
PdfContentByte newPageContent = writer.getDirectContent() //get the original page content
newPageContent.addTemplate(page, 0,0); //add the original page as a "template" for the new one with no transformations

Note that PdfWriter only has one method for accessing a PdfContentByte - getDirectContent() rather than the over and under options of the PdfStamper.

There is a major downside to remember when importing pages this way. All interactive features such as bookmarks, fields and so forth are lost in the process. If you want to retain them, you have to use PdfCopy instead.

In-depth iText information can be found in Bruno Lowagie's excellent book iText In Action http://www.manning.com/lowagie2/

2 comments: