Update, September 2026Since this thread still gets found, an update: the answer is now "yes", in two different ways depending on what you want the page number
for.
1. You want the number in the docx (a link whose text says "110")The Word way to express this is a PAGEREF field pointing at the bookmark:
- Code: Select all
{ PAGEREF myBookmark \h }
Word recomputes its result whenever fields are updated, so the docx stays correct as it is edited. What docx4j couldn't do before was fill in the
cached result (the "110") so the number shows before anyone presses F9. From 17.1.1 it can, because docx4j has a layout model, courtesy of Apache FOP:
- Code: Select all
PaginationMap map = Paginate.compute(wordMLPackage, null);
Map<String, String> byBookmark = Paginate.bookmarkKeys(wordMLPackage.getMainDocumentPart());
Integer page = map.getPage(byBookmark.get("myBookmark"));
Paginate (org.docx4j.model.pagination) lays the document out with FOP and reads back which page each paragraph starts on;
bookmarkKeys maps each bookmark name to the paragraph it opens in. Put the number in the field's result run and you have your link. This is exactly what docx4j's TOC generator now does for its own PAGEREF entries.
2. You want the number in a PDFThen you don't need to compute anything. In PDF output, a PAGEREF field becomes an fo:page-number-citation, which FOP resolves as it renders, so the page number is always right for that rendering. Just make sure the field exists; its cached result doesn't matter.
About counting w:lastRenderedPageBreakThe 2009 suggestion still works, with the same caveat: those markers record Word's
last layout, so they're only right if the document hasn't changed since Word saved it. Two things worth knowing now. First, Paginate.paginate(...) rewrites those markers from a fresh layout, so after editing a document with docx4j you can refresh them rather than trust stale ones. Second, to dqkit's question: a page ends where the
next w:lastRenderedPageBreak is (it sits at the start of the first run on the new page), and inside a paragraph that spans pages the marker sits mid-paragraph, at the exact character; a w:br with w:type="page" is a different thing, an explicit break the author put there, and a page also ends there.
The usual caveats: the layout is FOP's, using the fonts it can see, so it is close to Word's rather than identical, and it needs docx4j-export-fo on the classpath.