Adding PDF Page Headers with iTextSharp
Updated 2012-01-16.
A common question on the iText mailing list; probably because it's not a simple, one-step process.
The recommended method is to create a class that inherits from PdfPageEventHelper, which you should be able to guess, allows you to handle numerous document events. Since the goal is to add a header to every page of the PDF document, the following ASP.NET web forms example is implemented using the following steps:
- Create a class in the code-behind file that overrides
PdfPageEventHelper.
- Override the
OnEndPage() method to write the page header content. You should not use OnStartPage() to write header content - you should only override the method to initialize class members.
- Instantiate a PdfPTable within the
OnEndPage() method so everything is nicely formatted. We throw in an Image object, since that's also a popular question.
- Attach an instance object of our newly created class to PdfWriter's
PageEvent property.
On to the code. First the class that inherits from PdfPageEventHelper, nested in your code-behind class:
private class MyPageEventHandler : PdfPageEventHelper {
/*
* We use a __single__ Image instance that's assigned __once__;
* the image bytes added **ONCE** to the PDF file. If you create
* separate Image instances in OnEndPage()/OnEndPage(), for example,
* you'll end up with a much bigger file size.
*/
public Image ImageHeader {get; set;}
public override void OnEndPage(PdfWriter writer, Document document) {
// cell height
float cellHeight = document.TopMargin;
// PDF document size
Rectangle page = document.PageSize;
// create two column table
PdfPTable head = new PdfPTable(2);
head.TotalWidth = page.Width;
// add image; PdfPCell() overload sizes image to fit cell
PdfPCell c = new PdfPCell(ImageHeader, true);
c.HorizontalAlignment = Element.ALIGN_RIGHT;
c.FixedHeight = cellHeight;
c.Border = PdfPCell.NO_BORDER;
head.AddCell(c);
// add the header text
c = new PdfPCell( new Phrase(
DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " GMT",
new Font(Font.FontFamily.COURIER, 8)
));
c.Border = PdfPCell.NO_BORDER;
c.VerticalAlignment = Element.ALIGN_BOTTOM;
c.FixedHeight = cellHeight;
head.AddCell(c);
// since the table header is implemented using a PdfPTable, we call
// WriteSelectedRows(), which requires absolute positions!
head.WriteSelectedRows(
0, -1, // first/last row; -1 flags all write all rows
0, // left offset
// ** bottom** yPos of the table
page.Height - cellHeight + head.TotalHeight,
writer.DirectContent
);
}
}
In the button's event handler you stream the PDF to the client using this method:
private void _streamPdf() {
using (Document document = new Document()) {
PdfWriter writer = PdfWriter.GetInstance(
document, Response.OutputStream
);
// the image we're using for the page header
Image imageHeader = Image.GetInstance(Request.MapPath(
"~/kyouyuu/image/kuujinbo2.gif"
));
// instantiate the custom PdfPageEventHelper
MyPageEventHandler e = new MyPageEventHandler() {
ImageHeader = imageHeader
};
// and add it to the PdfWriter
writer.PageEvent = e;
document.Open();
// finally we add some pages with text to show the headers are working
string text = filler.Text;
for (int k = 0; k < 8; ++k) {
text += " " + text;
Paragraph p = new Paragraph(text);
p.SpacingBefore = 8f;
document.Add(p);
}
}
The inline comments should be self-explanatory.