PNG格式文件分析
一. 概述
PNG(Portable Network Graphics,便携式网络图形)是一种非常常见的图像存储格式,诞生于20世纪90年代,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。除了多数人所熟知的PNG支持透明背景这一特性,PNG格式更为重要的一点是其能在保证无损压缩的前提下,将文件体积减小到最小,此外对灰度图像和彩色图像分别提供了16 bit和48 bit深度,并且还可存储多达16 bit的α通道数据。
二. PNG文件结构
PNG文件由文件署名域(8字节)和最少3个数据块(Chunk)按照特定的顺序排列而成。
数据块分为两类:
- 关键数据块(Critical Chunk):必须包含的数据块。一个有效的PNG文件必须包含一个IHDR块、至少一个IDAT块和一个IEND块;
- 以及辅助数据块(Ancillary Chunk):可选的数据块。也就是说,编码器并不必须写入辅助数据块,解码器也可以选择忽略它们,但鼓励编码器在有相关数据时写入标准的辅助数据块、解码器在可行的条件下对这些内容进行解码。
每个数据块都包含4部分:
名称 | 长度 | 说明 |
---|---|---|
Length | 4字节 | 无符号整数,注意只表示Chunk Code部分的长度,允许为0,其值不超过 字节 |
Chunk type code | 4字节 | 标识该数据块的类型,由ASCII码的A-Z和a-z组成 |
Chunk data | 可变(应与Length值相等) | 存储指定数据,长度可为0 |
CRC | 4字节 | 循环冗余检测 |
三. PNG文件具体构成
1. PNG文件签名(PNG file signature)
文件的前8字节为PNG文件签名,便于计算机识别文件类型。PNG文件对应的标识为89 50 4E 47 0D 0A 1A 0A
。以一张带有透明背景的微信表情为例,使用Synalize it! Pro以二进制方式打开。其文件署名域可参见图2(紫色部分)。
下面将依次介绍各个数据块的结构。
2. 关键数据块
(1) IHDR chunk(Image Header chunk,文件头数据块)
IHDR必须为PNG文件的第一个数据块,它包含了一个PNG文件的基本信息。一个PNG数据流中只能有一个IHDR数据块。
IHDR由13字节组成:
名称 | 字节数 | 说明 |
---|---|---|
Width | 4字节 | 图像宽度(像素) |
Height | 4字节 | 图像高度(像素) |
Bit depth | 1字节 | 图像深度:表示每个采样点占用的bit数 索引(indexed)彩色图像:1,2,4或8; 灰度图像:1,2,4,8或16; 真彩色图像:8或16 |
Colour type | 1字节 | 颜色类型: 0:灰度图像, 深度为1,2,4,8或16 bit; 2:真彩色(truecolor)图像,深度为8或16 bit; 3:索引彩色图像,深度为1,2,4或8 bit; 4:带α通道数据的灰度图像,深度为8或16 bit; 6:带α通道数据的真彩色(truecolor with alpha)图像,深度为8或16 bit |
Compression method | 1字节 | 压缩方法: 0:LZ77派生算法(目前仅定义了0) 其他值:无效;为未来扩展的压缩方法预留 |
Filter method | 1字节 | 滤波器方法: 0(目前仅定义了0) 其他值:无效 |
Interlace method | 1字节 | 隔行扫描方法: 0:非隔行扫描; 1: Adam7隔行扫描方法 |
同样以图1为例,其IHDR字段如下:
由数据可知,该图像:
- Length:0x00 00 00 0D(13),表示IHDR块的Chunk data部分长度为13字节
- Chunk type code:0x49 48 44 52(ASCII码“IHDR”),标识该块类型
- Chunk data:
- Width:0x00 00 00 40(64)
- Height:0x00 00 00 40(64)
- Bit depth:8,表示8 bit深度
- Colour type:3,表示索引彩色图像
- Compression method:0
- Filter method:0
- Interlace method:0,非隔行扫描
- CRC:0x9D B7 81 EC
(2) PLTE chunk(Palette chunk,调色板数据块)
若PLTE块存在,必须要放在IDAT块之前,且只能有1个此块。
PLTE块包含有与索引彩色图像 (indexed-colour image) 相关的彩色变换数据,包含1—256个调色板信息,其中每条信息由8 bit表示:
颜色 | 长度 | 含义 |
---|---|---|
Red | 1字节 | 0 = 黑,255 = 红 |
Green | 1字节 | 0 = 黑,255 = 绿 |
Blue | 1字节 | 0 = 黑,255 = 蓝 |
调色板的作用在于,使得图像深度较小的图像,可以使用索引号来正确表示颜色。
PLTE块还必需满足以下限制条件,否则会被判定为不合法:
-
调色板的长度应为3的倍数,即PLTE块最大字节数为256 × 3 = 768 B;
-
调色板信息的数量不能超过图像深度可以表示的范围(如对于4 bit深度的图像,最多有16条调色板信息,但允许少于16条);
-
对于Colour type 3的PNG图像(索引图像),PLTE块是必需的,此时调色板的颜色索引从0开始编号,然后是1,2……;
对于Colour type为2和6的图像,PLTE块是可选的,此时调色板将提供一个1—256的建议颜色集,以便软件或屏幕不支持显示真彩色时量化真彩色图像;
Colour type为0和4的图像中不能出现PLTE块。
仍以图1为例,其PLTE块为:
其中:
-
Length:0x00 00 02 04(516),表示PLTE块的数据部分有516字节(是3的倍数)
-
Chunk type code:0x50 4C 54 45(ASCII码“PLTE”)
-
Chunk data:例如,
-
第0种颜色,0x 00 00 00,即 ;
-
第1种颜色,0x B9 81 3F,即 ;
-
第100中颜色,0xFF FF DD,即 (一种接近于白色的颜色)。现在将其修改为0x00 00 00(纯黑色),结果为:
图1-4 修改了调色板之后的[机智]表情这与预想的结果一致;
-
-
CRC:0x5A 89 F7 7C
(3) IDAT chunk(Image data chunk,图像数据块)
IDAT块包含实际的图像数据。此外:
- 允许编码器根据需要将压缩的数据流分为多个IDAT块,但它们必须连续出现;
- 并不限定IDAT块的大小,但过短的IDAT块会浪费更多空间;
- IDAT块可以出现在压缩数据流的任何位置。
(4) IEND chunk(Image trailer chunk,图像结束数据块)
IEND块必需出现在文件的末尾,用来标志PNG数据流的结束。该数据块的数据字段是空的。例如图1的IEND块为:
可以看出,其只包含Length(0)、Chunk Type Code(IEND)和CRC(0xAE 42 60 82)。
3. 辅助数据块
辅助数据块主要包含以下4类、14种:
-
表示透明信息(Transparency information)的数据块:tRNS chunk(Transparency chunk,透明信息数据块)
-
表示色彩空间信息(Colour space information)的数据块:
- gAMA chunk(Image gamma chunk,图像γ数据块)
- cHRM chunk(Primary chromaticities chunk,基色和白色度数据块)
- sRGB chunk(Standard RGB colour space chunk,标准RGB色彩空间数据块)
- iCCP chunk(Embedded ICC profile chunk)
-
表示文本信息(Textual information)的数据块:
- tEXt chunk(Textual data chunk,文本信息数据块)
- zTXt chunk(Compressed textual data chunk,压缩文本数据块)
- iTXt chunk(International textual data chunk)
-
表示其他信息(Miscellaneous information)的数据块:
-
bKGD chunk(Background colour chunk,背景颜色数据块)
-
pHYs chunk(Physical pixel dimensions chunk,物理像素尺寸数据块)
-
sBIT chunk(Significant bits chunk,样本有效位数据块)
-
sPLT chunk(Suggested palette chunk)
-
hIST chunk(Palette histogram chunk,图像直方图数据块)
-
tIME chunk(Image last-modification time chunk,图像最后修改时间数据块)
-
下面就几个问题,简要介绍其中几个辅助数据块。
(1) 如何将PNG部分呈现为“透明”?——tRNS chunk
Colour type为0、2或3的PNG图像(索引彩色图像)通过且tRNS块来显示透明信息,而Colour type为4或6的PNG图像(带α通道数据的灰度/真彩色图像)不需要此数据块就可以显示透明信息(直接从IDAT块的数据中提取α分量)。
如果存在tRNS块,则必须位于第一个IDAT块之前、PLTE块之后(若存在)。
对于Colour type 3的索引彩色图像(如下图),tRNS块包含了一系列对应于PLTE块信息的单字节α值(通常在这种情况下,图像中不包含完整的α通道)。α值与8 bit全α通道具有相同的含义: 0表示完全透明,255表示完全不透明,且与图像位深度无关。tRNS块所包含的α值不能超过调色板信息条数,但可以少于,在这种情况下,其余调色板条目的α值为255。
(2) 辅助颜色管理——sRGB chunk、gAMA chunk、cHRM chunk
除了使用PLTE块,PNG文件还可以使用sRGB进行颜色识别和颜色管理。
如果存在sRGB块,则图像样本符合sRGB色彩空间[IEC 61966-2-1]。
sRGB块的Chunk data部分只有1个字节:
名称 | 长度 | 说明 |
---|---|---|
Rendering intent | 1字节 | 0:Perceptual,用于牺牲色度精度以更好地适应输出设备的图像,例如照片; 1:Relative colorimetric,用于需要颜色外观匹配(相对于输出设备白点)的图像,例如标志; 2:Saturation,用于牺牲亮度和色相以保持合适的饱和度的图像,例如图表和图形; 3:Absolute colorimetric,用于需要保留绝对色度的图像,例如用于其他输出设备的图像预览(校样)。 |
例如对于下面的照片(图2),其sRGB块如图2-1所示:
其Chunk data部分为0x00(照片)。
标准中还建议,编码器除了写入sRGB块外,还写入gAMA块(以及可选的cHRM块),以便与不使用sRGB块的PNG解码器兼容。当sRGB块存在时,标准建议能对其识别并进行颜色管理的解码器忽略gAMA和cHRM块,而改用sRGB块。
gAMA块和cHRM块的Chunk data部分只能取以下值:
数据块 | Chunk data的取值(十进制) |
---|---|
gAMA | 45455 |
cHRM | White point x:31270 White point y:32900 Red x:64000 Red y:33000 Green x:30000 Green y:60000 Blue x:15000 Blue y:6000 |
(3) 如何表示物理分辨率?——pHYs chunk
pHYs块的Chunk data由三部分构成:
名称 | 长度 | 说明 |
---|---|---|
Pixels per unit, X axis | 4字节 | |
Pixels per unit, Y axis | 4字节 | |
Unit specifier | 1字节 | 0:单位未知 1:单位为米 |
例如,图2的pHYs块如下图所示:
从中可知,该图像水平、垂直方向上的物理分辨率(像素密度)均为2835(0x00 00 0B 13)像素/米。
(4) 如何在PNG中存储EXIF信息?——eXIf chunk
EXIF,可交换图像文件格式,是专门为数码相机拍摄的照片所设定的,用于记录照片属性信息和拍摄参数的数据。
但eXIf块并不在[前面所列出的14种辅助数据块的范围](#3. 辅助数据块)中。实际上,辅助数据块允许编码器自定义,例如图2的该数据块为:
从中我们可以看出一些图像元数据,例如:
- 拍摄设备:Apple iPhone XR
- 镜头:Apple iPhone XR back camera 4.25 mm ƒ/1.8
- 拍摄时间:2019.12.16 10:07:12
四. 参考文献
Portable Network Graphics (PNG) Specification (Second Edition)