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块的笔记