2

Is there any method specified in POI API to get the total number of pages, I am able to add page number in the footer of the document but i am not able to add the total number of pages value.

user3398321
  • 73
  • 3
  • 7
  • 2
    Unfortunately word doesn't store page numbers on the file, it is generated on the fly based on text, size, etc. – Shank Dec 29 '16 at 19:09

1 Answers1

12

Page count in Word is dependent of much things like font size, paragraph top/bottom margins and padding, printer settings, manually inserted page breaks and so on. So it cannot be stored directly in the file. It will be calculated on the fly while Word is rendering its pages.

But we can use fields within the footer which also calculate the page number and the total number of pages.

Example using up to apache poi 3.14:

import java.io.*;

import org.apache.poi.xwpf.usermodel.*;

import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
//import org.apache.poi.wp.usermodel.HeaderFooterType;

public class CreateWordHeaderFooter {

 public static void main(String[] args) throws Exception {

  XWPFDocument doc= new XWPFDocument();

  // the body content
  XWPFParagraph paragraph = doc.createParagraph();
  XWPFRun run=paragraph.createRun();  
  run.setText("The Body:");

  paragraph = doc.createParagraph();
  run=paragraph.createRun();  
  run.setText("Lorem ipsum.... page 1");

  paragraph = doc.createParagraph();
  run=paragraph.createRun();
  run.addBreak(BreakType.PAGE); 
  run.setText("Lorem ipsum.... page 2");

  paragraph = doc.createParagraph();
  run=paragraph.createRun();
  run.addBreak(BreakType.PAGE); 
  run.setText("Lorem ipsum.... page 3");

  // create header-footer
  XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
  if (headerFooterPolicy == null) headerFooterPolicy = doc.createHeaderFooterPolicy();

  // create header start
  XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
  //XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);

  paragraph = header.getParagraphArray(0);
  if (paragraph == null) paragraph = header.createParagraph();
  paragraph.setAlignment(ParagraphAlignment.LEFT);

  run = paragraph.createRun();  
  run.setText("The Header:");

  // create footer start
  XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);
  //XWPFFooter footer = doc.createFooter(HeaderFooterType.DEFAULT);

  paragraph = footer.getParagraphArray(0);
  if (paragraph == null) paragraph = footer.createParagraph();
  paragraph.setAlignment(ParagraphAlignment.CENTER);

  run = paragraph.createRun();  
  run.setText("Page ");
  paragraph.getCTP().addNewFldSimple().setInstr("PAGE \\* MERGEFORMAT");
  run = paragraph.createRun();  
  run.setText(" of ");
  paragraph.getCTP().addNewFldSimple().setInstr("NUMPAGES \\* MERGEFORMAT");

  FileOutputStream out = new FileOutputStream("CreateWordHeaderFooter.docx");
  doc.write(out);
  out.close();
  doc.close();

 }
}

The fields in Word then are {PAGE \* MERGEFORMAT} and {NUMPAGES \* MERGEFORMAT}.

For using current apache poi 4.1.2 one can do this without XWPFHeaderFooterPolicy using XWPFDocument.createHeader, XWPFDocument.createFooter and HeaderFooterType:

...
//import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy;
import org.apache.poi.wp.usermodel.HeaderFooterType;
...

  // create header-footer
  //XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();
  //if (headerFooterPolicy == null) headerFooterPolicy = doc.createHeaderFooterPolicy();

  // create header start
  //XWPFHeader header = headerFooterPolicy.createHeader(XWPFHeaderFooterPolicy.DEFAULT);
  XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
...
  // create footer start
  //XWPFFooter footer = headerFooterPolicy.createFooter(XWPFHeaderFooterPolicy.DEFAULT);
  XWPFFooter footer = doc.createFooter(HeaderFooterType.DEFAULT);
...
Axel Richter
  • 56,077
  • 6
  • 60
  • 87
  • I successfully took inspiration from this answer to add the current page and the total number of pages in the footer. However I failed to add the same kind of information in the body of the document. I'm using exactly the same code, is there are reason why it is working in the footer but not in the body of the document? An additional information: I substituted "PAGE \\* MERGEFORMAT" with "DATE \\@ \"yyyy-MM-dd\" \\* MERGEFORMAT" and in this case the code is working as expected and adds the current date inside the body of the document. – rlar Jan 11 '18 at 16:27
  • I've just noticed that the code I've written is actually working. The only problem is that the field is not automatically updated and it remains empty. If I manually trigger an update of all the fields the number of pages shows up also in the body of the document. Do you know why is it happening and why to manually trigger the update of the fields is not necessary for the DATE variable? – rlar Jan 11 '18 at 17:30
  • @rlar: The problem is pretty clear. Word does first rendering the document body parts and then the header and footer parts. So while rendering the document body parts the actual page number and total number of pages is not already known. Both are results of the rendering process. The date is of course known independent of the rendering process. – Axel Richter Jan 11 '18 at 17:58