> ## 文章索引
> 在这里获取全部文章的索引：https://lrd.im/blog/llms.txt
> 这是 lrd.im 的个人博客，记录设计、技术与思考。

# 探索 JPG 和 PNG 图片的压缩表现、算法与应用

![封面图](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/01.png)

前段时间做了些展示页，工作时需要给到切图给前端。以我的习惯，每次都会导出 PNG 并压缩后才交付给前端。有一天我突然想到：

> 为什么我每次切图时下意识都是会提供 PNG 格式给开发，而不是使用 JPG 格式的图片？这是什么时候开始的习惯？

回想起来应该是我刚刚进职场的时候，在一些设计文章里听过的说法：

1. PNG 图片支持透明通道，适用场景比 JPG 要更加宽广，无脑 PNG 即可；
2. PNG 图片支持 "无损压缩"，所以图像质量会比 JPG 好一些。

第一点毋庸置疑，但对于第二点我是有点怀疑的：PNG 图片的质量真的在任何时候都比 JPG 要高吗？并且更想知道所谓的 "无损压缩" 是什么，真有这么厉害的技术？所以我打算花点时间做下研究，顺便将研究结果分享给其他团队的设计师们。

这篇文章是一篇在团队月度分享会的记录，分享会内容主要是在回答这个问题：

> JPG 和 PNG 分别适合储存什么类型的图片？

回答完这个问题后，我会简单介绍下 **JPG 和 PNG 图片压缩机制**。正是因为 JPG 和 PNG 这两种图片格式的压缩机制的不同才导致适合储存不同类型的图片。
以及扩展一下思路，会介绍一个我已经实际工作用过的方法：**通过 CSS 的混合模式节省网页图片资源**。

## 一、图片压缩分析

### 分析方法

这次我用了三种类型的图片进行分析，都是我在实际设计工作中有可能导出成位图交付给前端开发的图片类型：

![三种图片类型示例：颜色丰富的 Flash SALE Banner 图、画面简单的渐变背景图、包含日历与任务列表的界面设计图，分别用于测试 JPG 与 PNG 在不同场景下的压缩表现。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/02.png)


1. 颜色丰富的 Banner 图：测试压缩算法在细节保持方面的表现
2. 过渡柔和的背景图：测试压缩算法在处理低色彩复杂度时的表现
3. 界面设计图：测试压缩对大色块、文字和边缘清晰度的影响

具体的分析过程：拿三个在设计工作中常用到的图片类型（相同尺寸、均无透明通道）进行压缩，以对比 JPG & PNG 图片在压缩前后的表现。分两个维度进行对比：**图片体积**和**图像质量**。

![分析过程示意图，分三步：第一步用 Figma 导出无透明通道的 JPG 和 PNG 图片（默认质量）；第二步用 TinyPNG 以默认参数压缩；第三步对比压缩前后的图片体积与质量，得出 JPG 和 PNG 各自适用的图片类型结论。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/03.png)

### 分析结果

#### 一、图片体积对比

![三类图片压缩体积对比表格：颜色丰富的 Banner 图，JPG 从 518kb 压缩至 66kb，PNG 从 926kb 压缩至 182kb；过渡柔和的背景图，JPG 从 61kb 压至 8kb，PNG 从 158kb 压至 42kb；界面设计图，JPG 从 114kb 压至 36kb，PNG 从 30kb 压至 12kb。前两类 JPG 体积远小于 PNG，界面设计图则 PNG 更小。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/04.png)

由上图对比可以比较直观的看到，前两个类型（颜色丰富的 Banner 图、过渡柔和的背景图）在图片体积上，JPG 格式图片的体积要比 PNG 格式的图片体积小得多。

通过这一轮对比，我们可以得出结论：

1. 画面颜色丰富、颜色过渡比较细腻柔和的图片，JPG 图片的体积比 PNG 的更小；
2. 画面颜色越丰富，JPG 图片越能节省空间；
3. 颜色数量较少时，PNG 图片的体积比 JPG 图片的更小。

