Properly add page numbers and total number of pages to PDF using ReportLab

泄露秘密 提交于 2021-02-18 18:15:12

问题


I am trying to create a document that has page numbering of the format "Page x of y". I have tried the NumberedCanvas approach (http://code.activestate.com/recipes/576832/ and also from the forums https://groups.google.com/forum/#!topic/reportlab-users/9RJWbrgrklI) but that conflicts with my clickable Table of Contents (https://www.reportlab.com/snippets/13/).

I understood from this post http://two.pairlist.net/pipermail/reportlab-users/2002-May/000020.html that it may be possible using forms, but examples on this are very scarce and uninformative. Does anybody have any idea on how this can be implemented using forms (or fixing the NumberedCanvas approach?)


回答1:


This page (http://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/) explains a good way to do it. I made some changes to make better use of inheritance.

It creates a new Class that inherits from ReportLab Canvas class.

This is my modified code:

from reportlab.lib.units import mm
from reportlab.pdfgen.canvas import Canvas


class NumberedPageCanvas(Canvas):
    """
    http://code.activestate.com/recipes/546511-page-x-of-y-with-reportlab/
    http://code.activestate.com/recipes/576832/
    http://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/
    """

    def __init__(self, *args, **kwargs):
        """Constructor"""
        super().__init__(*args, **kwargs)
        self.pages = []

    def showPage(self):
        """
        On a page break, add information to the list
        """
        self.pages.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        """
        Add the page number to each page (page x of y)
        """
        page_count = len(self.pages)

        for page in self.pages:
            self.__dict__.update(page)
            self.draw_page_number(page_count)
            super().showPage()

        super().save()

    def draw_page_number(self, page_count):
        """
        Add the page number
        """
        page = "Page %s of %s" % (self._pageNumber, page_count)
        self.setFont("Helvetica", 9)
        self.drawRightString(179 * mm, -280 * mm, page)

To use it just change Canvas for NumberedCanvas when creating a new file. When the file is saved the numbers are added.




回答2:


So I ended up rendering the document twice. Takes a couple more seconds, but works very well!

class MyDocTemplate(BaseDocTemplate):
    def generate(self, story):
        self.multiBuild(story[:])
        # Decrease by one because canvas is at the page after the last
        self.page_count = self.canv.getPageNumber() - 1
        self.multiBuild(story[:])


class MyPageTemplate(PageTemplate):
    def onPage(self, canvas, doc):
        if getattr(doc, 'page_count', None) is not None:
            canvas.drawString(x, y, canvas.getPageNumber(), doc.page_count)

Not 100% happy, but sometimes you take what you can get!

Make sure you do not pass the same objects to the first and second multiBuild, as report lab adds some properties to them during the first build, that will cause errors in the second build.

I am slightly concerned that at some point the canvas object might be destroyed or reset after the build, so if any future people want to use this, be careful.



来源:https://stackoverflow.com/questions/51498663/properly-add-page-numbers-and-total-number-of-pages-to-pdf-using-reportlab

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!