navigation

Create PDF documents like a pro – part 2

Create PDF documents like a pro – part 2

by
December 12, 2014

This is the second part of my series of  blog posts in which I explore how to manipulate PDF files through Java. In Part 1 I described how to create dynamic documents and documents from a template. How its time to learn to add a footer and content to the template. We use the iText library to create PDF documents because its opensource and can be downloaded here.

Add content to template

I will show you how to accomplish the following scenario where you want to add a dynamic part after the static template part is over. Once we know where the static part ends,  we will use the position of our last template field. Also to handle data spread across multiple pages we will use ColumnText. We need to use this component because when we create new PDF document iText takes care of adding new pages and spreading the content over the pages. However, here we reuse PDF so we have to take care of this ourselves. For this purpose, we will use the following self explanatory code which contains important comments. So, read through them:

public class DynamicTemplateExample {

public static void main(String[] args) throws IOException,
                                                               DocumentException {

File newCoverPage = new File("DynamicTemapleExample.pdf");
FileOutputStream fileOutputStream = newFileOutputStream(newCoverPage);
PdfReader pdfTemplate = new PdfReader(new
FileInputStream("PdfPageTemplate.pdf"));

//Again use the stamper object

PdfStamper stamper = new PdfStamper(pdfTemplate, fileOutputStream);
         stamper.setFormFlattening(true);

//Here you can fill the acrofields then take the last and take its position.

AcroFields acroFields = stamper.getAcroFields();
      acroFields.setField("TextArea", TemplateExample.getLoremText());
FieldPosition position = acroFields.getFieldPositions("TextArea").get(0);
          PdfContentByte canvas = stamper.getOverContent(1);
          PdfDocument document = canvas.getPdfDocument();

//Here we take its bottom position and the 15 is for some more space or we can add new line instead

  float contenEnd = position.position.getBottom() - 15;
    int pageNum = 1;
    Rectangle page = pdfTemplate.getPageSize(pageNum);

//First rectangle object represents the space that is left from the end of the content till the end of the template page

 Rectangle firstPageRect =
        new Rectangle(page.getLeft() + document.leftMargin(),
                    page.getBottom() + document.bottomMargin(),
                      page.getRight() - document.rightMargin(), contenEnd);

//This rectangle represent the content space for the newly added pages

 Rectangle nextPageRect =
       new Rectangle(page.getLeft() + document.leftMargin(),
                      page.getBottom() + document.bottomMargin(),
                      page.getRight() - document.rightMargin(),
                      page.getTop() - document.topMargin());

    PdfPTable largeTable = createLargeTable(page.getRight() + document.rightMargin());

//ColumnText object will help us to handle the multiple page content

ColumnText ct = new ColumnText(stamper.getOverContent(pageNum));

//If you want you can create space with a new line. For the line this is one good way

ct.addElement(Chunk.NEWLINE);
ct.addElement(largeTable);
ct.setSimpleColumn(firstPageRect);
while (true) {

//Here it is important to set the new canvas. The one of the new page

 ct.setCanvas(stamper.getOverContent(pageNum));
}
stamper.close();
pdfTemplate.close();
fileOutputStream.close();
}
public static PdfPTable createLargeTable(float width) {
PdfPTable largeTable = new PdfPTable(1);
largeTable.setTotalWidth(width);
largeTable.setWidthPercentage(100.0f);
largeTable.setSplitRows(true);
largeTable.setSplitLate(false);

              PdfPCell cell = new PdfPCell(new Phrase("LARGE TEXT"));
cell.setBorder(Rectangle.NO_BORDER);
for (int i = 0; i <= 100; i++) {
                     cell.addElement(new Paragraph("LARGE TEXT"));
}
          largeTable.addCell(cell);
            return largeTable;
          }
   }

**When you “call” the method it will return one of the following situations: the column ended or the text ended. In the first case “the column ended”  a new column definition can be loaded with the method setColumns and the method go can be called again. The second situation “the text ended” more text can be loaded with addText and the method go can be called again. The only limitation is that one or more complete paragraphs must be loaded each time.
You can see the example.

Adding a footer

Here we will explore how to accomplish a very common scenario which is adding a header or footer to every page of your PDF document. This is done with the help of page events and for our purposes we will use PdfPageEventHelper. This class is really useful because it allows us to implement only the methods that are important for us and the other methods from the PdfPageEvent interface have a default implementation. In our case we are interested in onEndPage event method which will help us implement footer for every page and another method like onChapterEnd, onParagraph will have their default behavior. The class that extends the PdfPageEventHelper  is normal class and it can be separated class or inner class.I use an inner class because it will not be used anywhere except for this tutorial. The onEndPage is executed when we reach the end of the current page and we will create our footer content again in the table in it.The next code will illustrate the scenario it is self explanatory and has comments in it so read them:

public class HeaderFooterExample {

//We use this method to create large text that will expand on several pages in order to see that footer is added to every page

public static PdfPTable createLargeTable() {
PdfPTable largeTable = new PdfPTable(1);
largeTable.setWidthPercentage(100.0f);
largeTable.setSplitRows(true);
largeTable.setSplitLate(false);

PdfPCell cell = new PdfPCell(new Phrase("LARGE TEXT"));
cell.setBorder(Rectangle.NO_BORDER);
for (int i = 0; i <= 10000; i++) {
cell.addElement(new Paragraph("LARGE TEXT"));
}
largeTable.addCell(cell);
return largeTable;
}

public static void createDocument() throws FileNotFoundException, IOException,
                                  DocumentException {
Document document = new Document();
document.setMargins(72f, 72f, 36f, 45f);
FileOutputStream fos = new FileOutputStream(new File("HeaderFooterExample.pdf"));
PdfWriter writer = PdfWriter.getInstance(document, fos);

//It is important to create and register the page event before opening the document. Here is the creation of the event

HeaderFooter event = new HeaderFooter();

//Here we register the event in the setPageEvent method

writer.setPageEvent(event);
document.open();

document.add(createLargeTable());

document.close();
fos.close();
}

public static void main(String[] args) throws FileNotFoundException,
IOException,
DocumentException {
createDocument();
}

//Inner class that extends the PdfPageEventHelper  and will take care of the page footer

private static class HeaderFooter extends PdfPageEventHelper {

//The total width of the table is needed that is why we need the width parameter

private PdfPTable createFooterTable(float width) throws DocumentException {
PdfPTable regardsTable = new PdfPTable(1);
regardsTable.setWidthPercentage(100.0f);
regardsTable.setTotalWidth(width);

PdfPCell cell = new PdfPCell();
cell.setBorder(Rectangle.NO_BORDER);
      cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
cell.addElement(new Paragraph("Footer text"));
regardsTable.addCell(cell);

return regardsTable;
}

//This method is called on every page end so it will add footer to every page

public void onEndPage(PdfWriter writer, Document document) {
PdfPTable footerTable = null;
try {

//The width of the table is the whole space between the page margins

footerTable =
         createFooterTable(document.left() + document.right() -
              2 * document.rightMargin());
} catch (DocumentException e) {
e.printStackTrace();
}

float x = document.left();
float y = document.bottomMargin();

footerTable.writeSelectedRows(0, -1, x, y - 4,
writer.getDirectContent());
}
}
}

Here is the example.
In PART 3 I will draw your attention to creating checkboxes and copying pages. Until then …

I welcome your thoughts and comments on the topic.

 

Denis Danov

Java EE and Oracle Developer at Dreamix

More Posts - Website

Follow Me:
TwitterLinkedInGoogle Plus

Do you want more great blogs like this?

Subscribe for Dreamix Blog now!