#### 二、图像质量对比

##### 对比一：颜色丰富的 Banner 图

这一轮我们会放大图片的局部，对比 JPG 和 PNG 图片在经过压缩后，图像质量的区别。

![JPG 与 PNG 图像质量对比：颜色丰富的 Banner 图中，JPG 颜色过渡柔和，PNG 出现明显色块；文字清晰度方面，PNG 边缘锐利，JPG 有杂色，PNG 更优。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/05.png)

在颜色丰富的图像中，JPG 图片的颜色过渡质量比 PNG 好得多，即便是压缩过后也能保持柔和的过渡。反观 PNG 图片，则是出现了明显的色块。

在文字、边缘的展示方面，PNG 图片则比 JPG 图片好一些。PNG 图片保持了原本清晰、锐利的边缘，而 JPG 图片则在处理边缘时有些许杂色。

##### 对比二：过渡柔和的背景图

![图片质量对比（2）：两组柔和渐变背景图的 JPG 与 PNG 压缩质量对比。左组为青绿色渐变，右组为淡紫色渐变，两组结论均为"颜色质量：接近"，差异不明显。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/06.png)

这是一个令人意外的结果，在图像内容比较简单，仅仅只有一些色彩过渡的时候，JPG 和 PNG 图片的质量都很接近。只有在放大很多倍的时候才能看到 PNG 的图片过渡效果比 JPG 要差一些，还是出现了和前一种类型类似的色块现象。

为了探究得更深入些，我在这里用了一张暗色系且过渡柔和的背景图进行同样的压缩测试，这次的测试结果对比会明显很多。

![暗色系柔和过渡背景图的 JPG 与 PNG 压缩质量对比：左侧紫色渐变和右侧深绿色渐变各自展示 JPG 和 PNG 版本，PNG 图片出现明显色块和噪点，JPG 仍保持平滑过渡，颜色质量 JPG 胜出。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/07.png)

在深色系且有柔和过渡的图片当中，JPG 图像的质量明显比 PNG 要高。如上图所示，PNG 图片的色块和噪点已经比较明显了，而 JPG 仍然保持较柔和的过渡。

##### 对比三：界面设计图

![界面设计图的 JPG 与 PNG 质量对比：左侧色块边缘对比中，PNG 的蓝色按钮边缘更清晰锐利，JPG 略有杂色；右侧文字清晰度对比中，PNG 的中文字符边缘明显更清晰，JPG 出现模糊锯齿。结论：PNG 更适合界面设计图。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/08.png)

在对比界面设计图时可以看到，PNG 格式的图片在处理色块边缘、文字边缘时都比 JPG 图片要好得多，边缘很清晰锐利，甚至和压缩前的原图没有什么分别。

#### 三、总结

经过上述对三种不同类型图片的**图片体积**、**画面质量**对比后，我这里总结出了以下规律：

![JPG 与 PNG 适用场景对比总结：JPG 适合颜色丰富、过渡柔和的图片（网站 Banner、大场景、3D 渲染图、摄影图片）；PNG 适合颜色数量少、色块切割明显的图片（界面设计、扁平插画、Logo、带文字图片）。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/09.png)

| 格式 | 适用场景 | 图片特征 | 典型用途 | 优势 |
|------|----------|----------|----------|------|
| JPG | 颜色丰富、过渡柔和、有丰富渐变和复杂视觉元素 | 复杂色彩、连续色调 | 网站 Banner、大场景、3D 渲染图、摄影图片 | 体积小且颜色漂亮 |
| PNG | 颜色数量少、色块切割明显 | 简单色彩、边缘清晰 | 界面、扁平插画、Logo、带文字的图片 | 体积小、色彩准确、边缘清晰 |

## 二、图片压缩过程

这一章会探索 JPG & PNG 图片的压缩过程，这也是导致上文提到 JPG 和 PNG 压缩后图像差异的原因。

### JPG 图片压缩过程

JPG 图片压缩过程主要有以下几步：

