图片压缩实战:有损 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 参数看进度。

知识体系总览

下面这张图把这一节的核心逻辑串起来了。你可以把它当作决策地图:

图片压缩决策流程 图片压缩决策流程 原始图片 需要保留全部细节? 是 否 无损压缩 PNG / WebP 无损 / AVIF 无损 有损压缩 JPEG / WebP 有损 / AVIF 有损 输出优化后的图片 提示:用 <picture> 标签做多格式降级,优先 AVIF → WebP → JPEG/PNG

实战避坑指南

最后分享几个我踩过的坑,希望能帮你省点时间。

我曾经在转一批带透明度的图标时,用了 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。

嗯,图片压缩这块,工具和参数都不难。难的是你心里要清楚:这张图到底要什么?是像素级的精确,还是视觉上的「差不多」?想清楚这个,剩下的就是跑脚本的事了。