3. 图片压缩基础:有损压缩与无损压缩的区别,常见图片格式(JPEG、PNG、WebP、AVIF)

说到图片压缩,很多同学第一反应就是「压一下,小一点」。但实际项目里,选错格式的代价可不小。我见过有人把截图存成 JPEG,结果文字边缘全是马赛克;也见过有人把所有图片都转成 PNG,一个页面加载了 5MB 的图片资源。

说白了,图片压缩的核心就两个方向:有损和无损。搞懂它们的区别,你才能在不同场景下做出正确的选择。

3.1 有损压缩 vs 无损压缩

先看一张图,帮你快速建立整体认知:

图片压缩分类体系 图片压缩 有损压缩 无损压缩 JPEG WebP(有损) AVIF(有损) PNG WebP(无损) AVIF(无损) 关键区别: • 有损压缩:丢弃人眼不敏感的色彩/细节信息,文件小,但不可逆 • 无损压缩:保留全部像素数据,可完全还原,但压缩率有限

3.2 有损压缩:用「看不见」换「体积小」

有损压缩的原理,说白了就是丢掉人眼不太敏感的信息。比如一张蓝色天空的照片,相邻几百个像素都是差不多的蓝色,没必要每个像素都精确记录。

JPEG 用的就是这种思路。它先把图像从 RGB 转到 YCbCr 色彩空间,然后对亮度(Y)保留高精度,对色度(Cb、Cr)做大幅下采样。人眼对亮度变化敏感,对颜色变化迟钝——这就是 JPEG 能压到很小但看起来还不错的秘密。

核心指标:质量因子(Quality Factor)

大部分图片库用 0-100 的数值控制压缩程度。我个人习惯:

  • 85-95:高质量,适合摄影作品、产品图
  • 60-75:平衡点,适合大多数 Web 场景
  • 30-50:低质量,适合缩略图或预览图

举个例子,一张 1920×1080 的风景照,原始 BMP 大约 6MB。用 JPEG 质量 80 压缩,能压到 200KB 左右,肉眼几乎看不出区别。但如果你把质量调到 20,文件可能只有 50KB,不过天空会出现明显的色块——这就是「压缩伪影」。

⚠ 注意:有损压缩不可逆

我曾经接手过一个项目,设计师把所有源文件都存成了 JPEG。每次修改都要重新导出,反复保存几次后,图片质量肉眼可见地下降。记住:JPEG 每保存一次,质量就损失一次。源文件一定要用无损格式保存。

3.3 无损压缩:像素级「零误差」

无损压缩不会丢掉任何像素数据。它用的是更聪明的编码方式——比如把重复的数据用更短的符号代替。

PNG 就是无损压缩的代表。它用 DEFLATE 算法(和 ZIP 一样)来压缩数据。对于有大面积纯色的图片(比如截图、图标、UI 界面),PNG 的压缩效果非常好。但如果是照片这种色彩丰富、细节复杂的图,PNG 的压缩率就远不如 JPEG 了。

💡 什么时候必须用无损?

  • 截图、UI 设计稿、文字图片
  • 需要透明背景的图片(PNG-32 支持 Alpha 通道)
  • 医学影像、法律文档等不允许任何失真的场景
  • 作为中间格式反复编辑的源文件

3.4 常见图片格式对比

下面这张表是我在实际项目中总结的,你可以直接拿来当参考:

格式 压缩类型 透明通道 压缩率 浏览器支持 最佳场景
JPEG 有损 不支持 高(照片可压 10-20 倍) 全部 照片、复杂渐变图
PNG-8 无损 支持(1-bit) 中(256 色) 全部 图标、Logo、小尺寸 UI
PNG-24/32 无损 支持(8-bit Alpha) 低(照片压缩率差) 全部 截图、需要透明背景的图
WebP 有损/无损 支持 比 JPEG 小 25-35% Chrome/Edge/Firefox Web 通用替代方案
AVIF 有损/无损 支持 比 JPEG 小 50% 左右 Chrome/Firefox 下一代 Web 图片格式

3.5 WebP 和 AVIF:新一代格式

JPEG 和 PNG 都是上世纪 90 年代的标准了。这些年 Web 图片的需求变了——移动端流量贵、加载速度要求高,老格式越来越力不从心。

WebP 是 Google 在 2010 年推出的。它同时支持有损和无损压缩,还能带透明通道。我做过对比测试:同一张照片,JPEG 质量 80 是 200KB,WebP 有损模式只要 130KB,肉眼几乎看不出区别。无损模式下,PNG 的截图是 150KB,WebP 无损只要 90KB。

AVIF 更新,2019 年才定稿。它基于 AV1 视频编码技术,压缩率比 WebP 还高 30-40%。不过编码速度慢——压缩一张图可能要好几秒,不适合实时场景。

我的建议:

如果你在做新项目,可以这样选:

  1. 照片类 → 优先 WebP 有损,降级到 JPEG
  2. 截图/UI → 优先 WebP 无损,降级到 PNG
  3. 追求极致体积 → 用 AVIF,但要准备 JPEG/PNG 兜底

浏览器不支持 WebP 或 AVIF 的情况越来越少,但还是要做 <picture> 标签的降级处理。

3.6 实战:用 Python 做格式转换

说了这么多理论,来点实际的。下面是我常用的图片压缩脚本,用 Pillow 库实现:

from PIL import Image
import os

def compress_image(input_path, output_path, format='WEBP', quality=80):
    """
    图片压缩与格式转换
    :param input_path: 输入文件路径
    :param output_path: 输出文件路径
    :param format: 目标格式(JPEG/PNG/WEBP/AVIF)
    :param quality: 质量因子(仅对有损格式有效)
    """
    img = Image.open(input_path)

    # 如果是 JPEG 且图片有透明通道,先转成 RGB
    if format == 'JPEG' and img.mode in ('RGBA', 'P'):
        img = img.convert('RGB')

    # 保存
    img.save(output_path, format=format, quality=quality)
    print(f"压缩完成: {input_path} → {output_path}")

# 使用示例
compress_image('photo.png', 'photo.webp', format='WEBP', quality=85)
compress_image('photo.png', 'photo.jpg', format='JPEG', quality=80)
compress_image('screenshot.png', 'screenshot_lossless.webp', format='WEBP', quality=100)

💡 小技巧:批量处理

我在项目中经常要处理几百张图片。用 glob 配合上面的函数,几秒钟就能搞定整个文件夹的格式转换。记得先备份原图——我吃过这个亏,一次误操作把源文件全覆盖了。

3.7 避坑指南

最后分享几个我踩过的坑:

  • 不要用 JPEG 保存带文字的截图——文字边缘会出现模糊和色块,阅读体验极差。截图请用 PNG 或 WebP 无损。
  • PNG 不是万能的——很多人觉得 PNG 是「无损」就所有图都用它。但一张 4K 照片存成 PNG 可能有 15MB,同样的图 JPEG 只要 300KB。选格式要看场景。
  • WebP 的编码质量参数含义不同——WebP 的 quality 是 0-100,但和 JPEG 的 quality 不是线性对应的。我习惯 WebP 用 80-90,效果相当于 JPEG 的 85-95。
  • AVIF 编码慢——如果你在做批量处理,AVIF 的编码时间可能是 WebP 的 5-10 倍。线上实时转换不推荐用 AVIF。

嗯,图片压缩这块,说白了就是在体积和质量之间找平衡。没有银弹,每种格式都有自己的脾气。你只要记住:照片用有损,截图用无损,新项目优先考虑 WebP,就基本不会出大问题。