ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PyMuPDF PDF 文件压缩实战:深入解析 save() 压缩参数与最佳实践

PyMuPDF PDF 文件压缩实战:深入解析 save() 压缩参数与最佳实践 图像处理【免费下载链接】PyMuPDFPyMuPDF is a high performance Python library for data extraction, analysis, conversion manipulation of PDF (and other) documents.项目地址https://gitcode.com/gh_mirrors/py/PyMuPDF点击查看免费下载PyMuPDF 通过Document.save()提供了一整套细粒度的 PDF 体积压缩选项从打包对象流use_objstms、流数据压缩deflate、压缩力度调节compression_effort到垃圾对象清理garbage可以按文档类型组合出显著的文件瘦身效果。本文以官方 cookbook 中 1.8 MB 的mupdf_explored示例 PDF 为对照样本逐项讲解每个参数的取值含义、底层实现原理与实测效果并给出可复制的批量基准测试脚本帮助你在交付前选择压缩比 / CPU 开销的最优平衡点。PyMuPDF 与压缩总体思路PDF 文件之所以臃肿通常来自三个方面未被压缩的对象定义、未被压缩的内容流文本与矢量图形、以及大量不再被引用的垃圾对象。PyMuPDF 的Document.save()恰恰针对这三类问题分别提供了开关你可以独立或组合使用对象定义层用use_objstms把散落的对象定义打包进可压缩的对象流ObjStm流数据层用deflate对未压缩的流内容流、字体程序等执行 Flate 或 Brotli 压缩结构清理层用garbage删除未引用对象、压缩 xref 表、合并重复对象与重复流。从源码看Document.save()的完整签名 默认值如下garbage0、deflate0、deflate_images0、deflate_fonts0、use_objstms0、compression_effort0。也就是说不做任何设置时 save() 只做最基本的重写不做压缩优化——这正是你需要主动配置这些参数的原因。这些参数最终被逐一写入 MuPDF 的PdfWriteOptions见 save() 中 opts 赋值段opts.do_compress deflate、opts.do_use_objstms use_objstms、opts.compression_effort compression_effort、opts.do_garbage garbage随后交给mupdf.pdf_save_document()完成实际写入。理解这一调用链有助于把握参数间的职责边界每个参数只影响写入管线中的一个环节。use_objstms把对象定义打包进可压缩流use_objstms是布尔选项源码层面实际接受 0/1 整数作用是把 PDF 中大量对象如页面、字体描述、注释字典等的定义打包进专门的对象流/Type/ObjStm中使其整体可以被流压缩机制处理从而减少冗余与体积。import pymupdf doc pymupdf.open(mupdf_explored.pdf) doc.save( output.pdf, use_objstmsTrue, # pack object definitions into compressible streams ) doc.close()仅此一项示例文件从1.8 MB 降到 1.5 MB。仓库测试 tests/test_objectstreams.py 从实现层面对该行为做了验证test_objectstream1用use_objstmsTrue保存后遍历 xref断言能找到/Type/ObjStm类型的对象test_objectstream2用use_objstmsFalse保存后则断言找不到任何对象流证实该参数确实决定对象流是否生成。注意一个约束save()中linear线性化/快速 Web 查看与use_objstms互斥同时请求会抛出ValueError(linear and use_objstms cannot both be requested)见 save() 校验逻辑。deflate压缩未压缩的流use_objstms解决了对象定义的打包问题但 PDF 中还有大量未压缩的流数据内容流、字体程序、图像流等。deflate参数专门负责这一层。取值含义如下取值含义0不压缩默认值1使用标准 Flate 压缩Deflate 算法2使用 Brotli 压缩最慢、输出最小但属实验特性许多工具与阅读器不支持deflate与use_objstms组合使用效果最佳——先把对象定义收进可压缩的对象流再对流执行压缩。Flatedeflate1import pymupdf doc pymupdf.open(mupdf_explored.pdf) doc.save( output.pdf, use_objstmsTrue, # pack object definitions into compressible streams deflate1, # compress uncompressed streams with Flate compression ) doc.close()结果903 KB。Flate 是 PDF 生态中最通用、兼容性最好的压缩方式几乎所有阅读器都支持。Brotlideflate2import pymupdf doc pymupdf.open(mupdf_explored.pdf) doc.save( output.pdf, use_objstmsTrue, # pack object definitions into compressible streams deflate2, # compress uncompressed streams with Brotli compression ) doc.close()结果863 KB比 Flate 又省约 40 KB。Brotli 在文本密集和矢量图形密集的文档上预期能带来明显收益而对扫描件或照片密集的文档几乎无差别因为图像流本身已是压缩格式。兼容性警告Brotli 目前是实验特性许多工具与阅读器尚不支持。若压缩后的文件在你的阅读器中无法打开官方建议尝试 MuPDF 自带的MUPDF GL查看器若仍存在问题可在 PyMuPDF 的 issue 跟踪器中反馈。捷径ez_save()如果你不关心微调只想一键获得接近最优的压缩效果Document.ez_save()会自动应用合适的参数组合doc.ez_save(output.pdf)从源码看ez_save()的默认值 与save()显著不同garbage3、deflateTrue、deflate_imagesTrue、deflate_fontsTrue、use_objstms1即默认就启用对象流 压缩 垃圾清理。它内部只是把这些默认值转发给save()见 ez_save() 的实现。所以对mupdf_explored.pdf而言doc.ez_save(output.pdf)与上面use_objstmsTrue, deflate1得到相同结果。测试 tests/test_objectstreams.py 中的 test_objectstream3 也验证了ez_save()会自动生成对象流。compression_effort用 CPU 时间换体积compression_effort在deflate2Brotli时用于控制 MuPDF 压缩流数据时的努力程度。它的核心特性是只影响压缩率与耗时绝不改变文档的视觉呈现。import pymupdf doc pymupdf.open(mupdf_explored.pdf) doc.save( output.pdf, use_objstmsTrue, # pack object definitions into compressible streams deflate2, # compress uncompressed streams with Brotli compression compression_effort100, # ask Brotli to work hard at it ) doc.close()结果进一步降到834 KB。取值含义与最常见的坑compression_effort是int 而非 bool取值含义0零投入默认值1最小投入——最快、输出最大100最大投入——最慢、输出最小最常见的错误是误传布尔值# WRONG — True 1 minimum effort doc.save(out.pdf, use_objstmsTrue, deflate2, compression_effortTrue) # CORRECT - maximum effort defined doc.save(out.pdf, use_objstmsTrue, deflate2, compression_effort100)由于 Python 中True等于整数1传布尔值会静默地选中 effort1最小投入不产生任何警告文件只会比你预期的更大。Artifex 官方对应mutool clean的-e参数给出了经验性的投入档位参考40—— 约等于默认 Flate 压缩的速度75—— 约等于最大 Flate 压缩的速度100—— 榨出所有可压缩空间但运行时间明显变长。这些数值是在 Brotli 压缩的语境下给出的具体数字仅作参考。compression_effort 影响什么、不影响什么它调节的是写文件时应用到流对象上的压缩器强度它不决定是否用 Brotli 压缩流那是deflate2的职责也不负责重新打包对象定义那是use_objstmsTrue的职责。调优compression_effort之前请务必确认deflate2与use_objstmsTrue已正确设置。有效果的对象内容流文本与矢量图形字体程序及其他未压缩的二进制流use_objstmsTrue产生的对象流。效果甚微的对象已以压缩格式存储的图像JPEG、JPEG2000、JBIG2。对它们再次运行通用压缩器毫无收益请改用Document.rewrite_images()处理主体为未引用对象的文档。这类文档应使用garbage3或garbage4。garbage清理未引用对象文档在多次编辑、插入、删除后常常残留未引用对象。garbage参数逐级加强清理力度取值含义0不清理默认1删除未使用未引用的对象2在 1 的基础上压缩 xref 表3在 2 的基础上合并重复对象4在 3 的基础上检查流对象是否重复。该步骤可能较慢因为流数据通常很大能省多少完全取决于文档里有多少垃圾。例如对mupdf_explored.pdf这类本就比较干净的文档garbage4只额外省下几 KBimport pymupdf doc pymupdf.open(mupdf_explored.pdf) doc.save( output.pdf, use_objstmsTrue, # pack object definitions into compressible streams deflate2, # compress uncompressed streams with Brotli compression compression_effort100, # ask Brotli to work hard at it garbage4 # drop unreferenced objects, compact xref table, merge duplicate objects, check streams for duplication ) doc.close()最终体积831 KB。值得注意的是garbage并不只是锦上添花对于反复增删页面或合并文档产生大量残留对象的文件它往往是收益最大的单一步骤。PyMuPDF 自带的命令行工具src/main.py 中的 doc_join在合并 PDF 后保存时就固定使用garbage4, deflateTrue可见这是官方认可的基础清理组合。结果汇总1.8 MB 到 831 KB 的逐步压缩描述文件大小备注原始文件1.8 MBuse_objstmsTrue1.5 MBuse_objstmsTrue,deflate1903 KBuse_objstmsTrue,deflate2863 KB警告Brotli 属实验特性许多工具与阅读器不支持use_objstmsTrue,deflate2,compression_effort100834 KB警告同上use_objstmsTrue,deflate2,compression_effort100,garbage4831 KB警告同上可以看到对这份以文本/矢量为主的文档从 1.8 MB 压缩到 831 KB总体缩减约 54%。其中对象流 流压缩是决定性组合1.8 MB → 903 KB而compression_effort与garbage属于边际优化。如果你的文档以扫描图像为主收益分布会完全不同——此时应优先考虑rewrite_images()。实战批量压缩前的基准测试收益高度依赖语料corpus。在批量任务中为压缩率付出 CPU 代价之前先对代表性样本做一次测量import pathlib import time import pymupdf src input.pdf for effort in (0, 40, 75, 100): doc pymupdf.open(src) out fout_{effort}.pdf start time.perf_counter() doc.save(out, garbage4, deflate1, use_objstmsTrue, compression_efforteffort) elapsed time.perf_counter() - start doc.close() size pathlib.Path(out).stat().st_size print(feffort{effort:3} {size/1e6:6.2f} MB {elapsed:5.2f}s)该脚本在deflate1Flate基础上遍历 effort 0/40/75/100输出每个档位的体积与耗时帮你确定投入产出比最好的档位。如需评估 Brotli将deflate1改为deflate2即可。组合拳其他压缩手段save()的参数之外PyMuPDF 还提供两个与文件瘦身直接相关的独立方法适合与上述参数配合使用Document.rewrite_images()重新编码文档中的图像默认尽可能转为 JPEG通过dpi_threshold/dpi_target控制分辨率、quality控制质量、bitonal/color/gray控制处理的图像类别。对扫描件和照片密集的文档这是比流压缩更有效的瘦身手段正好补上compression_effort的盲区。Document.subset_fonts()为 PDF 构建字体子集用只含实际使用字符的较小字体替换嵌入字体默认使用 MuPDF 内部实现出错时可回退到依赖 fontTools 的旧实现。对嵌入大量中文字体的文档子集化收益非常可观。一个典型的生产流水线是先rewrite_images()处理图像再subset_fonts()精简字体最后用save(garbage4, deflate1, use_objstmsTrue, compression_effort...)完成写入追求一键简化时直接ez_save()即可获得 90% 的收益。延伸阅读Document.save()本文所有参数的完整签名与默认值Document.ez_save()一键压缩的推荐默认组合Document.rewrite_images()图像重压缩入口Document.subset_fonts()字体子集化入口tests/test_objectstreams.py对象流参数的行为验证测试src/main.py 的 doc_join命令行工具中的garbage4, deflateTrue组合实践赞分享图像处理【免费下载链接】PyMuPDFPyMuPDF is a high performance Python library for data extraction, analysis, conversion manipulation of PDF (and other) documents.项目地址https://gitcode.com/gh_mirrors/py/PyMuPDF点击查看免费下载相关推荐TBOOX/TBOX压缩模块详解ZIP、GZIP压缩解压最佳实践TBOOX/TBOX压缩模块详解ZIP、GZIP压缩解压最佳实践 你是否还在为C语言项目中复杂的压缩解压功能而头疼是否希望找到一个轻量级、跨平台、易集成的压后端压缩 Rust 二进制文件UPX 最佳参数与实测效果压缩 Rust 二进制文件UPX 最佳参数与实测效果 你是否曾为 Rust 编译出的二进制文件体积过大而困扰明明只是个简单工具却动辄几 MB 甚至几十 M示例工程autocannon请求压缩最佳实践平衡压缩率与CPU消耗autocannon请求压缩最佳实践平衡压缩率与CPU消耗 为什么需要请求压缩 在Web性能测试中请求压缩是一把双刃剑。启用压缩可以显著减少网络传输量提性能测试测试开发工具上一篇rapidjson NPM兼容Node.js包管理的兼容性下一篇Swift Composable Architecture文档生成自动化API文档和示例创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表