技术资料里的图片怎么压缩:体积、文字和动画的取舍
整理一批离线技术资料时,正文已经是 Markdown,图片也下载到了本地。接着盘点体积,38,461 个独立图片文件一共占了 11.82 GB。
这些资料要跨设备保存,图片就成了比正文更重的负担。最省事的设想,是把它们统一转成一种格式,再降画质、缩尺寸。如果能压到原来的 1/20,就只剩约 591 MB。
我需要保住的是图里的技术信息。照片少一点纹理,通常还能看;代码截图少一个小数点、公式下标糊成一团,资料的意思就可能变了。压缩率再好,也补不回读者无法辨认的内容。
我先做了一轮抽样比较。结果比预想的更分散:有些图无损编码就能缩小一半,有些原本已经压得很好,换格式反而更大;最激进的方案确实能把长截图压到十几 KB,但中文字也已经读不清了。
先看图片里保存了什么
按实际文件格式统计,这批资料主要由 JPEG 和 PNG 构成:
| 格式 | 文件数 | 体积 |
|---|---|---|
| JPEG | 20,968 | 7.116 GB |
| PNG | 16,411 | 3.291 GB |
| GIF | 499 | 1.324 GB |
| WebP | 582 | 0.088 GB |
| SVG | 1 | 660 字节 |
这里的格式只是编码方式,不能直接当成内容分类。JPEG 里也有代码截图,PNG 里也有照片。真正影响选择的,是图里哪些细节必须留下。
公式、命令、表格和流程图经常依赖细笔画、上下标、小数点、箭头与颜色。照片和绘画更多依赖纹理、渐变和主体轮廓。动图还多了一条时间轴,不能只看某一帧清不清楚。
487 个文件是动图,共 1.323 GB。宽度超过 2400 的图有 6,229 张,共 4.372 GB。这两部分都值得检查,但不能由此推导出「动图抽几帧」「宽图统一缩小」的处理规则。
用样本比较,再估算整库
这轮测试先按实际格式、文件大小和宽高比分层,固定种子抽取 127 张静态图,再加入 6 张大文件做压力测试,另按大小分层抽取 12 个动图,总共 145 个样本。
大文件压力样本用于暴露问题,不参与整库容量外推。否则,专挑几张特别能压的大图,很容易得到过于乐观的数字。
编码使用 Sharp 0.35.5,本机底层是 libvips 8.18.7、libwebp 1.6.0 和 AOM 3.15.1。静态样本比较无损、近无损、不同画质的 WebP 和 AVIF,也比较限制宽度与限制最长边两种缩放方式。编码和检查都在本地完成,没有把资料上传给在线压缩服务。
「近无损」允许在编码前调整部分像素来改善压缩,因此不保证逐像素相同。它与后面提到的无损编码计算参数是不同的机制,见 libwebp 的参数说明。
整库估算按每层的样本输出/输入字节比,乘以这一层的实际总字节。变大、校验失败的候选按原图大小计算;未测试的大图、超大动图和特殊色彩文件也保留原大小,约有 1.42 GB 没有计算压缩收益。
| 方案 | 整库估计体积 | 预计节省 |
|---|---|---|
| 原尺寸像素无损 | 9.56 GB | 19.1% |
| 原尺寸 WebP 90 为主 | 5.48 GB | 53.7% |
| 原尺寸 WebP 82 为主 | 4.85 GB | 59.0% |
| 原尺寸 AVIF 75 为主 | 4.83 GB | 59.2% |
| AVIF 40,并限制最长边为 1600 | 2.81 GB | 76.2% |
表里的数字是样本外推,不是全库转换后的实测体积。各方案都允许回退原图;AVIF 方案还允许回退 WebP。有损方案的动图使用相同的 WebP 85/无损候选,无损方案只使用无损候选,不能理解为把整库强制转成表头中的一种编码。
对 WebP 90 方案做 500 次层内重采样,结果范围约为 4.58–6.68 GB。每层样本不多,这个范围只提醒我们估算有波动,不构成容量上限,更不能证明所有图片都可读。详细参数和汇总数据见测试口径弹窗。
保持尺寸,已经能省不少空间
比较中,一个很实用的发现是:不必先缩图,原尺寸编码就有明显收益。
一张 2552×870 的彩色日志截图,原文件 809.5 KiB,原尺寸 WebP 90 为 331.1 KiB。命令、颜色和标点仍需要放大对照,但至少没有先丢掉分辨率。
另一张 1920×1078 的流程图,原文件 104.6 KiB,无损 WebP 为 49.2 KiB,比 WebP 90 的 53.6 KiB 还小。一张终端命令截图也有类似结果,无损候选 23.6 KiB,有损候选反而是 33.9 KiB。
所以我没有把「有损」当成「一定更小」。候选通过验证后,还要和原文件、无损版本比较体积。有些图最合适的选择,就是保持原样。
样本里已有一张 89.1 KiB 的 WebP 表格,重新编码后,无损版本变成 89.2 KiB,90 档增至 153.2 KiB。它不需要再处理一次。文件换了后缀、工具成功退出,都不能说明完成了有效优化。
无损只表示对当前解码像素的保留。已经存在于 JPEG 里的模糊和压缩痕迹,不会因为转成无损 WebP 而恢复。
无损模式下,参数名也容易让人误会。libwebp 的说明区分了 -q 的两种作用:有损模式中影响画质与体积,无损模式中则影响编码速度与压缩程度。无损时把它从 100 调到 75,并不等于让图片只剩「75 分画质」。
我用 8 张图补测,两档都保持完整解码像素一致。75 档的输出总字节增加约 0.4%,本机累计编码耗时从约 14.5 秒降到 7.5 秒。这是小样本的速度取舍,不是全库固定提速保证;对上万张图片,它比不加区分地把所有参数调到最大更实用。
长截图不能照搬照片的缩放参数
这轮最明显的反例,是一张 1080×11520 的长截图。
原文件约 988.1 KiB。把最长边限制为 1600 后,输出变成 150×1600,只有 17.3 KiB。体积看起来非常漂亮,但宽度只剩原来的约七分之一,中文已经无法正常阅读。
问题出在缩放比例。长图的高度先触及上限,宽度也按相同比例缩小:1080 × 1600 ÷ 11520 = 150。
如果确实要限制长图尺寸,应该先确定需要保住多宽的文字,再考虑只限制宽度,并禁止放大。Sharp 的 resize 参数可以分别表达这两种意图:
// 限制宽高,按比例缩进 1600×1600;长图的宽度也可能大幅缩小。
image.resize({ width: 1600, height: 1600, fit: 'inside', withoutEnlargement: true });
// 只限制宽度。原图宽 1080,不放大时无需缩放。
image.resize({ width: 1600, withoutEnlargement: true });
这段是缩放选项的对照示例,不是完整批处理程序。对于文字截图,原尺寸仍是更稳妥的起点;只限制宽度,也不能代替阅读检查。
那张长截图原尺寸 WebP 90 还出现了增大,变成 1041.0 KiB。82 档缩到 783.8 KiB,但节省的空间是否值得再次有损编码,需要结合小字判断,不能看到「长图」就自动降低画质。
动图要比较完整时间轴
动图的帧数减少,并不必然意味着画面丢失。
一个终端演示 GIF 有 146 帧、14.6 秒,大小为 2,502,516 字节。无损 WebP 变成 72 帧,大小为 319,316 字节,节省 87.2%。完整时间轴检查显示,减少的是连续重复的源画面,时长、循环设置及对应时刻的画面都保持一致。
用一个 400 毫秒的简化样例就容易理解。前两个 100 毫秒显示相同画面,合成一个持续 200 毫秒的帧,播放内容没有变化:
检查时要沿两份动画的帧延迟划分时间区间,再比较对应区间的完整画面。无损候选要求像素一致,还要检查透明度、总时长和循环次数。只核对文件能打开、首帧相同,或者源帧数与输出帧数相等,都不够。
这轮也遇到了改变总时长、合并不同源画面的候选,它们都被保守地排除,保留原动画。不能把某一个 GIF 节省 87% 的结果,推广成所有动图的固定压缩率。
像素检查之外,还要看显示结果
解码得到的像素值相同,也不一定足以说明阅读器中的显示结果相同。色彩配置、透明度及解码和渲染过程,都可能影响最终画面。
ICC 配置描述像素值与颜色之间的对应关系,PNG 还可能独立携带明暗响应(gamma)、色度坐标等信息。格式转换时需要检查它们怎么处理,而不只是比较 RGB 缓冲。Sharp 的 keepMetadata()有明确的保留范围,但它不承诺原容器字节不变,也不能据此假定所有 PNG 文本信息都会随转换保留。
我对 133 张静态样本追加了 Chrome sRGB 画布检查。132 张无损候选的显示 RGBA 与原图完全相同,另 1 张出现了最大为 2 的通道差异。这点差异很轻微,但既然暂时没有定位到具体的解码或渲染原因,就没有把它归入「显示完全一致」,也没有直接认定是色彩配置丢失。
另一项限制来自阅读工具。当前本机 Chrome 能显示测试中的 AVIF,Codex 图片查看工具却返回不支持格式的错误;同一张图的 WebP 可以直接看。这个结果只说明当前工具链的兼容情况,不代表所有 Agent 或未来版本都不支持 AVIF。
这些资料既供人阅读,也供 Agent 参考。相比再省一点体积,我更在意常用阅读入口能直接打开,因此这次默认采用 WebP,保留 AVIF 的比较数据。
全量应用时,先保住可回退性
样本中的原尺寸 WebP 90 方案,是比较容量潜力的基线。实际批量应用采用更保守的规则:
- PNG、已有 WebP 和动图先尝试无损,静态无损候选还要通过浏览器显示像素检查。
- 普通 JPEG 尝试原尺寸 WebP 90;小文件、小尺寸图、较矮的图和宽高比超过 3 的图先尝试无损,避免给公式、命令行和长截图重复有损编码。
- 候选至少节省 3% 且不少于 4 KiB,才继续考虑替换;尺寸、透明度、ICC 和方向检查不通过时保留原图。
- 16 位图、超出解码预算的图片、超出 WebP 单边尺寸上限的图片,以及尚未验证的特殊色彩类型保留原件,不通过缩图绕过这些限制。
这是保守的格式与几何代理规则,不是文字识别器。JPEG 仍可能是截图,质量指标也不能保证每一个字符都没有受到影响,所以需要保留原件并抽样复核,不能把一套自动过滤说成逐图阅读验收。
有损候选还计算像素误差,低于质量门槛时不采用。这里使用的峰值信噪比(PSNR)由像素均方误差换算而来,分数较高通常表示平均误差较小,但它不能回答「负号还看不看得见」。对缩放候选来说,如果只与同尺寸参考图比较,高分甚至无法体现原分辨率已经丢失。
批处理因此拆成了两个阶段。先在暂存目录生成候选,记录输入指纹、参数、输出指纹和验证结果;完整一轮处理结束后,才更新正式媒体清单与正文引用。中途中断可以复用已验证的结果,恢复时仍要重新检查输入与候选是否匹配,不能只相信文件存在。
图片转成新的 WebP 后,文件名按新内容指纹生成。来源指纹与派生文件指纹分开保存,不能继续把有损产物记成原始下载文件。正文、可逆改写记录和媒体清单一起进入可恢复写入流程;旧下载日志也要识别已经批准的派生记录,避免续传时把旧路径写回来。
最后保留旧图片的本机备份。内容寻址会让新图片复用已有文件,因此还要检查最终引用:仍被其他条目使用的文件留在资料库,不能在备份旧图时直接移走。备份保留期间,正式资料库的使用体积会下降,但本机磁盘总占用不会按相同比例下降,还要算上原件和暂存文件。这是保留回退能力的真实成本,不应该从压缩报告里省略。
整库处理的实际结果
2026 年 10 月 26 日完成应用后,正式图片从 11.82 GB 降到了 6.95 GB,实际减少约 4.86 GB,41.2%。所有采用的候选都保持原尺寸。
| 项目 | 结果 |
|---|---|
| 压缩前输入文件 | 38,461 个 |
| 采用更小候选 | 29,300 个 |
| 保持原样 | 9,161 个 |
| 进一步内容去重后的正式文件 | 38,383 个 |
| 正式图片总字节数 | 6,954,690,959 |
文件变少来自派生内容去重,不是删除正文里的图片。16,261 个输入采用无损编码,其中 16,011 个静态文件通过完整像素与浏览器显示比较,250 个动图通过完整时间轴检查。另有 13,039 个 JPEG 采用原尺寸 WebP 90,最低 PSNR 为 40.00007,仍在设定门槛之上。
保留原图也占了相当一部分结果。5,693 个文件因为收益不足或文件很小而不改;1,176 个没有通过像素或质量检查,另有 1,177 个无损候选在浏览器中出现显示像素差异。其余还涉及解码预算、位深、色彩类型、元数据及动画时长或循环参数等限制。没有完成原因隔离前,我不会把所有显示差异都归因于某一种色彩信息。
这解释了为什么没有达到样本里 5.48 GB 的点估计:实际选择了更保守的对象分类,并对完整输入逐图检查、回退。两者不是相同策略,不能把差额全解释成抽样误差。容量规划需要以最后采用的文件为准。
完成后又对最低分数的 4 张 JPEG 做了左上角与中心的原像素局部对照。能看见有损编码带来的细微色块和边缘变化,所查样本中的表格、数字、文字及箭头仍可辨认。这是对程序检查的补充,不能替代全库人工阅读。
本轮还保留了约 8.52 GB 原件备份和 3.84 GB 候选缓存,尚未清理。6.95 GB 只表示正式图片体积,不能用它描述当前磁盘总占用。压缩前文件与正式文件也已分别重新核对全部指纹,便于后续确认采用了什么、原件在哪里。详细计数与参数见全量压缩结果弹窗。
总结
这批图片最终从 11.82 GB 减到 6.95 GB,所有采用的候选都保持原尺寸,另有 9,161 个文件保留原样。主要收益来自编码选择,不能压或不值得压的图片也构成了最后的容量结果;无损、有损和保留原图都需要有自己的采用条件。
技术图的条件要落到具体信息上:长图保住文字宽度,动图保住完整时间轴,像素比较之外还要检查色彩、透明度和阅读器兼容性。公式、小字和细线是否可辨认,不能只靠体积或质量分数判断。样本帮助选择方向,最终容量仍以完整处理和回退后的文件为准。
长期维护还要求派生图片、正文引用与媒体清单一致,并留下可验证的原件备份。正式图片变小,不代表备份与缓存占用也随之消失。这轮结果尚不足以支持「全库压到原来的 1/20,同时保持技术图可读」这个容量目标。
图片压缩测试口径与参数
测试采集于 2026 年 10 月 25 日,范围是 38,461 个去重图片文件,总计 11,818,071,086 字节。127 个静态随机样本和 12 个动图样本用于分层估算,6 个大文件压力样本只用于检查风险。
静态样本尝试 9 个候选,动图尝试 3 个,共 1,233 个候选。1,177 个通过基础校验,56 个因透明度、色彩配置、方向或时间轴检查不符而未被采纳。基础校验与阅读验收分开,未覆盖图片按原大小计算。
静态样本限定为 8 位、2400 万像素以内;动图累计解码像素不超过 1 亿。浏览器检查使用隔离的 Chrome 155.0.8059.85,不使用日常登录状态。
无损 WebP 抽样使用 lossless:true, quality:100, effort:6, exact:true;原尺寸有损 WebP 使用 quality:90/82, effort:4, smartSubsample:true, alphaQuality:100, exact:true。AVIF 使用 effort:3,75/60 档为 4:4:4,激进 40 档为 4:2:0。这些 quality 数字是各编码器自己的参数,不能跨格式直接对等,定义见 Sharp 输出参数。全量应用的无损候选使用 effort:4,包含 75 和 100 两档已经验证的结果;它们保留同样的像素,计算投入不同,输出大小也可能不同。
汇总文件仅保留统计、参数和匿名样本数据,不提供第三方课程原图或全文。正文配图为自制统计与机制示意,不是源课程截图。
全量压缩结果与校验统计
打开原文件 application-summary.json
应用于 2026 年 10 月 26 日完成,38,461 个输入文件中采用 29,300 个候选、保留 9,161 个原文件。进一步内容去重后有 38,383 个正式文件,共 6,954,690,959 字节,实际减少 41.15%。
统计包含程序逐图校验的计数,不代表每张图都已人工阅读。保留原因按每文件最先触发的条件计数;原件备份和候选缓存另计,不混入正式图片体积。汇总不包含第三方课程原图、原始 URL 或本机路径。