红底海报存成WebP无损,竟比有损还小

27 阅读6分钟

我一直默认「无损」和「小」是两头的事。要干净就得认大体积。要小就得接受一点损失。这周拿一张红底海报去试 WebP 的时候这个默认被打翻了。cwebp 的无损模式压出来只有 48 KB,比有损质量 80 的 66 KB 还小。更怪的是同样叫 WebP 无损的浏览器 canvas 导出却有 375 KB。一个格式换个编码器就差出去七倍多。我把这几组数摆在一起看了一遍,也顺带想清楚了这类图该选哪条路。

海报是我自己写脚本生成的 1600×900 促销风样图,上面是红底黄字的大标题,下面一张白卡片印着几行红色小字。图里没有照片也没用外部素材。126 373 字节的原图 PNG 里我数出了 746 种颜色。真正用到的其实就红黄白黑那几种颜色,剩下的全是字边抗锯齿挤出来的过渡色。机器是一台 16 GB 内存的 Apple M4 Mac,命令行编码器用的是 cwebp 1.6.0,浏览器是 Chromium 149 的开源构建。好坏我看的是字边那一圈的色差 ΔE,越小越接近原图,一般认为超过 5 肉眼就能直接看到色边。

先说有损。WebP 有损这个格式本身只有 4:2:0 这一种色度抽样。颜色信息横竖各砍一半以后只剩四分之一的像素。红字白底和黄字红底之间差的主要是颜色,颜色一存粗字边就晕出一圈杂色。浏览器导出 0.8、0.9 和 0.99 三档时色差分别是 6.93、6.56 和 6.29。调到 0.99 也只好了一点点,跟 JPEG 的 4:2:0 在同一个水平上。cwebp 有个 -sharp_yuv 开关能换一种 RGB 转 YUV 的算法,抽样还是 4:2:0 不变。质量 90 时加上它色差会从 6.56 降到 4.77。文件则由 87 554 字节变成 94 840 字节,只多了 8%。这开关挺划算,可惜浏览器的导出接口里没有这个选项。

无损为什么反而小?我不是做编码器的。下面只是我自己的理解。有损编码是按小方块来处理画面的。字边这种颜色突变的地方最费数据。它花了很多码率去描那一圈也还是描不准。无损模式手里有调色板还能直接照抄前面出现过的像素。这张海报大片纯红和大片纯白之间只夹着几种颜色的字,正好撞在它最擅长的内容上。cwebp 加 -lossless 出来的 49 432 字节文件误差是 0。

为了找个参照,我在这张纯色海报上又用了图映 ImgIng(imging.cn/)的压缩转换,在同一台 M4 的 Chromium 149 上全用默认参数跑的。它识别成线稿以后直接切到了 PNG-8。输出的文件 124 色、48 481 字节,比原图省 62%,字边色差 0.13。两条路几乎一样大。界面上写的是「无损又小」,可我逐像素对了一遍发现有 2.03% 的像素不一样,最大差 6。肉眼看不出来但谈不上逐像素无损。我又让它转了一次 WebP,默认推荐的质量 84 出来是 74 490 字节,色差 6.80。这比它自己默认给的 PNG-8 更大也更脏。

最让我意外的是浏览器那边。canvas 导出 WebP 时质量填 1.0 的话 Chromium 走的也是无损。可文件有 384 000 字节,也就是 375 KB。这是 cwebp 无损的 7.8 倍,差不多是原图 PNG 的三倍。我猜是浏览器为了导出快用了一套偷懒的无损参数,这点我没拆开证实。反正结论不变。想拿到无损 WebP 那点体积只能靠 cwebp 这类命令行工具。浏览器里直接导是导不出来的。

上面这些全是在我自己画的纯色海报上测的。想看看换成网上的真实图还成不成立,我从网上找了一张现成的 2026 年国庆放假通知模板(稿定设计的模板图)又跑了一遍。它是 1242×2688 的真彩 PNG。顶上是红底大标题,中间是米白卡片上的红字,下面是一格格红字日历。背景里还有渐变、插画和灯笼打底。光是颜色就有 169 747 种,跟那张 746 色的海报完全不是一类图。配图里角上的品牌小标和二维码我都裁掉了。

从网上找的国庆放假通知模板全图,两个红框标出放大的位置

这张是模板的全图。两个红框就是后面放大的地方。一个框着中间卡片里「10月8日返岗」那行字,另一个框着日历里 10 月 1 日到 3 日这三格。下面那张放大图只截了日历这一块。

模板日历三格放大 5 倍,从上到下是原图、浏览器 WebP 0.9、cwebp 90 加 sharp YUV、WebP 无损

这张是日历里「1 廿一」「2 廿二」「3 廿三」那三格放大 5 倍以后的样子,图上没标任何字。从上到下四行依次是原图、浏览器导出的 WebP 0.9、cwebp 质量 90 加 sharp YUV 和 WebP 无损。要盯的是底下那排「廿一」「廿二」小字。第二行的笔画颜色发暗发褐,原图那几笔是正红。第三行颜色回来了一些,细看还是比原图脏一点。最底下的无损和原图分不出来。有损这边方向和纯色海报一样。日历这块浏览器 WebP 0.9 和 cwebp 质量 90 的色差都是 4.67。加上 sharp YUV 能降到 3.71,cwebp 的文件从 770 350 字节涨到 803 972 字节。

无损这边就翻过来了。cwebp 无损出来有 2 359 014 字节。浏览器 WebP 0.9 只有 769 886 字节。连 JPEG 0.9 那 950 062 字节都比它小了一大截,无损的体积是 JPEG 0.9 的 2.5 倍。我猜是渐变和插画把颜色撑得太多,调色板和照抄像素那两招在这种图上都使不上劲。所以前面说的「无损又小又干净」只在几种纯色加字的平面图上成立,这张模板上正好反过来。这回图映也没有选 PNG-8。它把模板判成了「截图/界面」,默认给的是 WebP 画质 84。结果从 3.18 MB 压到 587.9 KB 省了 82%。字边色差 5.12,跟普通 WebP 有损在一个水平,谈不上保住了红字。

我现在给这类纯色加文字的图选格式时先看手边能不能跑命令行。能跑就直接 cwebp -lossless,在这种图上它比我测过的每一档 WebP 有损都小还干净。只能在浏览器里导的话千万别选 WebP 1.0。那是个 375 KB 的坑,存 PNG 减色要实在得多。带渐变和插画的模板就别指望无损了。老老实实用有损,能跑命令行的话再加上 sharp YUV。照片我这次没测,这种图谁更好我就不下结论了。写完这篇正好是十月一号,祝祖国生日快乐。