减小 PDF 文件大小¶
有多种方法可以减小给定 PDF 文件的大小。最简单的一种方法是删除内容(例如图像)或页面。
删除重复内容¶
有些 PDF 文档可能多次包含相同的对象。例如,如果一张图片在 PDF 中出现了三次,它可能被嵌入了三次。或者,它可能只嵌入一次,并被引用两次。
当向 PdfWriter 添加数据时,数据会被复制,同时保持原始格式。例如,如果两页包含相同的图像,而该图像在源文档中是重复的,则该对象将在 PdfWriter 对象中重复。
此外,当你删除文档中的对象时,pypdf 无法轻松识别这些对象是否在其他地方使用,或者用户是否希望保留它们。当写入 PDF 文件时,这些对象将隐藏在文件中(文件的一部分,但不显示)。
为了减小文件大小,可以使用压缩调用:writer.compress_identical_objects(remove_identicals=True, remove_orphans=True)
remove_identicals
启用/禁用压缩合并相同的对象。remove_orphans
启用/禁用抑制未使用的对象。
建议在写入文件/流之前应用此过程。
这取决于 PDF 文件的具体情况,但我们已经看到在一个真实的 PDF 文件中,通过此方法文件大小减少了 86%(从 5.7 MB 降到 0.8 MB)。
删除图像¶
from pypdf import PdfWriter
writer = PdfWriter(clone_from="example.pdf")
writer.remove_images()
with open("out.pdf", "wb") as f:
writer.write(f)
降低图像质量¶
如果我们降低 PDF 中图像的质量,有时可以减少整个 PDF 文件的大小。这取决于降低质量的图像能压缩到什么程度。
from pypdf import PdfWriter
writer = PdfWriter(clone_from="example.pdf")
for page in writer.pages:
for img in page.images:
img.replace(img.image, quality=80)
with open("out.pdf", "wb") as f:
writer.write(f)
无损压缩¶
pypdf 支持 FlateDecode 过滤器,使用 zlib/deflate 压缩方法。它是一种无损压缩,这意味着生成的 PDF 看起来完全一样。
可以通过 {meth}
page.compress_content_streams <pypdf._page.PageObject.compress_content_streams>` 对页面应用 Deflate 压缩:
from pypdf import PdfWriter
writer = PdfWriter(clone_from="example.pdf")
for page in writer.pages:
page.compress_content_streams() # 这会消耗 CPU!
with open("out.pdf", "wb") as f:
writer.write(f)
page.compress_content_streams
使用 zlib.compress
并支持 level
参数:level=0
表示不压缩,level=9
表示最高压缩。
使用此方法,我们已经看到一个实际 PDF 文件的大小减少了 70%(从 11.8 MB 降到 3.5 MB)。
删除源¶
当从页面列表中删除一页时,其内容仍然存在于 PDF 文件中。这意味着该数据可能仍然在其他地方被使用。
仅仅从页面列表中删除页面会减少页面数量,但不会减少文件大小。为了完全排除内容,应该避免通过 PdfWriter.append()
函数添加这些页面。相反,应该只选择需要包含的页面(注意:PR #1843 将添加页面删除功能)。
在某些情况下,可能会遇到 PDF 格式不佳的问题,例如所有页面都链接到同一个资源。在这种情况下,删除对特定页面的引用变得没有意义,因为所有页面只有一个源。
裁剪是一个无效的减小文件大小的方法,因为它仅调整查看框,而不调整源图像的外部部分。因此,已不再显示的内容仍会存在于 PDF 文件中。
进一步优化¶
演示文稿 Putting a Squeeze on Your PDF 提供了其他优化建议。一个关键点是,大多数显著的大小优化通常来自图像和字体的修改。然而,字体优化(如替换、合并和子集化)目前不在 pypdf 的功能范围内。