使用ReportLab正确添加PDF页码和总页数

5
我正在尝试创建一个文档,其中页面编号的格式为“第x页,共y页”。 我尝试了NumberedCanvas方法(http://code.activestate.com/recipes/576832/和论坛https://groups.google.com/forum/#!topic/reportlab-users/9RJWbrgrklI),但这与我的可点击目录(https://www.reportlab.com/snippets/13/)发生冲突。
我从这篇文章中了解到http://two.pairlist.net/pipermail/reportlab-users/2002-May/000020.html,可能可以使用表单实现,但是关于此的示例非常少且不具有信息量。 有人知道如何使用表单实现这个功能吗(或修复NumberedCanvas方法)?
3个回答

10

这个页面 (http://www.blog.pythonlibrary.org/2013/08/12/reportlab-how-to-add-page-numbers/) 解释了一个好的方法来添加页码。我进行了一些更改,以更好地利用继承。

它创建了一个新类,该类继承自ReportLab Canvas类。

这是我的修改后的代码:

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)

要使用它,只需在创建新文件时将 Canvas 更改为 NumberedCanvas。保存文件时会添加数字。


太棒了!我不知道你还可以在页面完成后继续画图。 - Yotam Alon
原则上是个好主意,但是在今天并且使用Python 3.6.x时,我得到的结果是空的PDF和错误。 - SkyWalker
@SkyWalker 我正在使用Python 3.6.8版本的项目,在生产环境中使用它。你使用的是哪个ReportLib版本?我使用的是3.5.34。 - Martin

3
所以我最终将文档呈现了两次。这样需要多几秒钟的时间,但效果非常好!
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)

虽然不是完全满意,但有时候你需要接受现实!

确保在第一次和第二次multiBuild中不要传递相同的对象,因为report lab在第一次构建过程中会添加一些属性到它们上面,在第二次构建中会导致错误。

我有点担心在构建后画布对象可能会被销毁或重置,所以如果未来有人想使用它,请小心。


0

在上面的答案中提到的方法,覆盖了画布类,最终导致页面引用(例如使用bookmarkPage())在生成的pdf中出现问题。这很可能是因为按照所描述的方式调用self.__doc.addPage()(在canvas.showPage()中找到)太晚了。

文档中的所有引用都将指向第一页,无论何时调用bookmarkPage()。

然而,可以通过增加新的showPage方法中的self._doc.pageCounter来修复引用问题;

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接