Python PDF Compress

需求

  • 一个PDF预览功能,由于前端预览太大的PDF时加载过慢,想要后端做PDF压缩。
  • 对比后基于fitz,将PDF中的每页转换成图片

性能对比

  • 源 PDF (Size: 27.9 MB | 3[图片页数] / 8[总页数] )
方法压缩比例处理速度依赖项缺点
PyPDF227.6MB (1%)0.029s压缩比例低
fitz7.40MB (27.6%)2.9s
Ghostscript16MB (27.3%)5.645sGhostscript需要另裝工具
且需要命令行執行
aspose.pdf13.5 MB (27.4%)14.657s有水印
Spire.PDF6.24 MB (27.8%)15.17s有水印

实例代码

PyPDF2
import time
from PyPDF2 import PdfReader, PdfWriter


def compress_pdf_pypdf2(input_path, output_path):
    reader = PdfReader(input_path)
    writer = PdfWriter()
    for page in reader.pages:
        writer.add_page(page)
    # 启用内容流压缩(无损)
    writer.compress_content_streams = True
    with open(output_path, "wb") as f:
        writer.write(f)


if __name__ == "__main__":
    start = time.time()
    compress_pdf_pypdf2("input.pdf", "output_pypdf2.pdf")
    print(time.time() - start)
aspose.pdf
  • 缺点:商用 - 左上角的水印去不掉
# -*- coding: utf-8 -*-
import time
import aspose.pdf as ap


def Lossless_Compression(path1, path2):
    """
    :param path1: 需要压缩的pdf文件路径
    :param path2: 保存的pdf文件路径
    :return: None
    """
    compress_path = ap.Document(path1)  # 需要压缩的pdf文件路径
    optimize = ap.optimization.OptimizationOptions()
    optimize.image_compression_options.compress_images = True
    optimize.image_compression_options.image_quality = 90  # 压缩质量
    compress_path.optimize_resources(optimize)
    compress_path.save(path2)  # 需要压缩后保存的文件路径


if __name__ == "__main__":
    start = time.time()
    Lossless_Compression("input.pdf", "output_aspose.pdf")
    print(time.time() - start)

aspose.pdf
  • 缺点:商用 - 左上角的水印去不掉
import time
from spire.pdf import *


def compress_pdf(input_pdf, output_pdf):
    # 创建 PdfCompressor 对象,并设置压缩选项(设置图片质量、启用图片大小调整和压缩)
    compressor = PdfCompressor(input_pdf)
    compression_options = compressor.OptimizationOptions
    compression_options.SetImageQuality(ImageQuality.Medium)
    compression_options.SetResizeImages(True)
    compression_options.SetIsCompressImage(True)

    # 压缩 PDF 文件并保存到输出文件夹
    compressor.CompressToFile(output_pdf)


if __name__ == "__main__":
    start = time.time()
    compress_pdf("input.pdf", "output_spire.pdf")
    print(time.time() - start)

Ghostscript
  • 调用外部工具,压缩比例高,支持多种优化算法。
  • 依赖系统安装的Ghostscript,适合对压缩率要求高的场景。
#!/bin/bash

# Compression levels:
#     0: default - almost identical to /screen, 72 dpi images
#     1: prepress - high quality, color preserving, 300 dpi imgs
#     2: printer - high quality, 300 dpi images
#     3: ebook - low quality, 150 dpi images
#     4: screen - screen-view-only quality, 72 dpi images

gs -sDEVICE=pdfwrite \
-dCompatibilityLevel=1.5 \
-dNOPAUSE \
-dQUIET \
-dBATCH \
-sOutputFile=compressed.pdf input.pdf
fitz
import time
import fitz

def auto_dpi(page):
    rect = page.rect
    return max(72, int(300 * (rect.width / 800)))


def compress_pdf(path1, path2, dpi):
    """
    压缩PDF函数(无需中间图片文件)
    :param path1: 原始PDF路径
    :param path2: 输出PDF路径
    :param dpi: 输出分辨率(值越小文件越小,但越模糊)
    """
    # 打开原始PDF
    src_doc = fitz.open(path1)
    # 创建新PDF对象
    dst_doc = fitz.open()

    for page in src_doc:
        # dpi = auto_dpi(page)
        # 生成图片矩阵
        matrix = fitz.Matrix(dpi / 100.0, dpi / 100.0)
        # 获取页面像素图(关闭alpha通道)
        pix = page.get_pixmap(matrix=matrix, alpha=False)

        if page.get_text("text"):
            img_bytes = pix.tobytes(output="png")
        else:
            img_bytes = pix.tobytes(output="jpeg", jpg_quality=85)
        # # 将像素图转为JPEG字节流(内存操作)
        # img_bytes = pix.tobytes(output="jpeg", jpg_quality=90)

        # 从内存字节流创建图片PDF
        imgdoc = fitz.open("jpeg", img_bytes)
        pdfbytes = imgdoc.convert_to_pdf()
        imgdoc.close()

        # 将单页PDF插入目标文档
        pdfpage = fitz.open("pdf", pdfbytes)
        dst_doc.insert_pdf(pdfpage)
        pdfpage.close()

    # 保存并关闭文档
    if dst_doc.page_count > 0:
        dst_doc.save(path2, deflate=True, garbage=3)  # 启用压缩
    dst_doc.close()
    src_doc.close()


if __name__ == "__main__":
    start = time.time()
    zoom = 300  # 缩放比率
    compress_pdf("input.pdf", "output_fitz.pdf", zoom)
    print(time.time() - start)

### 使用Python实现PDF文件压缩 #### 方法一:基于PyMuPDF的图像处理方式 通过将PDF文档转换成一系列图像,再按照指定比例缩放这些图像并重新组合为新的PDF文件来达到压缩效果。这种方法适用于那些主要由图形组成的PDF文档。 ```python import fitz # PyMuPDF def compress_pdf_by_image(pdf_path, output_path, zoom=1.5): doc = fitz.open(pdf_path) # 打开PDF文件 for page_num in range(len(doc)): page = doc.load_page(page_num) pix = page.get_pixmap(matrix=fitz.Matrix(zoom, zoom)) img_name = f"page_{page_num}.png" pix.save(img_name) new_doc = fitz.open() for i in range(len(doc)): img_file = f"page_{i}.png" imgdoc = fitz.open(img_file) pdfbytes = imgdoc.convert_to_pdf() imgpdf = fitz.open("pdf", pdfbytes) new_doc.insert_pdf(imgpdf) new_doc.save(output_path) ``` 此方法利用了`fitz.Matrix()`函数调整分辨率从而改变图片尺寸[^1]。 #### 方法二:Aspose.PDF优化资源选项 另一种更高效的方式是直接操作PDF内部结构而不必经过中间格式转化的过程。这可以通过设置特定参数控制诸如嵌入字体子集化、去除冗余对象以及降低图片质量等措施完成压缩工作。 ```python from aspose.pdf import Document from aspose.pdf.optimization import OptimizationOptions compressPdfDocument = Document("example.pdf") options = OptimizationOptions() image_opt = options.image_compression_options image_opt.compress_images = True image_opt.image_quality = 75 # 调整数值可更改最终输出的质量与体积平衡 compressPdfDocument.optimize_resources(options) compressPdfDocument.save("compressed_example.pdf") ``` 上述代码片段展示了如何配置`OptimizationOptions`类中的属性以满足不同的需求场景下的压缩策略[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值