![JPG 压缩流程图，依次经过六个步骤：色彩空间转换 → 下采样 → 分块和离散余弦变换 → 量化 → 编码 → 存储。其中前两步为预处理+有损压缩，第三、四步同样为预处理+有损压缩。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/10.png)

1. 色彩空间转换（预处理）
2. 下采样（有损压缩）
3. 分块和离散余弦变换（预处理）
4. 量化（有损压缩）
5. 编码
6. 存储

在整个压缩过程中会进行两次预处理和有损压缩，分别是第1、2步和第3、4步。其他步骤与图像质量之间的关系不大，所以我这里就只介绍这两次的预处理和压缩。

#### 第一次预处理和压缩（色彩空间转换和下采样）

我们设计师平常接触到的 "RGB" 或 "CMYK" 色彩空间，一个字母代表一种颜色，比如 "RGB" 意味着 "红绿蓝"，"RGB" 的色值代表红色、蓝色、绿色分别占多少。

而压缩工具拿到 JPG 图片后，会先将图片转换为一个叫 "YCbCr" 的色彩空间。其中 "Y" 代表了这张图片的亮度信息，而 "Cb/Cr" 分别代表图片中蓝色和红色与亮度 "Y" 的差值。经过这种转换，可以针对性地保留更多的亮度信息，而减少色度信息。

简单来说就是能够让人眼难以感知到的方式来减少图像中的色彩信息，减少图片文件体积。

![色彩空间转换示意图：左侧 RGB 色彩空间由红、绿、蓝三个通道叠加合成彩色图像；右侧 YCbCr 色彩空间将图像拆分为亮度通道 Y（灰度图）和色度通道 Cb、Cr，同样可合成彩色图像。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/11.png)

色彩空间转换之后，会进行一个叫 "下采样" 的压缩动作。维持亮度信息的同时，统一处理每个 2x2 的像素区块的色度信息（比如在一个 2x2 区块内 4 个像素在色彩上会被统一处理，看起来拥有相同的色度，但明度是不同的）

![下采样示意图：一张 2×3 的灰度图（各像素明度不同）与一张 2×2 的色度图（左黄右紫）相乘后，输出图像保留了各像素的明度差异，但同一色块内的色度被统一处理。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/12.png)

#### 第二次预处理和压缩（分块、离散余弦变换和量化）

分块、离散余弦变换指的是会将图像分成多个 8*8 像素的色块，然后将其从像素域转换成频率。转换成频率域的意思是能够让电脑分辨图像中的：

1. 高频区域：颜色变化剧烈的部份，如色块、文字的边缘；
2. 低频区域：颜色变化平缓的部份，如下图所示的黄色渐变。

![离散余弦变换示意图：一张 Flash Sale 促销横幅经变换后，分离出低频区域（黄色玩具的渐变色块）和高频区域（"now"文字与红色背景的 sharp 边缘），说明算法可区分图像中平缓与剧烈的色彩变化区域。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/13.png)

而量化则是利用了人类视觉对于图像中的高频变化不是很敏感这一点，通过减少高频区域的数据量，同时在低频区域保持一定精度，让人感觉到图片仍然很清晰。

简单来说，就是压缩算法知道图像里哪些部分的色彩过渡比较缓和，哪些部分的色彩过渡是强烈的，然后对色彩过渡比较强烈的部份使用较高的压缩率。

#### 结论

所以正如前面对比分析时看到的结果那样，JPG 图片对于色彩丰富的图片的压缩效果比较好，因为 JPG 的压缩算法会根据人眼的特点来优化图片的不同区域。

### PNG 图片压缩过程

PNG 图片的的压缩过程主要有以下几步，其中只有前三步对图像画质有影响，这里只介绍前三步：

1. 量化（有损压缩）
2. 过滤器选择（预处理）
3. DEFLATE 压缩（无损压缩）
4. 合成输出

![PNG 图片压缩流程示意图：量化（有损压缩）→ 过滤器预处理 → DEFLATE 压缩 → 合成输出，其中量化属于有损压缩，过滤器预处理与 DEFLATE 压缩共同构成预处理加无损压缩阶段。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/14.png)

