png 图片格式笔记

前文

PNG 是一种采用无损压缩算法的位图格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。PNG 使用从LZ77派生的无损数据压缩算法,原则上会使用 zlib.deflate 将每个数据块的内容进行压缩。

按照标准可以把所有数据存储在一个大的 IDAT 块中,也可以分割存储在多个 IDAT 块中,这原本是为了编码解码时可控内存占用量而设计的,但没有考虑到并行解码,也就是说在对每一个 IDAT 块解压前并不会知道到其中包含了多少像素 。

而与此同时,PNG 也支持动图,即 APNG 格式。

APNG(Animated Portable Network Graphics)是一个基于PNG(Portable Network Graphics)的位图动画格式,扩展方法类似主要用于网页的GIF 89a,仍对传统PNG保留向下兼容。第1帧是标准的单幅PNG图像,因此只支持原版PNG的软件能正常显示第1帧。剩余的动画帧和帧速数据储存在符合原版PNG标准的扩展数据块里。

但目前来说 Chrome 59、Edge 12、Firefox 3、Opera 46 和 Safari 8 可以查看 APNG,但 Google 并不是很推崇 APNG 格式(他们比较推崇 webp 格式)。

我们可以使用 https://products.aspose.app/imaging/zh-hans/image-view 分离 APNG 的每一帧位图。

Signature - 文件签名

PNG Signature 大小为 8 bytes

十六进制描述为 89 50 4E 47 0D 0A 1A 0A

文件特征为 ‰PNG

Chunk - 数据块

名称 字节数 说明
Length (长度) 4 指定数据块中数据域的长度,其长度不超过 (\(2^{31}-1\)) 字节
Chunk Type Code (数据块类型码) 4 数据块类型码由 ASCII 字母 (A-Z 和 a-z) 组成
Chunk Data (数据块数据) Length 存储按照 Chunk Type Code 指定的数据
CRC (循环冗余检测) 4 存储用来检测是否有错误的循环冗余码

PNG 被分为一个个 Chunk,每个 Chunk 有相同的格式,但存放着不同的数据。

PNG 数据块

数据块符号 数据块名称 多数据块 可选否 位置限制
IHDR 文件头数据块 第一块
cHRM 基色和白色点数据块 PLTEIDAT之前
gAMA 图像γ数据块 PLTEIDAT之前
iCCP 辅助数据块 PLTE之后IDAT之前 (存在则无sRGB)
sBIT 样本有效位数据块 PLTEIDAT之前
sRGB 标准RPG颜色 PLTE之后IDAT之前 (与iCCP冲突)
PLTE 调色板数据块 IDAT之前
bKGD 背景颜色数据块 PLTE之后IDAT之前
hIST 图像直方图数据块 PLTE之后IDAT之前
tRNS 图像透明数据块 PLTE之后IDAT之前
oFFs (专用公共数据块) IDAT之前
pHYs 物理像素尺寸数据块 IDAT之前
sCAL (专用公共数据块) IDAT之前
IDAT 图像数据块 与其他IDAT连续
tIME 图像最后修改时间数据块 无限制
tEXt 文本信息数据块 无限制
zTXt 压缩文本数据块 无限制
fRAc (专用公共数据块) 无限制
gIFg (专用公共数据块) 无限制
gIFt (专用公共数据块) 无限制
gIFx (专用公共数据块) 无限制
IEND 图像结束数据 最后一个数据块

详情可查询 https://www.w3.org/TR/PNG/

APNG 数据块

数据块符号 数据块名称 多数据块 可选否 位置限制
acTL 动画控制块 IHDR之后
fcTL 帧控制块 IHDR之后
fdAT 帧数据块 IHDR之后

详情可查询 https://wiki.mozilla.org/APNG_Specification

IOS 特有的数据块

数据块符号 数据块名称 多数据块 可选否 位置限制
iDOT 并行解析数据块 IHDR之后IDAT之前

Apple 并未公开

IHDR

域的名称 字节数 说明
Width 4 图像宽度,以像素为单位
Height 4 图像高度,以像素为单位
Bit depth 1 图像深度,详情查看下表
Color type 1 颜色类型,详情查看下表
Compression method 1 压缩方法 (LZ77派生算法,原则上默认为 zlib.deflate)
Filter method 1 滤波器方法
Interlace method 1 隔行扫描方法:0则表示非隔行扫描 ;1则表示 Adam7
Color type 值 含义 Bit depth 值
0 灰度图像 1,2,4,8 或 16
2 真彩色图像 8 或 16
3 索引彩色图像 1,2,4 或 8
4 \(\alpha\)通道数据的灰度图像 8 或 16
6 \(\alpha\)通道数据的真彩色图像 8 或 16

IEND

一般来说,IEND 数据块的长度总是 0,十六进制描述总是:

00 00 00 00 49 45 4E 44 AE 42 60 82

iDOT

这是 Apple 为了 PNG 解码速度而做的一个优化 。苹果为了让 PNG 格式的图片可以并行解码并且兼容原本的 PNG 标准,把图片内容分为前半后半两部分,并把像素流分为多个 IDAT 块,然后在 PNG 文件里添加了一个 iDOT 辅助块,其中记录了前半后半的分隔位置(后半数据相对 iDOT 块的偏移值)和解压后的像素高度,这样用 Apple 的 PNG 编码器编码的 PNG 图片用 Apple 自家的 PNG 解码器解码就可以分为 2 个并行的过程,以此充分利用多核性能,同时这样的 PNG 图片也能被普通解码器解码。

但其存在一个 bug,详情可以查看文章:PNG有关iDOT块的笔记