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 基色和白色点数据块 否 是 在PLTE和IDAT之前
gAMA 图像γ数据块 否 是 在PLTE和IDAT之前
iCCP 辅助数据块 是 是 在PLTE之后IDAT之前 (存在则无sRGB)
sBIT 样本有效位数据块 否 是 在PLTE和IDAT之前
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块的笔记