Adding Header and Footer in PDF using iText in Java
When creating PDF documents, the first thing we usually do, is create a header and footer for every page. Adding an image to the header, helps to brand the product and/or business. At the bottom of the page we can optionally include a copyright symbol followed by some text. In the bottom right corner you can find the current page number, followed by the total number of pages. In this tutorial we demonstrate how to add a header and footer in a PDF document using iText.
IText Dependency
We use Maven, add the following maven dependency to your project, and Maven’ll resolve the dependencies automatically.
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.9</version>
</dependency>
Adding Header, Footer and Total Pages
The com.itextpdf.text.pdf.PdfPageEventHelper
contains all the events that occur when iText is writing a PDF document. By extending from this class and overriding these methods, we can write additional data to the PDF document when these events occur. Let’s take a look at the events.
- onOpenDocument called when the document is opened. Perfect place to initialize certain variables.
- onEndPage is called when a page is finished, just before being written to the document. We can add the header and footer to every page inside the PDF document.
- onCloseDocument is called before the document’ll be closed. This is the event where we inject the total number of pages in to the previously created template.
package com.memorynotfound.pdf.itext;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import java.io.IOException;
import java.net.MalformedURLException;
public class HeaderFooterPageEvent extends PdfPageEventHelper {
private PdfTemplate t;
private Image total;
public void onOpenDocument(PdfWriter writer, Document document) {
t = writer.getDirectContent().createTemplate(30, 16);
try {
total = Image.getInstance(t);
total.setRole(PdfName.ARTIFACT);
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
addHeader(writer);
addFooter(writer);
}
private void addHeader(PdfWriter writer){
PdfPTable header = new PdfPTable(2);
try {
// set defaults
header.setWidths(new int[]{2, 24});
header.setTotalWidth(527);
header.setLockedWidth(true);
header.getDefaultCell().setFixedHeight(40);
header.getDefaultCell().setBorder(Rectangle.BOTTOM);
header.getDefaultCell().setBorderColor(BaseColor.LIGHT_GRAY);
// add image
Image logo = Image.getInstance(HeaderFooterPageEvent.class.getResource("/memorynotfound-logo.jpg"));
header.addCell(logo);
// add text
PdfPCell text = new PdfPCell();
text.setPaddingBottom(15);
text.setPaddingLeft(10);
text.setBorder(Rectangle.BOTTOM);
text.setBorderColor(BaseColor.LIGHT_GRAY);
text.addElement(new Phrase("iText PDF Header Footer Example", new Font(Font.FontFamily.HELVETICA, 12)));
text.addElement(new Phrase("https://memorynotfound.com", new Font(Font.FontFamily.HELVETICA, 8)));
header.addCell(text);
// write content
header.writeSelectedRows(0, -1, 34, 803, writer.getDirectContent());
} catch(DocumentException de) {
throw new ExceptionConverter(de);
} catch (MalformedURLException e) {
throw new ExceptionConverter(e);
} catch (IOException e) {
throw new ExceptionConverter(e);
}
}
private void addFooter(PdfWriter writer){
PdfPTable footer = new PdfPTable(3);
try {
// set defaults
footer.setWidths(new int[]{24, 2, 1});
footer.setTotalWidth(527);
footer.setLockedWidth(true);
footer.getDefaultCell().setFixedHeight(40);
footer.getDefaultCell().setBorder(Rectangle.TOP);
footer.getDefaultCell().setBorderColor(BaseColor.LIGHT_GRAY);
// add copyright
footer.addCell(new Phrase("\u00A9 Memorynotfound.com", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD)));
// add current page count
footer.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
footer.addCell(new Phrase(String.format("Page %d of", writer.getPageNumber()), new Font(Font.FontFamily.HELVETICA, 8)));
// add placeholder for total page count
PdfPCell totalPageCount = new PdfPCell(total);
totalPageCount.setBorder(Rectangle.TOP);
totalPageCount.setBorderColor(BaseColor.LIGHT_GRAY);
footer.addCell(totalPageCount);
// write page
PdfContentByte canvas = writer.getDirectContent();
canvas.beginMarkedContentSequence(PdfName.ARTIFACT);
footer.writeSelectedRows(0, -1, 34, 50, canvas);
canvas.endMarkedContentSequence();
} catch(DocumentException de) {
throw new ExceptionConverter(de);
}
}
public void onCloseDocument(PdfWriter writer, Document document) {
int totalLength = String.valueOf(writer.getPageNumber()).length();
int totalWidth = totalLength * 5;
ColumnText.showTextAligned(t, Element.ALIGN_RIGHT,
new Phrase(String.valueOf(writer.getPageNumber()), new Font(Font.FontFamily.HELVETICA, 8)),
totalWidth, 6, 0);
}
}
Adding Total Number of Pages
- In the first event,
onOpenDocument
, we initialized thePdfTemplate
variable. This variable is a placeholder in which we add the total number of pages digit. This is due to the fact, that we only know the total of pages when we are finished writing content to the pdf document. - Let’s immediately jump to the
onCloseDocument
event. In this event iText is about to close the document, meaning we know exactly on which page number thePdfWriter
is currently on. First, we calculate the number of digits the page number has. We need to calculate the number of pixels to allocate. Using the current font we’ve calculated that each digit takes approximately 5 pixels. So by multiplying the total length of the page numbers by the total width of a single digit, we are allocating enough space. Finally, we insert the page number total in the perviously createdPdfTemplate
.
Adding the Header and Footer
- In the
onEndPage
event, we are adding the header and footer to the PDF document. This event occurs every time a page has finished, just before being written to the document. - We created a
addHeader
method, which will obviously add a header to the document. In this method, we create aPdfTable
with two columns. The first column is for the logo (image) and the second is for the text. We initialize the header with a fixed height, correct width and adding a border to the bottom. In the first column we add the image which is loaded from thesrc/main/resources
folder. Next, we create aPdfCell
in which we add twoPhrase
elements that contain text. Finally, we call thewriteSelectedRows
method that will write thePDFTable
to the document at a fixed position. - The
addFooter
method does almost the same as theaddHeader
method. But notice, that we add the previously createdPdfTemplate
inside aPdfCell
. This template acts like a placeholder in which we are injecting the total page number.
Adding copyright and symbols
We can add a copyright symbol to a PDF Document using the unicode character \u00A9
.
Adding Page Event and Create PDF Document
When creating the PDF document, we simply add the previously created HeaderFooterPageEvent
using the setPageEvent
method of the PdfWriter
.
package com.memorynotfound.pdf.itext;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class CreatePdfDocument {
public static void main(String... args) throws FileNotFoundException, DocumentException {
// create document
Document document = new Document(PageSize.A4, 36, 36, 90, 36);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("HeaderFooter.pdf"));
// add header and footer
HeaderFooterPageEvent event = new HeaderFooterPageEvent();
writer.setPageEvent(event);
// write to document
document.open();
document.add(new Paragraph("Adding a header to PDF Document using iText."));
document.newPage();
document.add(new Paragraph("Adding a footer to PDF Document using iText."));
document.close();
}
}
Output
Here you can see the result. The PDF document we generated contains a clean header with an image. The footer contains a copyright symbol on the left. On the bottom right you can see the current page number together with the total page number.
to get the right number of pages you need to replace String.valueOf(writer.getPageNumber()) by String.valueOf(writer.getPageNumber()-1) in public void onCloseDocument(PdfWriter writer, Document document)
thanks, the code was helpful
Thanks!
I get an error with:
total = Image.getInstance(t);
total.setRole(PdfName.ARTIFACT);
//He doesn´t know total.setRole AND doesn´t know PdfName.ARTIFACT
AND
PdfContentByte canvas = writer.getDirectContent();
canvas.beginMarkedContentSequence(PdfName.ARTIFACT);
footer.writeSelectedRows(0, -1, 34, 50, canvas);
canvas.endMarkedContentSequence();
//He doesn´t know PdfName.ARTIFACT and tells me there are unsychronize things or something similar
add only found in 5.5.9 itext
com.itextpdf
itextpdf
5.5.9
I have a problem with the footer, because it overlaps the text that I put in the body of the document. Do you know how I fix it so they do not overlap?
You can change de bounds/margins of the document
Thanks for this. has been very helpful. A few changes in this very code and i got my problem solved.
S’il existait un mot plus grand que MERCI, alors je l’aurais utilisé. Que Dieu vous bénéfice