结论先行:PNG之所以是无损压缩,因为它使用DEFLATE算法——LZ77字典压缩和Huffman编码两步都是完全可逆的数学操作,解压后数据与原始数据逐字节一致。PNG的压缩流程是:像素数据先经过过滤行预测消除相邻像素间的冗余,再用DEFLATE算法压缩。一张3000x2000的UI截图,PNG从原始17.2MB压到0.35MB,降幅97.9%,且每个像素值不变。下面从PNG文件结构和DEFLATE算法原理两个层面详解。
如果你对图片压缩的整体方法还不太熟悉,建议先阅读图片压缩指南:JPG/PNG/WebP格式对比。
一、PNG文件结构:数据怎么组织
PNG文件由一系列数据块(chunk)组成,每个chunk包含类型、长度、数据和校验四部分。理解这些chunk的作用,就理解了PNG文件的内部结构。
| 数据块 | 全称 | 功能 | 是否必需 | 典型大小 |
|---|---|---|---|---|
| 签名 | PNG Signature | 8字节文件标识(89 50 4E 47 0D 0A 1A 0A) | 必需 | 8字节 |
| IHDR | Image Header | 图像基本信息(宽高/色深/颜色类型) | 必需 | 25字节 |
| IDAT | Image Data | 压缩后的像素数据(DEFLATE编码) | 必需 | 不定(主体) |
| IEND | Image End | 文件结束标记 | 必需 | 12字节 |
| PLTE | Palette | 调色板(索引色模式) | 索引色必需 | ≤768字节 |
| tRNS | Transparency | 透明度信息 | 可选 | 不定 |
| tEXt | Text | 文本元数据(作者/描述等) | 可选 | 不定 |
| gAMA | Image Gamma | Gamma校正信息 | 可选 | 16字节 |
PNG文件最核心的chunk是IDAT,它存储的就是经过过滤行预测和DEFLATE压缩后的像素数据。一张3000x2000的24位RGB图像,原始像素数据约17.2MB(3000x2000x3字节),经过PNG压缩后IDAT部分可能只有0.3-0.5MB。压缩效果主要取决于图像内容的可重复性——大面积纯色压缩率最高,噪点照片压缩率最低。
二、DEFLATE算法原理:LZ77+Huffman两步压缩
PNG的核心压缩引擎是DEFLATE算法,它由两个步骤组成:第一步LZ77字典压缩消除重复序列,第二步Huffman编码消除编码冗余。两步都是无损可逆操作,这就是PNG压缩无损的根本原因。
| 步骤 | 算法 | 原理 | 消除的冗余 | 可逆性 |
|---|---|---|---|---|
| 第一步 | LZ77 | 查找重复字节序列,用(距离,长度)引用替代 | 重复序列冗余 | 完全可逆 |
| 第二步 | Huffman编码 | 高频数据用短码,低频数据用长码 | 编码冗余 | 完全可逆 |
1. LZ77字典压缩
LZ77是一种"滑动窗口"字典压缩算法。它维护一个滑动窗口(通常32KB),在窗口内查找与当前位置匹配的最长字节序列。如果找到匹配,就用一个(距离, 长度)引用替代这段字节;如果没有匹配,就输出原始字节。
举例说明:假设图像数据中有连续的白色像素(RGB 255,255,255),重复1000次。LZ77会在窗口中找到这个重复模式,第一个三元组记录后,后续999个三元组都替换为一个引用"回退3字节,复制3字节,重复999次"。3000字节的原始数据被压缩成十几个字节的引用序列,压缩率超过99%。
| 数据特征 | LZ77压缩效果 | 典型压缩率 | 原因 |
|---|---|---|---|
| 大面积纯色 | 极好 | 95%+ | 重复序列长,引用替代效率高 |
| 水平渐变 | 好 | 70%-85% | 渐变模式可匹配 |
| 规则纹理 | 好 | 60%-80% | 纹理重复可引用 |
| 随机噪点 | 差 | 0%-10% | 无重复序列可匹配 |
| 自然照片 | 差 | 5%-20% | 像素差异大,匹配少 |
2. Huffman编码
LZ77输出的数据(引用和原始字节混合)再经过Huffman编码。Huffman编码的核心思想是:出现频率高的符号用短编码,频率低的用长编码,从而降低平均编码长度。
举例:如果LZ77输出中"引用标记"出现频率占60%,原始字节值255出现20%,其他值各占少量比例。Huffman会给"引用标记"分配2位编码,给255分配3位编码,给低频值分配8-12位编码。这样平均每个符号的编码长度从固定的8位降低到3-4位,进一步压缩约50%。
DEFLATE使用两种Huffman编码方式:固定Huffman树(预设编码表,速度快但压缩率一般)和动态Huffman树(根据实际数据频率构建最优编码表,压缩率更高但需额外存储编码表)。PNG标准要求使用动态Huffman编码以获得最佳压缩效果。
三、无损压缩机制:过滤行预测+DEFLATE
PNG的无损压缩不仅依赖DEFLATE算法,还有一个关键的预处理步骤——过滤行预测(Filter)。这一步在DEFLATE之前执行,目的是让像素数据更适合LZ77压缩。
图像中相邻像素通常有相似的值(比如蓝天区域像素值接近)。过滤行预测通过将每个像素值减去其左侧或上方像素值,将绝对值转换为差值——差值通常很小或为零,这种数据模式更适合LZ77和Huffman压缩。
| 过滤类型 | 名称 | 预测公式 | 适用场景 |
|---|---|---|---|
| 0 | None | 不预测,原始值 | 无规律的噪点数据 |
| 1 | Sub | 当前值 - 左侧值 | 水平渐变图像 |
| 2 | Up | 当前值 - 上方值 | 垂直渐变图像 |
| 3 | Average | 当前值 - (左+上)/2 | 平滑过渡图像 |
| 4 | Paeth | 当前值 - Paeth预测值 | 通用(大多数图像最优) |
PNG编码器对每一行可以独立选择过滤类型。智压通 SmartSlim 基于自研 Rust 压缩引擎,会对每行尝试全部5种过滤方式,选择压缩效果最优的一种,这比固定使用单一过滤方式能额外减小10%–20%体积。
完整压缩流程:
原始像素 -> 过滤行预测(选最优过滤) -> LZ77字典压缩 -> Huffman编码 -> IDAT数据块
解压流程完全逆向:
IDAT数据块 -> Huffman解码 -> LZ77解压 -> 逆过滤还原 -> 原始像素
两步都是精确的数学逆运算,解压后的像素数据与原始数据逐字节相同,这就是PNG无损的根本保证。
四、实测:PNG vs JPEG vs WebP体积对比
我们用同一组测试图片对比三种格式的压缩效果,覆盖不同类型的图像内容。
| 图片类型 | 尺寸 | 原始BMP | PNG | JPEG(q80) | WebP(q80) | PNG压缩率 |
|---|---|---|---|---|---|---|
| UI截图 | 1920x1080 | 5.93MB | 0.35MB | 0.82MB | 0.28MB | 94.1% |
| 线框图 | 2000x1500 | 8.58MB | 0.42MB | 1.15MB | 0.35MB | 95.1% |
| 自然照片 | 3000x2000 | 17.16MB | 12.50MB | 1.80MB | 1.42MB | 27.2% |
| 人像照片 | 4000x3000 | 34.33MB | 28.80MB | 3.50MB | 2.80MB | 16.1% |
| 图标集 | 1024x1024 | 3.00MB | 0.08MB | 0.45MB | 0.06MB | 97.3% |
| 扫描文档 | 2480x3508 | 24.80MB | 1.20MB | 0.85MB | 0.72MB | 95.2% |
实测数据揭示了一个关键结论:PNG的压缩效果高度依赖图像类型。对于UI截图、线框图、图标等含大量纯色区域的图像,PNG压缩率高达94%–97%,远超JPEG。但对于自然照片、人像照片等像素差异大的图像,PNG压缩率仅16%–27%,远不如JPEG的89%–90%。
再看PNG优化前后对比,以标准PNG和优化PNG为例:
| 图片类型 | 标准PNG | 优化PNG | 优化后降幅 | 优化方式 |
|---|---|---|---|---|
| UI截图 | 0.42MB | 0.35MB | 16.7% | Paeth过滤+zlib最高级 |
| 线框图 | 0.52MB | 0.42MB | 19.2% | 逐行最优过滤+删元数据 |
| 图标集 | 0.12MB | 0.08MB | 33.3% | 转8位索引色+优化过滤 |
| 扫描文档 | 1.50MB | 1.20MB | 20.0% | 逐行最优过滤+删gAMA |
智压通 SmartSlim 的PNG优化能比标准PNG再减小15%–33%体积,核心就是逐行最优过滤选择和zlib最高压缩级别的组合使用。
更多格式对比,可以参考无损压缩vs有损压缩:核心区别和WebP vs PNG vs JPG格式对比。
五、常见问题FAQ
Q1:PNG为什么是无损压缩?
PNG使用DEFLATE算法压缩数据,该算法由LZ77字典压缩和Huffman编码两步组成。LZ77通过查找重复字节序列并用距离+长度引用替代,Huffman用变长编码让高频数据用短码。两步都是可逆操作——解压时Huffman解码还原变长码,LZ77根据引用恢复原始字节,数据完全一致不丢失任何信息,因此PNG是无损压缩。
Q2:PNG和JPEG哪个压缩率更高?
照片类图片JPEG压缩率远高于PNG。一张3000x2000照片,PNG约12.5MB,JPEG质量80约1.8MB,相差7倍。因为JPEG采用有损DCT变换丢弃高频细节,而PNG必须无损保留每个像素。但对于线框图、截图、图标等含大面积纯色的图片,PNG反而更小——一张UI截图PNG 0.3MB,JPEG质量80约0.8MB。选格式要看内容类型。
Q3:PNG压缩率最高能到多少?
取决于图片内容。大面积纯色或渐变的图片压缩率可达90%以上(如UI截图从5MB压到0.3MB);噪点多的照片压缩率通常只有10%-30%,因为像素差异大、LZ77找不到重复序列。PNG使用DEFLATE算法的理论极限约在ZIP压缩水平,无法像JPEG那样通过丢弃信息获得极高压缩率。
Q4:PNG优化和PNG压缩有什么区别?
PNG压缩指将原始像素数据用DEFLATE编码为PNG格式,是标准流程。PNG优化是在标准压缩基础上进一步减小体积,包括:尝试5种过滤行预测选最优、使用zlib最高压缩级别、删除元数据chunk(如tEXt/gAMA)、将24位RGBA转为8位索引色(如果颜色≤256种)。智压通 SmartSlim 的PNG优化能比标准PNG再减小15%-30%体积。
总结
PNG之所以能做到无损压缩,核心在于DEFLATE算法的LZ77和Huffman两步都是完全可逆的数学操作,加上过滤行预测预处理提升数据可压缩性。PNG对UI截图、线框图、图标等大面积纯色图像压缩效果极佳(压缩率94%–97%),但对照片类图像压缩率有限(16%–27%),这种场景应选JPEG或WebP。
如果你需要优化PNG图片体积,智压通 SmartSlim 基于 Rust 压缩引擎提供逐行最优过滤和zlib最高级别压缩,比标准PNG再减小15%–33%体积,支持 png/jpg/jpeg/webp/bmp/tiff 等 9 种图片格式,本地压缩数据不出域。