WebP 压缩参数,我实测出这张表

先给结论:我现在所有配图固定 1200px 宽 + q82 + method=6,单图红线 80KB。

这三个数不是抄来的。9 月 28 号晚上张工连着问了两遍「这图到底有没有被压缩」,我嘴上保证没用,得拿数字。拿一张刚生成的 1536px 图,先缩到 1200px,再从 q95 一路压到 q60,每档记体积和 PSNR:

quality 1200px 体积 PSNR
q95 65.1 KB 36.9 dB
q90 51.3 KB 36.7
q85 43.9 KB 36.3
q82 40.9 KB —
q80 38.4 KB 36.1
q75 34.3 KB 35.3
q60 30.5 KB 34.9

测的是一张中英混排的信息图,不是照片。换一类图,这张表就得重测。

q95 到 q85 是白赚的

65.1KB 掉到 43.9KB,省了三分之一,PSNR 只掉 0.6dB。

这段没有任何代价。还在用 q95 存网页配图的,等于白扔三分之一的流量。q90 那行更没理由选 —— 51.3KB / 36.7dB,两边都不占优。

单看这张表会选 q75,那是错的

q85 往下再压到 q75,还能省 22%。PSNR 35.3dB。

35dB 放在任何一份「PSNR 多少算可接受」的资料里都算过关,通常说法是 30dB 以上人眼难辨。数字不难看,体积又小了近 10KB。我一开始就是顺着数字往下看的。

把这些图按正文实际宽度并排摆开,q75 的文字边缘开始毛了 —— 笔画边上浮出一层浅色糊边,字号越小越明显。图上的字糊了,这张图就没有存在价值了。

PSNR 为什么没报警?我的理解是它算全图逐像素误差的平均,而我这些图大片是纯色背景(背景色是 RGB(22,27,34),一张图里能占六七成),边缘那几千个像素的劣化被分母摊平了。这块我没深究,只是能对上现象。

能用的一句话结论是:对文字密集的图,PSNR 只能看趋势,不能当判据。 真正的判据就一条 —— 按显示宽度并排看字。

再往下 q60 是 30.5KB,比 q75 只小 3.8KB,画质继续掉,不值。

最后停在 82 也没什么深奥理由。q85 和 q82 差 3KB,画质区别我看不出来,就往低取了一格。表上 q82 那行 PSNR 是空的,因为它是最后定的档位,定完直接用上了,没回头补测。

宽度比质量更能决定体积

同一张图固定 q85,只改宽度:

1536px = 58.4KB    1200px = 43.9KB    1000px = 34.3KB    900px = 29.7KB    800px = 25.3KB

站点正文实宽约 800px。按「够用就行」,800px 就该是答案,比 1200 省 42%。

我没选它。这些图是文字密集的信息图,不是照片。压到 1x 在高分屏上一拉伸就糊,糊了字就白画了。1200 是 800 的 1.5x,是个折中:高分屏下不至于明显发虚,体积还能压在 45KB 上下。

照片往 800-1000 压没事,文字图不行。这是两类图的分界线。

alt:WebP 质量档位实测表,q95 到 q60 的体积与 PSNR,标出白赚区与文字边缘受损区
alt:WebP 质量档位实测表,q95 到 q60 的体积与 PSNR,标出白赚区与文字边缘受损区

定完就写进脚本,别每次手试

固化成一个 to_web():PNG 出来之后自动缩到 1200、转 WebP、量体积,超 80KB 直接标红。

WEB_WIDTH  = 1200
WEB_Q      = 82
WEB_MAX_KB = 80          # 单图红线,超了就报警

im.save(out, "WEBP", quality=WEB_Q, method=6)
kb = os.path.getsize(out) / 1024
flag = "" if kb <= WEB_MAX_KB else "  ← 超红线!"
python gen_images.py            # 生成 PNG 原图(1536px)
python gen_images.py to_web     # 缩到 1200px、转 WebP q82、报体积
python gen_images.py --no-web   # 只要 PNG,不压缩

method=6 是把压缩强度拉满,出图慢一些、体积再小一些。反正是本地跑一次,慢得起。

红线不是为了省流量,是兜住我自己的偷懒。图越画越复杂、元素越堆越多,体积会悄悄涨上去,涨到 80KB 就被拦一下。

alt:宽度与体积的对比条,以及 1200px、q82、80KB 红线三条定案参数与各自理由
alt:宽度与体积的对比条,以及 1200px、q82、80KB 红线三条定案参数与各自理由

那批图最后 3 张合计 116.2KB(40.9 / 38.0 / 37.2),线上 Content-Type 是 image/webp。对比最早那版生图的 3809KB,省了 97%。115-134KB 的 PNG 原图只留在本机,压过的那版才上传。

这些图都是 Pillow 画的,画的时候撞过三个字体坑,那篇里记了。上线清单那篇里我把「图片转 WebP」随手写成 ≤150KB,那个数是拍脑袋的,回看那篇才发现该改成 80KB。

PSNR 摊薄那部分我到现在也只是猜测。真要较真得看量化表怎么作用在边缘块上,我没往下挖。

发表评论