图片压缩后还是很糊?我把 JPEG、WebP、AVIF 的参数挨个试了一遍
去年冬天帮一个开女装店的朋友收拾她的详情页,才发现多数人处理图片的思路是反的。她拿着 PS 把 4000×6000 的原图直接“另存为 Web 格式”,质量拉到 60,出来一张 900KB 的图,手机上看糊得像隔了层毛玻璃。我问她为什么不先缩尺寸,她说缩了就“不清了”。这个逻辑其实挺普遍——大家把压缩等同于“降质量”,但真正决定观感的,是你在哪一步降、用什么算法降。
同样是 4000px 降到 1200px,ImageMagick 的默认 -filter 是 Mitchell,换成 Lanczos 边缘会锐一截,换成 -filter point 直接出锯齿。Lanczos 好用,但它有负瓣,在高对比边缘(比如白底黑字)会有轻微振铃,也就是字边上一圈淡淡的白边。我试过用 magick input.jpg -resize 1200x -filter Lanczos -unsharp 0x0.75+0.75+0.008 处理商品图,肉眼看是干净的;但同一套参数丢到带文字的促销 banner 上,白边就出来了。所以我的习惯是照片走 Lanczos,带文字和线条的截图走 Catmull-Rom 或者干脆 Photoshop 里的“两次立方(较锐利)”,别一条参数打天下。
再说 JPEG 本身。很多人只知道质量 0-100,不知道后面还藏着色度子采样。cjpeg -quality 82 -sample 2x2 -optimize -progressive 这条命令里的 2x2 就是 4:2:0,色度信息只保留四分之一。对风景照几乎没影响,但大面积纯红、纯蓝的平涂区域会出现色块,尤其是电商的纯色背景图。我朋友那批图就是因为一件酒红色毛衣,4:2:0 下色块一块一块的,改成 4:4:4 之后文件大了大概 40%,但色块没了。她那个页面总共 12 张图,多出来的体积在 WiFi 下根本不算事。
顺带说个更隐蔽的坑:-strip 会把 EXIF 一起删掉,包括手机竖拍照片里的方向标记。有次我批量压了 200 张用户上传的图,全变成横躺的,就是因为原图是 iPhone 拍的、靠 EXIF 的 Orientation 字段在浏览器里自动转向。解决办法是先读 EXIF 把方向转正再 strip,或者干脆别 strip。EXIF 通常也就几 KB,留着不亏。
WebP 和 AVIF 这两年问的人特别多。Google 官方给的数据是同等 SSIM 下 WebP 比 JPEG 小 25%-34%,AVIF 在低码率段又能比 WebP 再小 20% 左右。但数据是数据,我实测下来更在意的是编码耗时:一张 4000×4000 的图,libjpeg-turbo 编码 0.3 秒左右,WebP 大概 1.5 秒,AVIF 用 libaom 能跑 8-12 秒。sharp 里 .avif({ effort: 4 }) 算是个折中,effort 拉到 9 体积还能再小个 8% 左右,但时间翻三四倍,批量场景下不划算。
兼容性上现在没什么好纠结的。Safari 从 14 开始支持 WebP,16.4 开始支持 AVIF,都是好几年前的事了。真正需要做的是用 <picture> 兜底:第一层 AVIF,第二层 WebP,最后 <img src="xxx.jpg">。浏览器自己会挑第一个认识的,你连 JS 都不用写。我一般把质量参数定成 AVIF 50、WebP 80、JPEG 82,这三档在 1200px 宽度下的主观画质基本齐平。
还有一点很多人没意识到:有损 WebP 的透明通道是无损保存的,所以一张带大面积透明区域的设计稿转成有损 WebP,可能比 PNG 还大。这种情况要么保留 PNG,要么把透明区域先填成背景色再转。
最后给个我自己在用的参数清单,直接抄:照片先缩到目标尺寸的 2 倍(为了适配高 DPR 屏幕),-filter Lanczos,然后 cjpeg -quality 82 -sample 2x2 -optimize -progressive -strip(注意先转正再 strip);纯色多的商品图把 2x2 改成 1x1;带文字的图不走 JPEG,走 PNG 或者无损 WebP。整套流程下来,一张手机拍的 4MB 照片能落到 200-350KB,iPad 的 Retina 屏上看不出和原图的区别。真正拉开差距的从来不是质量滑块拖到几,是你先缩尺寸、再选算法、最后才谈质量。