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?