PyPDF2压缩

7 投票
4 回答
21464 浏览
提问于 2025-04-18 00:46

我在用PyPDF2模块压缩合并后的PDF文件时遇到了一些困难。这是我根据这个链接尝试的代码。

import PyPDF2
path = open('path/to/hello.pdf', 'rb')
path2 = open('path/to/another.pdf', 'rb')
merger = PyPDF2.PdfFileMerger()
merger.append(fileobj=path2)
merger.append(fileobj=path)
pdf.filters.compress(merger)
merger.write(open("test_out2.pdf", 'wb'))

我收到的错误信息是:

TypeError: must be string or read-only buffer, not file

我也尝试在合并完成后再压缩PDF。我是根据使用PDFSAM压缩后得到的文件大小来判断我的压缩失败的。有什么想法吗?谢谢。

4 个回答

0

pypdf 提供了几种方法来减小文件大小:https://pypdf.readthedocs.io/en/latest/user/file-size.html

compress_content_streams 是其中一种方法,它的缺点是可能需要较长时间(这取决于PDF文件的大小;可以把它想象成是PDF版的ZIP压缩):

from pypdf import PdfReader, PdfWriter

reader = PdfReader("example.pdf")
writer = PdfWriter()

for page in reader.pages:
    page.compress_content_streams()  # This is CPU intensive!
    writer.add_page(page)

with open("out.pdf", "wb") as f:
    writer.write(f)
0

最开始的方法其实没那么错。只需要在写入文件之前,把页面添加到你的写入器中,并进行压缩就可以了:

...

for i in list(range(reader.numPages)):
    page = reader.getPage(i)
    writer.addPage(page);
for i in list(range(writer.getNumPages())):
    page.compressContentStreams()

...
0

你的错误提示说,必须是字符串或者只读的缓冲区,而不是文件。

所以最好把你的合并结果写成字节或者字符串。

import PyPDF2
from io import BytesIO

tmp = BytesIO()
path = open('path/to/hello.pdf', 'rb')
path2 = open('path/to/another.pdf', 'rb')
merger = PyPDF2.PdfFileMerger()
merger.append(fileobj=path2)
merger.append(fileobj=path)
merger.write(tmp)
PyPDF2.filters.compress(tmp.getvalue())
merger.write(open("test_out2.pdf", 'wb'))
8

PyPDF2这个工具没有一个可靠的压缩方法。不过,它有一个叫做 compress_content_streams() 的功能,描述如下:

这个功能可以通过将所有内容流合并并应用FlateDecode过滤器来压缩页面的大小。

不过,有可能这个功能在某些情况下不会起作用,比如内容流的压缩变成了“自动”的。

总的来说,这在大多数情况下不会有什么改变,但你可以试试这个代码:

from PyPDF2 import PdfReader, PdfWriter


writer = PdfWriter()

for pdf in ["path/to/hello.pdf", "path/to/another.pdf"]:
    reader = PdfReader(pdf)
    for page in reader.pages:
        page.compress_content_streams()
        writer.add_page(page)

with open("test_out2.pdf", "wb") as f:
    writer.write(f)

撰写回答