You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 23:31:03