图片压缩完还是几百KB?我拿一张1.8MB的图实测,问题根本不在格式上

关键词:图片压缩, WebP, AVIF, JPEG采样因子, 图片体积优化

摘要:很多人压缩图片时纠结WebP还是AVIF,其实真正的瓶颈是像素数量和噪点。本文用一张iPhone原片的完整处理过程,给出每一步的具体命令和实测体积数据,说明为什么先做减法再选编码器。

先说结论:体积的锅,格式背不动

图片

图片体积 ≈ 像素数量 × 每个像素携带的信息量。格式(JPEG / WebP / AVIF)决定的是后半段——编码器能把这点信息压到多小,它压不动你图里本来就不该存在的东西。一张 4032×3024 的图有 1220 万个像素,你只打算用 750px 宽显示,那其中 96% 的像素从头到尾没人看见,但每一个都在占字节。所以压缩这件事,第一步永远是删,不是编码。

我见过太多人卡在「选 JPEG 还是 WebP」上纠结三天,却从来没右键看过一眼图片属性里的尺寸。

上个月帮一个做跨境电商的朋友看详情页,主图打开要四秒多。他把原图发我,是一张 4032×3024 的 iPhone 原片,8.7MB。他说他已经压过一轮了,用某个在线工具,压完 1.8MB,「应该够小了吧」。我问他这张图在页面上打算显示多大,他说详情页主体宽度 750px。问题就在这——8.7MB 和 1.8MB,都是在为 4032 个像素宽的数据付费,而屏幕上只兑现 750 个。

下面是我实际跑的一遍,所有数字都是同一张原图测出来的,环境是 macOS + ImageMagick 7 + mozjpeg 4.1.1 + libwebp 1.3.2 + libavif 1.0。

每一步的实测体积

图片

版本 尺寸 体积 备注
原图 HEIC 4032×3024 8.7MB iPhone 直出
转 PNG 无损 4032×3024 21.3MB 别问,问就是无损
mozjpeg q85,不缩尺寸 4032×3024 2.4MB 只压了质量没缩尺寸
mozjpeg q85 1500×1125 214KB 缩到 2 倍图
加上 4:2:0 采样 1500×1125 178KB 色度信息砍掉 3/4
WebP q80 -m 6 1500×1125 112KB
WebP q80 + sharp_yuv 1500×1125 118KB 边缘干净点,多花 6KB
AVIF q28 speed 4 1500×1125 89KB 编码耗了 11 秒

从 8.7MB 到 214KB,靠的是缩尺寸,不是换格式。从 214KB 到 112KB,才是格式的功劳。顺序反了,就白忙。

对应命令大概是这些:

# 缩放 + 去元数据 + 4:2:0 采样
magick src.heic -resize 1500x -colorspace sRGB -strip \
  -sampling-factor 4:2:0 -interlace Plane -quality 82 out.jpg

# mozjpeg 走一遍,tune-ms-ssim 比默认的 psnr 观感更好
cjpeg -quality 82 -tune-ms-ssim -sample 2x2 -optimize -outfile final.jpg out.jpg

# WebP
cwebp -q 80 -m 6 -sharp_yuv -metadata none -resize 1500 0 final.jpg -o final.webp



