iText 7 - Different footer on last page - Null pointer in PdfDictionary

后端 未结 2 1716
情书的邮戳
情书的邮戳 2021-01-14 11:32

I am trying to implement a footer in iText7, the footer should be different on the last page of the document, I have added an event handler which is called when

相关标签:
2条回答
  • 2021-01-14 11:50

    Your approach

    As you have found out yourself,

    if I set immediateFlush to false when creating the document then I do not get this issue.

    The cause is that itext usually attempts to write data to the output stream and free memory as early as possible to not leave too big a memory footprint. Thus, your approach

    I have added an event handler which is called when the document is closed [...] trying to then loop over the pages

    during that loop usually will try and manipulate pages whose contents have already been flushed and removed from the page object.

    Setting immediateFlush to false prevents this. The down side is that you use more memory because now much more of the pdf is kept in memory until the end.

    An alternative approach

    An alternative approach would use the normal END_PAGE event listener pattern. You can give such an event listener some method to signal to it which page will be the last. When the event listener is triggered, it can check whether it is currently processing that page, and in that case it can draw an alternative footer, e.g. like this:

    class TextFooterEventHandler implements IEventHandler {
        Document doc;
        PdfPage lastPage = null;
    
        public TextFooterEventHandler(Document doc) {
            this.doc = doc;
        }
    
        @Override
        public void handleEvent(Event event) {
            PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
            PdfCanvas canvas = new PdfCanvas(docEvent.getPage());
            Rectangle pageSize = docEvent.getPage().getPageSize();
            canvas.beginText();
            try {
                canvas.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA_OBLIQUE), 5);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (lastPage == docEvent.getPage()) {
                canvas.moveText((pageSize.getRight() - doc.getRightMargin() - (pageSize.getLeft() + doc.getLeftMargin())) / 2 + doc.getLeftMargin(), pageSize.getTop() - doc.getTopMargin() + 10)
                    .showText("VERY SPAECIAL LAST PAGE HEADER")
                    .moveText(0, (pageSize.getBottom() + doc.getBottomMargin()) - (pageSize.getTop() - doc.getTopMargin()) - 20)
                    .showText("VERY SPAECIAL LAST PAGE FOOTER")
                    .endText()
                    .release();
            } else {
                canvas.moveText((pageSize.getRight() - doc.getRightMargin() - (pageSize.getLeft() + doc.getLeftMargin())) / 2 + doc.getLeftMargin(), pageSize.getTop() - doc.getTopMargin() + 10)
                    .showText("this is a header")
                    .moveText(0, (pageSize.getBottom() + doc.getBottomMargin()) - (pageSize.getTop() - doc.getTopMargin()) - 20)
                    .showText("this is a footer")
                    .endText()
                    .release();
            }
        }
    }    
    

    (inner class in CreateSpecificFooters)

    You can use it like this:

    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new File("differentLastPageFooter.pdf")));
    Document doc = new Document(pdfDoc);
    TextFooterEventHandler eventHandler = new TextFooterEventHandler(doc);
    pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, eventHandler);
    for (int i = 0; i < 12; i++) {
        doc.add(new Paragraph("Test " + i + " Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."));
    }
    
    // the currently last page is also the last page of the document, so inform the event listener 
    eventHandler.lastPage = pdfDoc.getLastPage();
    doc.close();
    

    (CreateSpecificFooters test testDifferentLastPageFooter)

    You may have observed that in contrast to my original comment

    you can give that event listener some method to signal to it that the next event to come will be for the special case.

    I here do not signal "the next event to come" to be special but instead "the next event to come for the given page object". The cause is that iText 7 page events are triggered with some delay, so when I give the signal as above, the event for the page before the last might not have been triggered yet.

    By the way, I based this example on the iText samples class com.itextpdf.samples.sandbox.events.TextFooter. The samples class VariableHeader in the same package appears to indicate that my original thought (signaling "the next event to come" to be special) should have worked. The difference is, though, that in that example pages are switched by feeding AreaBreak objects to the document. This seems to trigger events early. In general, though, you cannot tell when pages shall switch, so in general you should also give the event listener the page to verify it has the correct page to treat specially.

    0 讨论(0)
  • 2021-01-14 12:09

    I have not used itext before, but the javadoc for onCloseDocument in itext5 says:

    Called when the document is closed. Note that this method is called with the page number equal to the last page plus one.

    could it be that you simply have to change your loop from

    for (int i = 1; i <= document.getPdfDocument().getNumberOfPages(); i++)
    {
    

    to

    for (int i = 1; i < document.getPdfDocument().getNumberOfPages(); i++)
    {
    

    ? (note the i < ... instead of i <= )

    0 讨论(0)
提交回复
热议问题