图片压缩实战:有损 vs 无损,WebP、AVIF 格式转换与工具链
图片压缩这件事,说简单也简单,说复杂也复杂。我见过不少团队,上线前随便扔个在线工具压一压,结果要么画质崩了,要么体积纹丝不动。说白了,你得先搞清楚你到底要什么——是要保留所有细节,还是只要看着差不多就行?
这一节,我们就把有损和无损的区别掰开揉碎,再把 WebP 和 AVIF 这两个现代格式的转换工具链走一遍。嗯,都是实战里每天要用的东西。
有损 vs 无损:核心差异
先给个最直白的定义:
- 无损压缩:压缩后解压出来,和原图一模一样。一个像素都不差。
- 有损压缩:丢掉一些人眼不太敏感的信息,换来更小的体积。解压后和原图不一样,但看着差不多。
你可能会问:「那为什么不都用无损?」原因很简单——体积。我做过一个测试,同一张 1920×1080 的摄影图,PNG 无损压完 2.3MB,JPEG 有损压到 85% 质量只有 320KB。差了 7 倍。对于网页来说,这个差距就是加载速度的天壤之别。
| 特性 | 无损压缩 | 有损压缩 |
|---|---|---|
| 还原度 | 100% 精确 | 近似,有信息丢失 |
| 压缩率 | 通常 2:1 ~ 5:1 | 可达 10:1 ~ 50:1 |
| 适用场景 | 图标、截图、UI 素材、医疗影像 | 摄影图、背景图、用户头像 |
| 典型格式 | PNG、WebP 无损、AVIF 无损 | JPEG、WebP 有损、AVIF 有损 |
核心原则:UI 界面中的图标、按钮、边框等硬边缘图形,优先用无损。摄影图、渐变背景、人物照片,放心用有损。混着用也没问题,但别搞反了。
WebP 与 AVIF:现代格式的优劣势
WebP 和 AVIF 是目前最值得关注的两个下一代图片格式。我个人的习惯是:能用 AVIF 就用 AVIF,不行就降级到 WebP,再不行才用 JPEG/PNG。
WebP
Google 出品,2010 年就发布了。支持有损和无损,也支持透明度(Alpha 通道)和动画。兼容性很好,Chrome、Firefox、Edge、Safari 14+ 都支持。我在一个电商项目中,把商品图从 JPEG 换成 WebP 有损,体积平均降了 30%,肉眼几乎看不出区别。
AVIF
基于 AV1 视频编码的图片格式,压缩率比 WebP 还高 20%~30%。支持 HDR、广色域、透明度。缺点是编码慢,兼容性稍差(Safari 16+ 才支持)。但说实话,对于静态图片,AVIF 是目前压缩效率的天花板。
| 格式 | 压缩率(对比 JPEG) | 有损/无损 | 透明度 | 动画 | 浏览器支持 |
|---|---|---|---|---|---|
| JPEG | 基准 | 仅限有损 | 不支持 | 不支持 | 全部 |
| PNG | 比 JPEG 差 | 仅限无损 | 支持 | 不支持 | 全部 |
| WebP | 比 JPEG 好 25%~35% | 两者都支持 | 支持 | 支持 | Chrome、Firefox、Edge、Safari 14+ |
| AVIF | 比 JPEG 好 50%+ | 两者都支持 | 支持 | 支持 | Chrome、Firefox、Safari 16+ |
我的建议:生产环境用 <picture> 标签做多格式降级。先给 AVIF,不行就 WebP,再不行就 JPEG/PNG。用户浏览器会自动选第一个能解码的格式。
工具链:从命令行到自动化
工具这块,我踩过不少坑。曾经用在线工具批量转 500 张图,结果网站崩了,还得重来。后来我全换成了本地命令行工具,稳定、可控、可脚本化。
1. cwebp — WebP 编码器
Google 官方工具,最稳的选择。安装方式:
# macOS
brew install webp
# Ubuntu
sudo apt-get install webp
基本用法:
# 有损压缩,质量 80
cwebp -q 80 input.jpg -o output.webp
# 无损压缩
cwebp -lossless input.png -o output.webp
# 带透明度
cwebp -lossless -alpha_q 100 input.png -o output.webp
我个人习惯用 -q 75 到 -q 85 之间的值。低于 70 时,有些图片会出现明显的块状伪影。高于 90 时,体积下降就不明显了。
2. avifenc — AVIF 编码器
来自 libavif 项目,需要单独安装:
# macOS
brew install libavif
# Ubuntu
sudo apt-get install libavif-bin
基本用法:
# 有损压缩,质量 80
avifenc -q 80 input.jpg -o output.avif
# 无损压缩
avifenc -l input.png -o output.avif
# 指定编码速度(0=最慢质量最好,6=最快)
avifenc -q 80 -s 4 input.jpg -o output.avif
注意:AVIF 编码速度默认很慢。我曾经转一张 4K 图,默认速度用了 12 秒。加上 -s 6 后降到 2 秒,画质几乎没区别。生产环境建议用 -s 4 到 -s 6。
3. 批量转换脚本
实际项目中你不会一张一张转。这是我常用的批量脚本:
#!/bin/bash
# 批量将当前目录所有 jpg/png 转为 webp 和 avif
for file in *.jpg *.png; do
[ -f "$file" ] || continue
name="${file%.*}"
# 转 WebP 有损,质量 80
cwebp -q 80 "$file" -o "${name}.webp"
# 转 AVIF 有损,质量 80,速度 4
avifenc -q 80 -s 4 "$file" -o "${name}.avif"
echo "已转换: $file"
done
把这个脚本保存为 convert.sh,放到图片目录里跑一下就行。我一般还会加个 --progress 参数看进度。
知识体系总览
下面这张图把这一节的核心逻辑串起来了。你可以把它当作决策地图:
实战避坑指南
最后分享几个我踩过的坑,希望能帮你省点时间。
我曾经在转一批带透明度的图标时,用了 cwebp -q 80 直接转 PNG。结果透明区域出现了白色锯齿。后来才发现,带透明度的图片必须加 -lossless 或者 -alpha_q 参数。记住:有透明度的图,优先用无损。
另一个坑:AVIF 编码时,如果原图是 CMYK 色彩空间的 JPEG,直接转会报错。必须先转成 sRGB。我写了个小脚本,用 ImageMagick 先转色彩空间再编码:convert input.jpg -colorspace sRGB output.jpg && avifenc -q 80 output.jpg -o output.avif。
嗯,图片压缩这块,工具和参数都不难。难的是你心里要清楚:这张图到底要什么?是像素级的精确,还是视觉上的「差不多」?想清楚这个,剩下的就是跑脚本的事了。