![图片](http://img2.baidu.com/it/u=3582158909,2014752667&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=667)


# AVIF
avifenc --min 20 --max 30 --speed 4 --yuv 420 --jobs 4 final.jpg final.avif

那个把体积翻倍的隐形杀手:锐化

这是我踩过最亏的一次坑。朋友的图在 Lightroom 里导出时「锐化」拉到 80,「细节」60,他说这样看起来才清楚。

JPEG 的编码核心是 8×8 像素块的 DCT 变换。一张干净的图,高频系数大多是 0 或接近 0,编码器几乎不用花码率;但锐化制造出来的边缘光晕和噪点,是彻头彻尾的高频信号,会把每个块的高频系数全部填满。结果就是:同样 1500×1125、同样 q85,他那张锐化过的图压出来 340KB,我自己重新导出一版没锐化的 178KB。差了将近一倍,肉眼在详情页上完全看不出区别。

如果原图已经锐化过了,补救办法是在压缩前做一次很轻的降噪,半径 0.3~0.5 就够:

图片

magick in.jpg -gaussian-blur 0.4 -resize 1500x -quality 82 out.jpg

注意这个顺序——降噪必须在缩放之后、编码之前。先降噪再缩放,模糊会被放大回来。另外手机夜景模式拍的图天生噪点多,这一类图换成 AVIF 收益会明显大于普通图,因为 AVIF 的块内预测对随机噪声的容忍度确实比 JPEG 高一截。

关于色彩配置和 EXIF,有个坑得说清楚

-strip 这两个字很多人是无脑加的,包括以前的我。但如果你拍的是 Display P3 的图(新款 iPhone 默认就是这个色彩空间),直接 strip 掉 ICC 配置,浏览器会按 sRGB 解释那些数值,红橙色会整个闷下去,肤色发灰。

普通 sRGB 的 ICC 配置只有 3KB 左右,丢不丢无所谓;苹果设备导出的 P3 配置也就几 KB。正确做法是先转到 sRGB 再 strip,而不是直接删:

图片

magick in.jpg -profile /System/Library/ColorSync/Profiles/sRGB Profile.icc -strip out.jpg

EXIF 倒是可以放心删,手机直出的 EXIF 一般 10~40KB,里面有 GPS 坐标、设备序列号、拍摄时间。除非你要做摄影作品集,否则这些信息对网页加载没有任何价值。

我对格式这件事的独立看法

现在的普遍说法是「AVIF 比 WebP 小 30%,WebP 比 JPEG 小 30%」,这个数据本身没错,但它有个前提:测试用的是原始的高质量图片。

一旦你按上面那套流程先把尺寸缩了、噪点降了,AVIF 相对 WebP 的优势会从 30% 掉到 8% 左右——我这次实测就是 89KB 对 112KB,差 23KB。为了这 23KB,你要付出的是:编码时间从 0.3 秒变成 11 秒(36 倍),构建流程里多一个原生依赖,以及给 2020 年前的老设备准备回退方案。

我的判断是:内容站、博客、后台系统,WebP 就够了,jpg + webp 双份输出,兼容性和收益平衡得最好。只有两类场景值得上 AVIF——一是图片量级在十万张以上、带宽成本真实存在的电商站;二是摄影、艺术类站点,图本身就是内容,那 8% 的观感提升是值得的。

图片

还有个反直觉的点:AVIF 在极低码率(相当于 JPEG q40 以下)区间的优势非常夸张,能到 2~3 倍,但在中高码率区间反超幅度骤减。所以如果你的图本来就压得很狠,换 AVIF 收益最大;如果你的图是 q82 这种「看起来很干净」的档位,换格式省下的那点体积,还不如把尺寸从 1500px 降到 1200px 来得实在。

我现在的固定流程

  1. 先问显示尺寸。响应式页面就按断点三分:640 / 1200 / 1920,配 srcset。桌面端不搞 2x 图,那是给手机和 Retina 笔记本用的。
  2. 缩放。ImageMagick 默认的 Lanczos 就可以了,缩小的场景下它比 bicubic 锐一些,但也更容易出振铃,人像图我会换成 -filter Triangle。
  3. 看看原图是否锐化过。光线充足、光圈 f5.6 以上的图基本不用降噪;夜景、室内、手机长焦的图,加 0.4 半径。
  4. 转色彩空间到 sRGB,strip 掉 EXIF 和多余配置。
  5. 输出 JPEG q82 打底,再出一份 WebP q80。用 <picture> 标签包起来,AVIF 暂时不加。
  6. 全部跑一遍 jpegoptim --strip-all --all-progressive --max=82,能再抠出 3%~5%。渐进式 JPEG 对首屏感知速度的提升其实比体积更明显。

最后说一句可能有点扫兴的话:图片优化这件事,80% 的收益来自「把尺寸改对」这一步,剩下的 20% 才轮得到格式、采样、渐进式这些技术细节去分。但大家总是更愿意研究后者,因为前者太朴素了,朴素到不像一个技术问题。

我刚开始做前端那两年也是这样,花一下午调 cwebp 的参数,就为了从 118KB 抠到 112KB,然后交上去一个 2400px 宽的 banner 图。

标签: