有损压缩实践

质量参数 80 是怎么来的?

上线初期,我在 generate_thumbnails 函数里硬编码了一个数字:quality=80

为什么是 80?说实话,我当时在 Google 上搜了一下”WebP 最佳质量参数”,看到一个回答推荐 75~85,就选了中间值。

直到有一天,摄影师老王在群里吐槽:“光影上的照片颜色有点糊,跟我原图比差了不少。”

我下载了老王上传的原图和压缩后的版本,放在一起对比:

原图:         6000×4000, JPEG, 8.7MB, 细节丰富,噪点清晰
压缩后(80):   800×533,   WebP, 45KB,  远看还行,放大后细节丢失明显

远看确实差别不大。但摄影师的眼睛是挑剔的——他们会放大看细节,会注意天空的色带、暗部的噪点、高光的过渡。

我意识到,quality=80 不是一个万能数字。不同类型的图片,需要不同的压缩策略。

第一组实验:JPEG vs WebP 质量扫描

我用小李的 5 张夜景照片做了第一组实验,测试不同质量参数下的文件大小和主观质量:

结果出来了:

质量参数对比(1200×800 夜景照片)

JPEG:
  q30:  18 KB   ← 严重色块,不可用
  q50:  35 KB   ← 可见色块,勉强
  q60:  48 KB   ← 轻微色块
  q70:  68 KB   ← 大部分场景可接受
  q75:  82 KB   ← 摄影师可接受的底线
  q80:  105 KB  ← 肉眼几乎看不出差异
  q85:  135 KB  ← 细节保留很好
  q90:  185 KB  ← 接近无损
  q95:  290 KB  ← 体积增大明显,收益递减

WebP:
  q30:  12 KB   ← 同样不可用
  q50:  24 KB   ← 比 JPEG q50 好一些
  q60:  32 KB   ← 可接受的起点
  q70:  46 KB   ← 与 JPEG q75 接近
  q75:  56 KB   ← 摄影师可接受
  q80:  71 KB   ← 肉眼几乎看不出差异
  q85:  92 KB   ← 细节保留很好
  q90:  128 KB  ← 接近无损
  q95:  198 KB  ← 收益递减

关键发现

同等主观质量下,WebP 比 JPEG 小约 30%~40%

WebP q75 ≈ JPEG q80(主观质量相当)
  JPEG q80: 105 KB
  WebP q75: 56 KB   ← 小 47%!

也就是说,我一直用的 quality=80,在 WebP 下实际上”质量过剩”了——WebP 的 80 对应的是 JPEG 的 85+。

第二组实验:不同内容类型的压缩差异

夜景照片只是其中一种。我又测了 4 种典型内容:

结果让我很意外:

不同内容类型在 800px 宽度下的最佳质量参数(SSIM ≥ 0.95)

内容类型        最佳质量参数   文件大小    说明
───────────────────────────────────────────────────
夜景照片        q78          62 KB      噪点被压缩算法"利用",天然适合有损压缩
人像照片        q75          48 KB      肤色过渡区域需要更多比特,但焦外可压缩
风景照片        q72          38 KB      大面积渐变(天空)压缩效果极好
白底产品        q82          28 KB      纯白背景压缩比极高,但产品边缘需要清晰
UI 截图         q90          85 KB      文字和线条对压缩极敏感,质量参数低了糊

结论:最佳质量参数从 72 到 90,跨度很大!

一句话总结:用固定的 quality=80,有的图片过度压缩(UI 截图),有的图片浪费带宽(风景照)。

第三步:基于内容类型的自适应压缩

我决定实现一个智能压缩策略:根据图片的内容特征,自动选择最佳质量参数。

但问题来了——这个分类逻辑太粗糙了。analyze_content 用的是简单的阈值判断,分类准确率大概只有 70%。有些照片被误判了,比如一张暗色人像被分到了”夜景”。

第四步:更务实的方案——二分搜索找最佳质量

与其费劲做内容分类,不如换一个思路:给定目标质量(SSIM),二分搜索找到最小文件大小对应的质量参数。

实际上,二分搜索的方案更适合生产环境——不依赖内容分类的准确性,直接以目标质量为准。

最终方案:混合策略

最终的方案结合了两种思路:

  1. 先用简单规则做粗分类(白底 vs 非白底,截图 vs 照片)
  2. 在分类基础上调整目标 SSIM
  3. 用二分搜索找到最佳质量参数

效果对比

用最终方案跑了一遍”光影”上最热门的 100 张图:

优化前后对比(800px 宽,WebP 格式)

指标          固定 q=80      智能压缩       改善
─────────────────────────────────────────────────
平均文件大小   78 KB         52 KB         ↓ 33%
最大文件大小   210 KB        120 KB        ↓ 43%
最小文件大小   25 KB         15 KB         ↓ 40%
SSIM ≥ 0.95   98%           100%          ↑ 2%
SSIM < 0.90   2%            0%            ↑ 消除

带宽节省:每月约 35% 的 CDN 流量费

摄影师老王也没再吐槽了。

前端适配

智能压缩是后端的事,但前端也需要配合——告诉浏览器自己支持什么格式: