-1

we use itextpdf and xmlworker APIs ( itextpdf-5.1.1.jar, Xmlworker-1.1.0.jar) for PDF generation tasks in our application. We generate HTML content from XML-XSLT conversion and then use the HTML content to create pdf document.

When we trying to implement pagination ( as 1 of 3, 2 of 3..), we learnt from itextpdf online samples that we always need to create a resultant pdf document apart from the PDF document that we create in order to stamp the page number on the each page content.

This approach brings challenges in removing the intermediate pdf document. Is there any way by which page numbers can be determined during the time we create the pdf very first time so that we will avoid creating one resultant pdf document?

Thanks Venkat

class TableFooter extends PdfPageEventHelper {          
      String header;          
      PdfTemplate total;

      public void setHeader(String header) {            
          this.header = header;
      }

      public void onOpenDocument(PdfWriter writer, Document document) {
          total = writer.getDirectContent().createTemplate(30, 16);

      }

      public void onEndPage(PdfWriter writer, Document document) {
          Font ffont = new Font(Font.FontFamily.UNDEFINED, 7, Font.NORMAL);
          PdfPTable table = new PdfPTable(2);
          try 
          {
              table.setWidths(new int[]{1,1});
              table.setTotalWidth(50);
              table.getDefaultCell().setFixedHeight(15);
              table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
              Phrase footer = new Phrase(String.format("%d of", writer.getPageNumber()), ffont);
              table.addCell(footer);                
              PdfPCell cell = new PdfPCell(Image.getInstance(total));
              table.addCell(cell);
              table.writeSelectedRows(0, -1, 275, 20, writer.getDirectContent());
          }
          catch(Exception de) {
              throw new ExceptionConverter(de);
          }
      }

      public void onCloseDocument(PdfWriter writer, Document document) {            
        ColumnText.showTextAligned(total, Element.ALIGN_LEFT, new Phrase(String.valueOf(writer.getPageNumber() - 1)), 10, 4, 0);
      }
  }
VenkatRam
  • 51
  • 3
  • 11

1 Answers1

1

Please download the free ebook The Best iText Questions on StackOverflow and read the questions listed in the chapter entitled "Page events". These are some of the questions that were selected for this book:

You can also look at the keywords page on the official iText site, more specifically at the key word Page X of Y.

In your question, you refer to creating an intermediate document. That's what the TwoPasses example is about. You are asking for a way to add Page X of Y in a single pass. That's what the MovieCountries1 example is about.

class PageXofYHeader extends PdfPageEventHelper {
    /** The template with the total number of pages. */
    PdfTemplate total;

    /**
     * Creates the PdfTemplate that will hold the total number of pages.
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(
     *      com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
     */
    public void onOpenDocument(PdfWriter writer, Document document) {
        total = writer.getDirectContent().createTemplate(30, 16);
    }

    /**
     * Adds a header to every page
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(
     *      com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
     */
    public void onEndPage(PdfWriter writer, Document document) {
        PdfPTable table = new PdfPTable(2);
        try {
            table.setWidths(new int[]{48, 2});
            table.setTotalWidth(527);
            table.setLockedWidth(true);
            table.getDefaultCell().setFixedHeight(20);
            table.getDefaultCell().setBorder(Rectangle.BOTTOM);
            table.getDefaultCell()
                .setHorizontalAlignment(Element.ALIGN_RIGHT);
            table.addCell(
                String.format("Page %d of", writer.getPageNumber()));
            PdfPCell cell = new PdfPCell(Image.getInstance(total));
            cell.setBorder(Rectangle.BOTTOM);
            table.addCell(cell);
            table.writeSelectedRows(0, -1, 34, 803,
                writer.getDirectContent());
        }
        catch(DocumentException de) {
            throw new ExceptionConverter(de);
        }
    }

    /**
     * Fills out the total number of pages before the document is closed.
     * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(
     *      com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
     */
    public void onCloseDocument(PdfWriter writer, Document document) {
        ColumnText.showTextAligned(total, Element.ALIGN_LEFT,
                new Phrase(String.valueOf(writer.getPageNumber() - 1)),
                2, 2, 0);
    }
}

As you can see, we create a small place holder named total in the onOpenDocument() method. As we don't know in advance what the total number of pages will be, we add this placeholder to each page without knowing what the page total will be. We only know the final page count when we close the document, and that's why we wait until the onCloseDocument() method is triggered to add content to the placeholder.

Community
  • 1
  • 1
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Thanks Bruno Lowagie for the detailed explanation on achieving Page X of Y stuff in single pass. Since we generate PDF document from XML-XSLT-HTMLContent approach, the sample program we tried similar to MovieCountries1 created the Page X of Y on header. Is there any sample to place the Page X of Y on footer area? Can you please direct me to a sample ? – VenkatRam Feb 05 '15 at 22:43
  • No need for an extra sample. Just change the coordinates when adding the extra content. Replace 803 by something like 20 (it's up to you to decide the position of the footer). – Bruno Lowagie Feb 06 '15 at 07:20
  • Thanks Bruno Lowagie. We tried changing the coordinates in our sample but nothing helped to bring the total number (Y) of page closer to X. – VenkatRam Feb 10 '15 at 23:08
  • What makes you think pasting code in a series of comment sections was a good idea? Nobody is going to read your code. Please use StackOverflow the way it is intended. Also: you were asking to bring the footer closer to the bottom. Now you are asking to *bring the total number (Y) closer to X*. Did you get an education? Didn't you study "analytical geometry" when you were at school? – Bruno Lowagie Feb 11 '15 at 07:29
  • Hi Bruno Lowagie, I am new the stackoverflow and I just pasted the code in a series of comment sections without understanding how to post a code snippet. Now I've updated my original post the entire section of the inner class that creating the footer. The problem I face is, the total number of page (Y) is not displayed with the each page value (X) as its supposed to. Played around the coordinates inside onCloseDocument method but we couldnt succeed. I have added 3 sample outputs (with diff cordinates) into a single image file for your attention [IMG]http://i59.tinypic.com/2ihqr2e.jpg[/IMG] – VenkatRam Feb 11 '15 at 17:03
  • That looks like a bug that has been fixed a long time ago. Please upgrade to iText 5.5.4. – Bruno Lowagie Feb 11 '15 at 17:12
  • Thanks Bruno. We are in a position to upgrade iText version as the old version already been used in production environment for an application to split the pdf documents. So, we chose the approach of creating intermediate document for having page numbers and headers. – VenkatRam Feb 26 '15 at 16:45