4、有损压缩原理:JPEG压缩流程、DCT变换、量化表、色度抽样、压缩率与质量权衡
有损压缩,说白了就是「丢掉一些你不太容易察觉的信息,换来大幅度的体积缩减」。在GUI设计中,图片资源占了很大比重。你想想看,一张未经压缩的1920×1080全彩图,光像素数据就要6MB左右。如果不做压缩,用户加载页面时体验会很糟糕。
JPEG是应用最广泛的有损压缩标准。我刚开始做前端时,总觉得JPEG就是「保存图片时选个质量参数」这么简单。直到有一次,我负责优化一个电商详情页,首屏加载了十几张商品图,每张都超过500KB。嗯,那之后我才真正去研究JPEG到底是怎么工作的。
JPEG压缩的整体流程
JPEG压缩不是一步到位的。它是一套精心设计的流水线,每个环节都在做「取舍」。我习惯把整个流程拆成五个步骤:
- 颜色空间转换:从RGB转到YCbCr
- 色度抽样:降低色彩分辨率
- 分块与DCT变换:把像素块转换到频域
- 量化:丢掉高频细节
- 熵编码:无损压缩剩余数据
每一步都有讲究。下面这张图能帮你快速建立整体认知:
颜色空间转换:为什么不用RGB?
JPEG第一步就是把RGB转成YCbCr。Y是亮度,Cb和Cr是蓝色差和红色差。为什么这么做?因为人眼对亮度变化敏感,对色彩变化相对迟钝。
我举个例子。你在暗光环境下看一张照片,能清晰分辨物体的轮廓(亮度信息),但可能很难准确说出物体的颜色(色度信息)。JPEG正是利用了这个特性。
转换公式(简化版):
Y = 0.299R + 0.587G + 0.114B
Cb = -0.169R - 0.331G + 0.500B + 128
Cr = 0.500R - 0.419G - 0.081B + 128
Y的范围是0-255,Cb和Cr的范围也是0-255(以128为中心)。
这个转换本身是无损的。真正的「损失」发生在后面的步骤。
色度抽样:人眼是最好的「压缩器」
色度抽样,说白了就是「降低色彩通道的分辨率」。最常见的模式有三种:
| 抽样模式 | 亮度分辨率 | 色度分辨率 | 数据量比例 | 典型场景 |
|---|---|---|---|---|
| 4:4:4 | 全分辨率 | 全分辨率 | 100% | 高质量图像、文字截图 |
| 4:2:2 | 全分辨率 | 水平减半 | ~67% | 视频、中等质量照片 |
| 4:2:0 | 全分辨率 | 水平和垂直都减半 | ~50% | Web图片、JPEG默认 |
我建议你在GUI设计中使用4:2:0作为默认值。为什么?因为大多数照片和UI截图,人眼根本看不出4:4:4和4:2:0的区别。我曾经做过一个A/B测试,让10个设计师盲选,结果没人能稳定区分4:2:0和4:4:4的版本。
⚠️ 注意:如果图片包含细小的彩色文字或彩色线条(比如UI中的彩色图标、标注),4:2:0会导致明显的色彩模糊。这种情况下,我建议使用4:4:4或干脆用PNG。
DCT变换:从像素到频率
DCT(离散余弦变换)是JPEG最核心的一步。它把8×8的像素块,从「空间域」转换到「频率域」。
你想想看,一张8×8的图片块,如果所有像素值都一样(比如纯色背景),它在频域里就只有一个「直流分量」。如果像素变化剧烈(比如纹理细节),就会有很多「高频分量」。
DCT变换本身是无损的(浮点精度内)。真正的「有损」发生在下一步——量化。
💡 我的理解:DCT就像把一段音乐分解成不同频率的音符。低频是主旋律,高频是细节装饰。量化就是决定「哪些音符可以丢掉」。
量化表:压缩率的「调节旋钮」
量化是JPEG中唯一真正丢失信息的地方。每个DCT系数都会被一个对应的量化值除,然后四舍五入取整。
量化表是8×8的矩阵,每个位置对应一个频率分量的「容忍度」。低频分量(左上角)的量化值小,保留更多细节;高频分量(右下角)的量化值大,被大量丢弃。
下面是一份标准的亮度量化表(JPEG标准推荐):
| 16 | 11 | 10 | 16 | 24 | 40 | 51 | 61 |
|---|---|---|---|---|---|---|---|
| 12 | 12 | 14 | 19 | 26 | 58 | 60 | 55 |
| 14 | 13 | 16 | 24 | 40 | 57 | 69 | 56 |
| 14 | 17 | 22 | 29 | 51 | 87 | 80 | 62 |
| 18 | 22 | 37 | 56 | 68 | 109 | 103 | 77 |
| 24 | 35 | 55 | 64 | 81 | 104 | 113 | 92 |
| 49 | 64 | 78 | 87 | 103 | 121 | 120 | 101 |
| 72 | 92 | 95 | 98 | 112 | 100 | 103 | 99 |
注意看,左上角的16是最小的,右下角的99是最大的。这意味着低频分量被保留得更多,高频分量被丢弃得更多。
量化公式:
量化后的系数 = round(DCT系数 / 量化值)
反量化时:重建的DCT系数 = 量化后的系数 × 量化值
因为四舍五入,重建的值和原始值之间就有了误差。这就是「有损」的来源。
你平时在Photoshop或图片库中设置的「Quality」参数,本质上就是缩放这个量化表。Quality=100时,量化表全部为1,几乎没有损失。Quality=1时,量化表被放大很多倍,文件极小但画质惨不忍睹。
压缩率与质量的权衡
这是JPEG最实际的问题。我见过太多设计师直接使用「最高质量」导出,结果图片体积大得离谱。也见过为了追求极致体积,把质量拉到20,图片全是块状伪影。
根据我的经验,不同场景的推荐值如下:
| 质量参数 | 压缩率 | 视觉质量 | 推荐场景 |
|---|---|---|---|
| 90-100 | 2:1 ~ 5:1 | 几乎无损 | 摄影作品、医疗影像 |
| 75-85 | 10:1 ~ 15:1 | 优秀 | Web产品图、Banner |
| 50-70 | 15:1 ~ 25:1 | 良好 | 缩略图、列表封面 |
| 30-50 | 25:1 ~ 40:1 | 可接受 | 预览图、低带宽场景 |
| <30 | >40:1 | 明显伪影 | 不推荐用于GUI |
💡 我的建议:对于Web GUI中的照片类资源,我通常使用Quality=80配合4:2:0色度抽样。这个组合能在体积和画质之间取得很好的平衡。如果图片包含文字或UI元素,我会改用Quality=90 + 4:4:4,或者直接使用PNG。
JPEG的「硬伤」与避坑
JPEG虽然强大,但有几个地方需要特别注意:
- 块效应:低质量下,8×8块的边界会变得明显。我曾经在优化一个背景渐变的页面时,压缩后的图片出现了明显的「马赛克」感。解决方案是提高质量参数,或者改用WebP。
- 振铃效应:在边缘附近出现「鬼影」。这在文字截图或UI元素中特别明显。
- 颜色偏移:色度抽样导致的色彩模糊。如果图片中有红色文字或蓝色按钮,4:2:0会让它们变得模糊。
⚠️ 避坑指南:我曾经把一个包含精细图表的截图用JPEG保存,结果图表中的网格线和标注文字全部糊成一团。从那以后,凡是包含文字、线条、图标的图片,我坚决不用JPEG。用PNG或WebP无损模式才是正解。
小结
JPEG的有损压缩,本质上是一场「欺骗人眼」的游戏。它利用我们对亮度敏感、对色彩迟钝的特性,通过色度抽样和量化,大幅减少了数据量。DCT变换把像素信息转换到频域,让量化可以「精准打击」那些不重要的高频细节。
理解这些原理,你就能在GUI设计中做出更明智的选择:什么时候用JPEG,用多少质量,用什么色度抽样。而不是盲目地「导出-看大小-调参数-再导出」。