如何拆分每张纸上包含多个逻辑页面的PDF文档?

1 投票
1 回答
704 浏览
提问于 2025-04-17 15:14

我想把一个2x2的PDF文档拆分成它原来的页面。每一页实际上包含四个逻辑页面,排列方式就像这个例子一样。

我正在尝试使用pythonpypdf

import copy, sys
from pyPdf import PdfFileWriter, PdfFileReader

def ifel(condition, trueVal, falseVal):
    if condition:
        return trueVal
    else:
        return falseVal

input  = PdfFileReader(file(sys.argv[1], "rb"))
output = PdfFileWriter()

for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
    (w, h) = p.mediaBox.upperRight

    for j in range(0,4):
        t = copy.copy(p)        
        t.mediaBox.lowerLeft  = (ifel(j%2==1, w/2, 0), ifel(j<2, h/2, 0))
        t.mediaBox.upperRight = (ifel(j%2==0, w/2, w), ifel(j>1, h/2, h))
        output.addPage(t)

output.write(file("out.pdf", "wb"))

可惜的是,这段代码没有按预期工作,因为它每隔四个逻辑页面就输出四次。由于我之前没有写过任何Python代码,我觉得这应该是个很基础的问题,可能是因为复制操作出了问题。我非常希望能得到一些帮助。


编辑:好吧,我做了一些实验。我手动插入了页面的宽度和高度,像下面这样:

import copy, sys
from pyPdf import PdfFileWriter, PdfFileReader

def ifel(condition, trueVal, falseVal):
    if condition:
        return trueVal
    else:
        return falseVal

input  = PdfFileReader(file(sys.argv[1], "rb"))
output = PdfFileWriter()

for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
    (w, h) = p.mediaBox.upperRight

    for j in range(0,4):
        t = copy.copy(p)        
        t.mediaBox.lowerLeft  = (ifel(j%2==1, 841/2, 0),   ifel(j<2, 595/2, 0))
        t.mediaBox.upperRight = (ifel(j%2==0, 841/2, 841), ifel(j>1, 595/2, 595))
        output.addPage(t)

output.write(file("out.pdf", "wb"))

这段代码的结果和我最初的代码一样错误但是如果我把那行(w, h) = p.mediaBox.upperRight注释掉,所有的东西就都正常了!我找不到任何原因。这个元组(w, h)甚至都没有再被使用,那为什么去掉它的定义会改变结果呢?

1 个回答

0

我怀疑问题出在mediaBox这个东西上,它只是一个神奇的访问器,用来访问一个在p和所有t的副本之间共享的变量。因此,当你给t.mediaBox赋值时,所有四个副本的mediaBox都会有相同的坐标。

mediaBox字段背后的变量是在第一次访问mediaBox时才创建的,所以如果你把这一行(w, h) = p.mediaBox.upperRight注释掉,mediaBox变量就会为每个t单独创建。

有两种可能的解决方案来自动确定页面的尺寸:

  1. 在复制之后获取尺寸:

    for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
    
        for j in range(0,4):
            t = copy.copy(p)       
            (w, h) = t.mediaBox.upperRight
            t.mediaBox.lowerLeft  = (ifel(j%2==1, w/2, 0),   ifel(j<2, h/2, 0))
            t.mediaBox.upperRight = (ifel(j%2==0, w/2, w), ifel(j>1, h/2, h))
            output.addPage(t)  
    
  2. 创建新的RectangleObjects来使用mediaBox变量

    for p in [input.getPage(i) for i in range(0,input.getNumPages())]:
        (w, h) = p.mediaBox.upperRight
    
        for j in range(0,4):
            t = copy.copy(p)        
            t.mediaBox.lowerLeft  = pyPdf.generic.RectangleObject(
                                        ifel(j%2==1, w/2, 0),   
                                        ifel(j<2, h/2, 0),
                                        ifel(j%2==0, w/2, w), 
                                        ifel(j>1, h/2, h))
            output.addPage(t)
    

使用copy.deepcopy()会导致处理大型复杂PDF时出现内存问题。

撰写回答