I was looking for a complete example of how to dynamically generate the page numbers when you create the pdf using iText and I couldn’t find one. This is based on the example in the iText in Action book but I added my “refactoring” if you will.
I hope this helps someone. If not, it will definitely help myself in the future 🙂
public abstract class BaseReportBuilder extends PdfPageEventHelper {
protected BaseFont baseFont;
private PdfTemplate totalPages;
private float footerTextSize = 8f;
private int pageNumberAlignment = Element.ALIGN_CENTER;
public BaseReportBuilder() {
super();
baseFont = load("fonts", "tahoma.ttf");
}
private BaseFont load(String location, String fontname) {
try {
InputStream is = getClass().getClassLoader().getResourceAsStream(location + System.getProperty("file.separator") + fontname);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
while (true) {
int size = is.read(buf);
if (size < 0)
break;
out.write(buf, 0, size);
}
is.close();
buf = out.toByteArray();
return BaseFont.createFont(fontname, BaseFont.CP1252, true, true, buf, null);
} catch (Exception ex) {
return null;
}
}
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
totalPages = writer.getDirectContent().createTemplate(100, 100);
totalPages.setBoundingBox(new Rectangle(-20, -20, 100, 100));
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
cb.saveState();
String text = String.format("Page %s of ", writer.getPageNumber());
float textBase = document.bottom() - 20;
float textSize = baseFont.getWidthPoint(text, footerTextSize);
cb.beginText();
cb.setFontAndSize(baseFont, footerTextSize);
if(Element.ALIGN_CENTER == pageNumberAlignment) {
cb.setTextMatrix((document.right() / 2), textBase);
cb.showText(text);
cb.endText();
cb.addTemplate(totalPages, (document.right() / 2) + textSize, textBase);
} else if(Element.ALIGN_LEFT == pageNumberAlignment) {
cb.setTextMatrix(document.left(), textBase);
cb.showText(text);
cb.endText();
cb.addTemplate(totalPages, document.left() + textSize, textBase);
} else {
float adjust = baseFont.getWidthPoint("0", footerTextSize);
cb.setTextMatrix(document.right() - textSize - adjust, textBase);
cb.showText(text);
cb.endText();
cb.addTemplate(totalPages, document.right() - adjust, textBase);
}
cb.restoreState();
}
@Override
public void onCloseDocument(PdfWriter writer, Document document) {
totalPages.beginText();
totalPages.setFontAndSize(baseFont, footerTextSize);
totalPages.setTextMatrix(0, 0);
totalPages.showText(String.valueOf(writer.getPageNumber() - 1));
totalPages.endText();
}
public void setPageNumberAlignment(int pageNumberAlignment) {
this.pageNumberAlignment = pageNumberAlignment;
}
}
public class PageNumberReportBuilder extends BaseReportBuilder {
public ByteArrayOutputStream buildPage() {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Document document = new Document(PageSize.LETTER);
try {
PdfWriter writer = PdfWriter.getInstance(document, stream);
writer.setPageEvent(this);
document.open();
// add your document stuff
} catch(DocumentException e) {
throw new RuntimeException(e);
}
document.close();
return stream;
}
}
Download the complete code example (eclipse project) along with jUnit tests where you can actually generate the PDF file.
This is a test comment.
many thanks for the upload!
Thanks. It worked for me.
I need help for little enhancement, which is to print timestamp , page number and documet name inside a table with three columns, as a footer.
Thanks for the Post, saved my tame.
I need to show Page XofY depending on Page Header Text.
Illustrating that, in my case I am preparing Report 1,2,3; and then a summary report containing those three reports. Hence, in summary report, I have at least 3 group of reports which may contain one or more than one page each i.e. report 1 may have one or more than one page in summary; so as reports 2 and 3.
So, in summary report I have to check whether the group is 1 and if 1 has (let’s say) 2 pages I have to check the header text and show page1of2 and page 2of2. Then for Report 2 again has (let’s say) 1 page I need to reset and start with Page 1of1… so on.
How can I determine from my header text and show implement that pageXofY dynamically?