#### 量化

第一步的量化是根据图像的需求选择合适的颜色类型和位深度，简单来说就是直接减少图片的颜色数量。这是最直接有效的压缩方式，同时也对图像质量损耗较大。
下图可以看到一个图像从 24 位（能储存 1677 万种颜色，又称真彩色）减少到 8 位色（能储存 256 种颜色，又称索引色）时，会出现色带现象 (Color Banding)

![颜色量化对比：左侧 PNG 24 位（真彩色）球体色彩过渡自然；右侧 PNG 8 位（索引色）球体出现明显色带现象，颜色层次感丧失，边缘过渡生硬。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/15.png)

#### 过滤器选择和 DEFLATE 压缩

这一步才是 PNG 图片的无损压缩。首先会先扫描 PNG 图片的每一行像素，然后以一种新的方式计算每个像素格子的颜色值。比如一个叫 "Sub" 的过滤器，每个像素值是通过当前像素值减去该像素左边像素值得到的；一个叫 "Average" 的过滤器，每个像素值是通过当前像素值减去当前像素左边和上方像素值的平均值得到的。

而 DEFLATE 压缩，这里会用到的方式有很多，比如 LZ77 编码和哈夫曼编码，这里不展开说明了，简单来说就是对过滤过的数据以更优的方式编码，达到减少文件大小的目的。

#### 结论

基于上文提到的过滤器，不难想象到这种无损压缩的方式对于颜色分明的图片——比如纯色图标，App 界面截图，扁平插画等——很有用，因为像素之间存在细微差异的地方不多，画面上都是大色块居多。

## 三、其他解决方案

前面提到了很多跟图像压缩相关的事情，这些都是与网页加载优化息息相关的。正好我前段时间做了一个需求，我让前端帮忙做了一件事来节省了大量的图片素材，也算是一次网页加载优化的小案例。

我的设计方案里需要用到八种主题色来作为对卡片的区分，然后我会给这八种主题色的卡片提供一个有简单渐变图像的背景图用以装饰画面，让其过渡不太生硬。设计稿如下图：

![数据看板首页设计稿截图，展示八个卡片模块排列成两行四列的网格布局，每个卡片顶部分别使用蓝、绿、紫、红、青、橙、粉、金黄八种不同主题色作为装饰色条加以区分。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/16.png)

如果按常规的做法和给予上文的调研，我将要提供八张代表不同颜色主题且经过压缩的 JPG 图片给到前端。但是在实际工作中，我只提供了一张灰色的背景图，然后让前端帮忙用 CSS 的颜色叠加 "Screen" 方式来给这张灰色图片上色，达到的效果是与设计稿一模一样的。

以下面这张图来举例。我先提供一个灰色的素材图，里面只有黑和白之间的明度变化，然后前端会写一个颜色块在这个图片上面，最后使用 CSS 属性 `background-blend-mode: screen;` 将这张灰色的图片和色块进行叠加，得到了与主题色对应的背景图。

![示意图展示 CSS screen 混合模式原理：一张灰色明度素材图与蓝、绿、粉三种纯色色块叠加后，分别生成对应主题色的彩色纹理背景图，一张素材可替代多张彩色图片。](https://lrdim.oss-accelerate.aliyuncs.com/blogimg/2024-12-10/17.png)

最终我仅用一张素材图实现了原本需要八张素材图才能实现的效果，成就感满满！

---

## 总结

这次做的调研确实打破了我从业以来多年的错误观念，现在我清晰地知道了：

1. JPG 和 PNG 适合储存的图像是不一样的；
2. JPG 和 PNG 的压缩算法导致了图片在压缩后的表现不一样。

虽然这些跟设计技能无关，但也算是一种视野的开拓吧。

这次的分享会是从一个 UI 设计师的角度去探索的，实际上我在 SHEIN 的工作更多是以交互设计师的角色去完成的，我已经有计划在之后的文章中分享更多交互设计的案例，读者们敬请期待吧。