如何用PyMuPDF实现PDF压缩的质量、体积与速度最优平衡?
使用PyMuPDF压缩PDF:平衡质量、体积与速度的优化思路
问题背景
我目前用PyMuPDF实现了PDF压缩,但压缩后体积几乎没变化,想知道怎么调整方法,在质量、文件体积和处理速度之间拿到最优平衡。我的现有实现代码如下:
import fitz #Installed via PyMuPDF. PyCharm sometimes doesn't recognize this import, however code still runs. # https://pymupdf.readthedocs.io/en/latest/the-basics.html#extract-text-from-a-pdf def compress_pdf(input_pdf_path, output_pdf_path, colorspace=fitz.csRGB, garbage=3, dpi=72): # Working, however size is about the same. """Compresses a PDF file using PyMuPDF (AKA fitz). Args: input_pdf_path: The path to the input PDF file. output_pdf_path: The path to the output PDF file. https://pymupdf.readthedocs.io/en/latest/page.html#Page.get_pixmap colorspace: fitz.csRGB fitz.csGRAY fitz.csCMYK https://pymupdf.readthedocs.io/en/latest/document.html#Document.save garbage: 0 = none 1 = remove unused (unreferenced) objects. 2 = in addition to 1, compact the xref table. 3 = in addition to 2, merge duplicate objects. 4 = in addition to 3, check stream objects for duplication. This may be slow. """ # Open the input PDF file. doc = fitz.Document(input_pdf_path) doc_new = fitz.Document() for page in doc: pixmap = page.get_pixmap(colorspace=colorspace, dpi=dpi, annots=False) new_page = doc_new.new_page(-1) xref = new_page.insert_image(rect=new_page.bound(), pixmap=pixmap) doc_new.save(output_pdf_path, garbage=garbage, deflate=True, deflate_images=True, deflate_fonts=True, pretty=True) doc.close() doc_new.close()
我也曾尝试使用Ghostscript,虽能实现压缩,但速度较慢,且无法完全关闭其运行窗口。
优化思路与方案
1. 先改掉核心问题:避免将矢量PDF转为位图
你当前的代码逻辑是把每页转成Pixmap再插入新文档,这相当于把原本的矢量PDF转成了位图——不仅不会压缩(甚至可能增大体积),还会丢失矢量清晰度,完全没必要。优先放弃这个思路,直接针对原PDF对象做优化。
2. 直接优化原文档,高效压缩非图片资源
PyMuPDF支持直接对原文档的冗余对象、流数据做压缩,速度快且保留矢量信息,这是最基础的平衡方案:
import fitz def compress_pdf_direct(input_pdf_path, output_pdf_path, garbage=3): doc = fitz.Document(input_pdf_path) # 启用核心压缩选项 doc.save( output_pdf_path, garbage=garbage, # garbage=3足够平衡速度与体积,garbage=4会大幅变慢 deflate=True, # 对所有可压缩流启用Deflate压缩 deflate_images=True, # 单独压缩图片流 deflate_fonts=True, # 压缩嵌入字体流(对含大量字体的文档效果明显) clean=True # 清理文档冗余资源 ) doc.close()
3. 针对位图图片的精细化压缩(如果文档含大量图片)
如果原PDF本身有很多位图图片,单独对图片做压缩能大幅减小体积,同时可控质量:
import fitz def compress_pdf_with_image_opt(input_pdf_path, output_pdf_path, image_quality=80, target_dpi=72, garbage=3): doc = fitz.Document(input_pdf_path) for page in doc: # 获取页面所有图片的完整信息 image_list = page.get_images(full=True) for img in image_list: xref = img[0] pix = fitz.Pixmap(doc, xref) # 仅处理RGB/灰度图片,避免破坏矢量或CMYK内容 if pix.colorspace in (fitz.csRGB, fitz.csGRAY): # 调整dpi(按需设置,72适合屏幕,打印建议150+) pix.set_dpi(target_dpi, target_dpi) # 临时保存为压缩后的JPG,quality范围0-100,值越小体积越小 pix.save("temp_compressed.jpg", quality=image_quality) # 替换原文档中的图片 doc.update_image(xref, filename="temp_compressed.jpg") pix = None # 及时释放资源 # 最后保存优化后的文档 doc.save( output_pdf_path, garbage=garbage, deflate=True, deflate_images=True, deflate_fonts=True ) doc.close()
4. 按需调整颜色空间
- 如果文档是黑白内容,将颜色空间转为
fitz.csGRAY,能显著减小体积,但会丢失彩色信息,仅适合非彩色文档。 - 不要盲目转换,先确认文档内容是否允许损失彩色。
关于Ghostscript的补充
你遇到的窗口无法关闭、速度慢问题,可以通过命令行参数和调用方式解决:
- 命令行添加
-dBATCH -dNOPAUSE -sDEVICE=pdfwrite -dQUIET参数; - 用
subprocess调用时,Windows下设置creationflags=subprocess.CREATE_NO_WINDOW,跨平台设置stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,即可隐藏窗口。不过Ghostscript确实比PyMuPDF慢,仅适合对体积要求极高的场景。
内容的提问来源于stack exchange,提问作者Greg Harward
相关产品推荐
相关产品推荐

