在我为朋友的业务编写的程序中,我正在使用 reportlab 模块为各种报告构建 PDF 文档。在大多数情况下,报告可以包含在一个页面上,但在极少数情况下它可能跨越两个页面。在那些罕见的情况下,我想做的是用更小的顶部和底部边距重新格式化页面,看看我是否可以让它适合单个页面。如果没有,我将只使用最小的边距并让它跨越两页。
为了构建报告,我正在创建SimpleDocTemplate
该类的一个实例。在将我所有的 flowables 传递给该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))
然而,走这条路感觉像是很多不必要的工作。我宁愿只更改文档边距并告诉文档使用这些新值重建自身,但我不知道如何。这甚至可能吗?