PNG 文件格式详解¶
PNG(Portable Network Graphics)是一种 无损压缩 的位图图像格式,常用于网页与图像处理。PNG 通过“签名 + 多个数据块(Chunk)”来组织整个文件,具备透明度、伽马/色彩信息、可扩展元数据等特性。
1. PNG 文件整体结构¶
PNG 文件从 8 字节签名 (Signature)开始,之后由若干个 Chunk 顺序组成,最后以 IEND 结束。
常见结构如下:
┌──────────────────────┐
│ PNG Signature (8B) │
├──────────────────────┤
│ IHDR (必须, 第一个) │
├──────────────────────┤
│ PLTE (可选/条件必须) │
├──────────────────────┤
│ IDAT (必须, 可多个) │
├──────────────────────┤
│ ... (可选 chunks) │
├──────────────────────┤
│ IEND (必须, 最后一个) │
└──────────────────────┘
注意:IHDR 必须是第一个 Chunk,IEND 必须是最后一个 Chunk。
2. 文件头:PNG 签名(File Header / Signature)¶
每个 PNG 文件都以固定的 8 字节开头:
含义(常见解释):
89:用于检测是否为二进制文件(避免被当作文本传输)50 4E 47:ASCII 字符"PNG"0D 0A:CRLF(DOS/Windows 风格换行)1A:DOS 结束符(历史兼容)0A:LF(Unix 风格换行)
3. 块(Chunk)通用格式(核心)¶
PNG 的数据以 Chunk 为单位组织,每个 Chunk 都遵循相同结构:
┌──────────────┬──────────────┬──────────────┬──────────────┐
│ Length (4B) │ Type (4B) │ Data (N bytes)│ CRC (4B) │
└──────────────┴──────────────┴──────────────┴──────────────┘
3.1 Length(长度,4 字节)¶
- 大端序(Big-endian)的无符号整数
- 表示 Data 字段的字节数 N
- 不包含 Type 与 CRC 的长度
3.2 Type(类型码,4 字节)¶
- 4 个 ASCII 字符,例如:
IHDR、IDAT、IEND、PLTE - 通过大小写还可表达额外语义(例如是否“关键块/辅助块”等),但一般解析时先按字面类型处理即可
3.3 Data(数据,变长 N 字节)¶
- 具体内容由 Type 决定
- 例如 IHDR 固定 13 字节,IEND 为 0 字节
3.4 CRC(校验,4 字节)¶
- CRC32 校验值
- 计算范围:Type + Data(不包括 Length)
- 用于检测块数据是否被破坏
4. 关键 Chunk 详解(必须掌握)¶
4.1 IHDR(Image Header,图像头,必须且第一个)¶
IHDR 的 Data 固定为 13 字节,包含图像的全局信息:
| 字段 | 大小 | 含义 |
|---|---|---|
| width | 4B | 宽度(像素) |
| height | 4B | 高度(像素) |
| bit_depth | 1B | 位深(½/4/8/16) |
| color_type | 1B | 颜色类型 |
| compression | 1B | 压缩方法(PNG 中固定为 0) |
| filter | 1B | 滤波方法(固定为 0) |
| interlace | 1B | 隔行方式(0 无;1 Adam7) |
color_type(颜色类型)常见取值:
- 0:灰度(Grayscale)
- 2:真彩色(Truecolor / RGB)
- 3:索引色(Indexed-color)
- 4:灰度 + Alpha
- 6:RGB + Alpha
4.2 PLTE(Palette,调色板,索引色时必须)¶
PLTE 的 Data 由若干个 RGB 三元组组成:
- 每个条目 3 字节:
R G B - 条目数 =
Data长度 / 3
一般规则:
- 当 color_type = 3(索引色)时,PLTE 通常是必须的
- 对于真彩/灰度,PLTE 可选但不常用
4.3 IDAT(Image Data,图像数据,必须,可多个)¶
- IDAT 保存的是**压缩后的像素数据流**
- PNG 允许出现 多个 IDAT:逻辑上等同于把它们的 Data 直接拼接,再作为一个整体解压
- 压缩算法为 DEFLATE(zlib 封装)
解压后的数据不是“直接像素”,而是“按扫描行组织 + 每行带滤波类型字节”的原始图像数据。
4.4 IEND(Image End,文件尾,必须且最后一个)¶
- IEND 的 Data 长度为 0
- 只用于标记 PNG 数据结束
5. 常见可选 Chunk(了解即可)¶
5.1 tEXt(文本信息)¶
- 保存键值风格的文本元数据(例如作者、说明)
- 数据结构通常为:
keyword\0text
5.2 gAMA(伽马值)¶
- 保存伽马校正信息(整数表示:gamma × 100000)
5.3 tRNS(透明度,针对非 alpha 颜色类型补充透明信息)¶
- 对索引色:为调色板条目提供 alpha 数组
- 对灰度:提供一个“完全透明的灰度值”
- 对真彩:提供一个“完全透明的 RGB 值”
6. PNG 压缩与滤波(为什么 IDAT 前要滤波)¶
PNG 为了提高压缩率,会先对每条扫描行做滤波(Filtering),再对滤波后的结果做 DEFLATE 压缩。
滤波类型(每行开头 1 字节):
0None:不滤波1Sub:与左侧像素差分2Up:与上方像素差分3Average:与(左 + 上)平均差分4Paeth:Paeth 预测器差分
7. 小结(快速记忆)¶
- 文件头:固定 8 字节签名
89 50 4E 47 0D 0A 1A 0A - 块格式:
Length(4) + Type(4) + Data(N) + CRC(4) - 必须块:
IHDR(第一)、IDAT(至少一个)、IEND(最后) - 常见可选块:
PLTE / tEXt / gAMA / tRNS ...