geeky · non php code

itext page number (page x of y)

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.

5 thoughts on “itext page number (page x of y)

  1. 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.

  2. 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?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s