跳转至

PNG 文件格式详解

PNG(Portable Network Graphics)是一种 无损压缩 的位图图像格式,常用于网页与图像处理。PNG 通过“签名 + 多个数据块(Chunk)”来组织整个文件,具备透明度、伽马/色彩信息、可扩展元数据等特性。


1. PNG 文件整体结构

PNG 文件从 8 字节签名 (Signature)开始,之后由若干个 Chunk 顺序组成,最后以 IEND 结束。

常见结构如下:

┌──────────────────────┐
│ PNG Signature (8B)    │
├──────────────────────┤
│ IHDR (必须, 第一个)   │
├──────────────────────┤
│ PLTE (可选/条件必须)  │
├──────────────────────┤
│ IDAT (必须, 可多个)   │
├──────────────────────┤
│ ... (可选 chunks)     │
├──────────────────────┤
│ IEND (必须, 最后一个) │
└──────────────────────┘

注意:IHDR 必须是第一个 ChunkIEND 必须是最后一个 Chunk


2. 文件头:PNG 签名(File Header / Signature)

每个 PNG 文件都以固定的 8 字节开头:

89 50 4E 47 0D 0A 1A 0A

含义(常见解释):

  • 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 字符,例如:IHDRIDATIENDPLTE
  • 通过大小写还可表达额外语义(例如是否“关键块/辅助块”等),但一般解析时先按字面类型处理即可

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 字节):

  • 0 None:不滤波
  • 1 Sub:与左侧像素差分
  • 2 Up:与上方像素差分
  • 3 Average:与(左 + 上)平均差分
  • 4 Paeth: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 ...