Reportlab:更改边距后重建文档?

时间:2013-09-23 20:39:41

标签: python reportlab

在我为朋友的业务编写的程序中,我使用reportlab模块为各种报告构建PDF文档。在大多数情况下,报告可以包含在一个页面上,但在某些罕见情况下可能会跨越两个页面。在那些罕见的情况下,我想要做的是重新格式化页面的顶部和底部边距较小,看看我是否可以让它适合单页。如果没有,我只会使用最小边距并让它跨越两页。

要构建报告,我正在创建SimpleDocTemplate类的实例。在将所有流量传递到build方法后,我发现我可以查询page属性以查看它使用了多少页面。这是我尝试的第一件事:

parts = []
path = "/path/to/my/file.pdf"
# ... a bunch of code that appends various flowables to 'parts'
doc = SimpleDocTemplate(path, pagesize=landscape(letter))
doc.build(parts)
# Shrink the margins while it's more than one page and the margins are above zero
while doc.page > 1 and not any([doc.topMargin <= 0, doc.bottomMargin <= 0]):
    # Decrease the page margins and rebuild the page
    doc.topMargin -= inch * .125
    doc.bottomMargin -= inch * .125
    doc.build(parts)
# If the margins are nil and we're still at 2 or more pages, use minimal margins
if doc.page > 1:
    doc.topMargin = inch * .25
    doc.bottomMargin = inch * .25
    doc.build(parts)

我假设在更改边距后使用相同的部分调用build方法会重新计算所有内容。但是,在经过多次试验和错误之后,我了解到传递给parts方法的build列表在构建过程中基本上被剥离了,将parts留作空列表。一旦将其再次传递回build方法,它就会创建一个零页面的文档。

要解决这个问题,我尝试使用parts列表的副本构建文档:

doc.build(parts[:])

这导致了一些奇怪的异常,所以我尝试使用copy模块进行深层复制:

doc.build(copy.deepcopy(parts))

这并没有抛出任何例外,但也没有改变边距。

有点绝望,我深入研究了SimpleDocTemplate属性并找到了一个名为_calc的方法。认为这可能会重新计算页面,我尝试在更改边距后调用它。它没有抛出任何例外,但也没有用。

我设法使其发挥作用的唯一方法是使用deepcopy流程并在每次调整边距时构建全新的文档:

doc = SimpleDocTemplate(path, pagesize=landscape(letter))
doc.build(copy.deepcopy(parts))
# Shrink the margins while it's more than one page and the margins are above zero
while doc.page > 1 and not any([doc.topMargin <= 0, doc.bottomMargin <= 0]):
    doc.topMargin -= inch * .125
    doc.bottomMargin -= inch * .125
    doc = SimpleDocTemplate(path, pagesize=landscape(letter),
                            topMargin = doc.topMargin,
                            bottomMargin = doc.bottomMargin)
    doc.build(copy.deepcopy(parts))
# If the margins are nil and we're still at 2 or more pages, use minimal margins
if doc.page > 1:
    doc.topMargin = inch * .25
    doc.bottomMargin = inch * .25
    doc = SimpleDocTemplate(path, pagesize=landscape(letter),
                            topMargin = doc.topMargin,
                            bottomMargin = doc.bottomMargin)
    doc.build(copy.deepcopy(parts))

然而,走这条路是感觉做了很多不必要的工作。我更愿意只更改文档边距并告诉文档使用这些新值重建自己,但我无法弄清楚如何。这甚至可能吗?

1 个答案:

答案 0 :(得分:1)

一个非常有趣的问题。但是,我相信你已经在ReportLab中找到了正确的方法。构建过程是一个可以对文档执行的一次性操作,因为它会产生无法回复的副作用。值得庆幸的是,正如您已经发现的那样,尽管有点烦人,但要做到你想要的并不是那么难。