另见 译本。
版权所有 © 1996-2025 万维网联盟 (W3C)。W3C® 的免责声明、商标以及宽松文档许可规则适用。
本文件描述了 PNG(便携式网络图形),这是一种用于无损、便携、高压缩存储静态和动画光栅图像的可扩展文件格式。PNG 为 GIF 提供了免专利替代方案,并可替代 TIFF 的许多常见用途。它支持索引色、灰度和真彩色图像,并可选择添加 Alpha 通道。采样深度范围为 1 到 16 位。
PNG 设计旨在良好适用于在线浏览应用程序(如万维网),因此它具有完全的可流式传输性,并包含渐进式显示选项。PNG 非常稳健,提供完整的文件完整性检查和简单常见的传输错误检测。此外,PNG 可以存储色彩空间数据,以改善在异构平台上的色彩匹配效果。
本规范定义了两种互联网媒体类型:image/png 和 image/apng。
本节描述了本文档发布时的状态。当前的 W3C 出版物列表及本技术报告的最新修订版可在 W3C 标准与草案索引(网址:https://w3org.cn/TR/)中找到。
本规范旨在成为一项国际标准,但目前尚未达成。将本规范称为“国际标准”是不恰当的。
本文件由 便携式网络图形 (PNG) 工作组 作为推荐标准发布,遵循 推荐标准轨道。
W3C 推荐标准是一项经由广泛共识,由 W3C 及其成员背书,且工作组成员承诺为其实施提供免版税许可的规范。
W3C 建议将本规范广泛部署为 Web 标准。
本文件由遵循 W3C 专利政策 的工作组制作。W3C 维护着一份 与该工作组交付成果相关的专利披露公开列表;该页面还包含专利披露的说明。任何拥有专利实际知识且认为该专利包含 必要权利要求 (Essential Claim) 的个人,必须根据 W3C 专利政策第 6 节披露相关信息。
本文档受 2023 年 11 月 3 日 W3C 流程文档 管辖。
本规范的设计目标是:
本规范规定了一种数据流及其相关文件格式——便携式网络图形(PNG,发音为“ping”),用于通过互联网传输无损、便携、压缩的个人计算机图形图像或基于帧的动画。
就本规范而言,适用以下定义。
色度是衡量颜色质量的指标,与其亮度无关。
前景图像被称为相对于背景进行了合成。
来源:[RFC1951]
软件通过将图像加载到帧缓冲区中,使图像出现在屏幕上。
0 和 2位深 - 1 的图像。亮度和色度共同完整定义了测量出的颜色。有关正式定义,请参阅 [COLORIMETRY]。
0 和 2位深 - 1 的图像。PNG 中仅可使用 RGB,不支持 ICtCp。
限制在 0 到 231-1 范围内的四字节无符号整数。
实施此限制是为了适配那些处理无符号四字节值有困难的编程语言。
网络字节序下的双字节无符号整数。
标准动态范围与原色无关,因此也与色域无关。PNG 支持宽色域 SDR 格式。
DEFLATE 风格的压缩方法。
来源:[rfc1950]
也指包含此方法示例实现的库的名称。
一种旨在检测大多数传输错误的校验值类型。
解码器计算接收数据的 CRC,并通过将其与编码器计算并附加到数据上的 CRC 进行比较来进行校验。不匹配表示数据或 CRC 在传输过程中已损坏。
所有 PNG 图像都包含单个静态图像。
某些 PNG 图像——称为动画 PNG (APNG)——还包含基于帧的动画序列,即动画图像。动画的第一帧可以是(但不一定是)静态图像。不支持动画的显示设备(如打印机)将显示静态图像,而不是动画序列。
本规范指定了 PNG 数据流,并对生成 PNG 数据流的 PNG 编码器、解释 PNG 数据流的 PNG 解码器,以及将一个 PNG 数据流转换为另一个的 PNG 编辑器提出了一些要求。它没有指定应用程序与 PNG 编码器、解码器或编辑器之间的接口。图像呈现给编码器或由解码器输出的具体形式未作规定。区分了四种图像。
这四种图像之间的关系如图 1 所示。
采样、通道、像素和采样深度之间的关系如图 2 所示。
颜色采样所在的 RGB 色彩空间可以通过以下四种方式之一指定:
对于高端应用,前两种方法提供了最大的灵活性和控制力。第三种方法能够指示一种特定但极其常见的色彩空间。第四种方法在 ICC 配置文件被广泛采用之前就已标准化,它允许指定 RGB 数据的精确色度,以及要应用的伽马校正(见 C. 伽马和色度)。然而,色彩感知应用程序会倾向于前三种方法中的一种,而色彩无感知应用程序通常会忽略所有四种方法。
表 1 是提供色彩空间信息的数据块类型列表,每个数据块都关联有一个优先级数字。如果单个图像包含不止一种这些数据块类型,则优先级数字最小的数据块应优先,更高数字的数据块类型应被忽略。
| 数据块类型 | 优先级 |
|---|---|
| cICP | 1 |
| iCCP | 2 |
| sRGB | 3 |
| cHRM 和 gAMA | 4 |
伽马校正不应用于 Alpha 通道(如果存在)。Alpha 采样始终为全范围,表示完全不透明度的线性分数。
还可以提供母版制作元数据。
参考图像在被编码为 PNG 图像前,需进行若干转换(见 3)。转换按以下顺序应用,方括号表示该转换是可选的:
[alpha separation]
indexing or ( [RGB merging] [alpha compaction] )
sample depth scaling
当每个像素要么完全透明要么完全不透明时,Alpha 分离、Alpha 压缩和索引化转换可能导致恢复的参考图像具有与原始参考图像不同的 Alpha 采样深度,或者完全没有 Alpha 通道。这对任何像素的不透明度都没有影响。这两个参考图像被视为等效,转换被视为无损。尽管如此,希望保留 Alpha 采样深度的编码器可以选择不执行会改变 Alpha 采样深度的转换。
如果参考图像中的所有 Alpha 采样都具有最大值,则可以省略 Alpha 通道,从而得到一个可以更紧凑编码的等效图像。
如果不同像素值的数量为 256 或更少,RGB 采样深度不大于 8,且 Alpha 通道缺失、恰好为 8 位深,或者每个像素要么完全透明要么完全不透明,那么通过索引化转换实现的替代索引色表示在编码时可能更有效。在索引色表示中,每个像素被替换为调色板的索引。调色板是包含三个 8 位采样(红、绿、蓝)的条目列表。如果存在 Alpha 通道,则还有一个平行的 8 位 Alpha 采样表,称为Alpha 表。
即使 PNG 图像不是索引色,也可以构建一个或多个建议调色板,以辅助只能显示有限数量颜色的查看器。
对于索引色图像,编码器可以重新排列调色板,使得具有最大 Alpha 值的表条目被分组在末尾。在这种情况下,表可以以不包含这些条目的缩短形式进行编码。
创建索引色 PNG 的编码器不得插入大于调色板表实际长度的索引值;这样做是错误的,解码器对该错误的处理方式各不相同。
如果红、绿、蓝通道具有相同的采样深度,并且对于每个像素,红、绿、蓝采样值相等,则这三个通道可以合并为单个灰度通道。
对于非索引图像,如果存在某种 RGB(或灰度)值,使得所有具有该值的像素都是完全透明的,而所有其他像素都是完全不透明的,则可以通过仅识别该透明的 RGB(或灰度)值来更紧凑地表示 Alpha 通道。
在 PNG 图像中,并非支持所有采样深度(见 6.1 颜色类型和值),且所有通道必须具有相同的采样深度。PNG 图像的所有通道使用不小于参考图像中任何采样深度的最小允许采样深度,参考图像中的可能采样值被线性映射到 PNG 图像的下一个允许范围内。图 5 展示了深度为 3 的采样如何映射到深度为 4 的采样。
仅允许少量采样深度减少了解码器需要处理的情况。采样深度缩放是可逆且无数据丢失的,因为参考图像采样深度可以记录在 PNG 数据流中。在没有记录采样深度的情况下,参考图像采样深度等于 PNG 图像采样深度。见 12.4 采样深度缩放 和 13.12 采样深度重新缩放。
参考图像的转换产生五种 PNG 图像类型之一(见 图 6):
每个像素的格式取决于 PNG 图像类型和位深。对于除索引色以外的 PNG 图像类型,位深指定每个采样的位数,而不是每个像素的总位数。对于索引色图像,位深指定每个调色板索引的位数,而不是调色板或 Alpha 表中颜色的采样深度。像素内的采样顺序如下(取决于 PNG 图像类型):
PNG 图像编码过程的概念模型如图 7 所示。这些步骤指的是对 PNG 图像中像素数组或索引数组的操作。调色板和Alpha 表不以这种方式编码。
通道提取(见 图 7)将 PNG 图像拆分为一系列缩减图像,其中第一个图像定义粗略视图,后续图像增强该粗略视图,直到最后一个图像完成 PNG 图像。缩减图像集也称为隔行扫描 PNG 图像。本规范定义了两种隔行扫描方法。第一种方法为空方法;像素按顺序从左到右存储,扫描线从上到下存储。第二种方法对图像进行多次扫描,以产生七个缩减图像序列。示例图像的七个通道如图 图 7 所示。见 8. 隔行扫描和通道提取。
每一行像素(称为扫描线)表示为字节序列。
PNG 允许图像数据在压缩前进行过滤。过滤可以提高数据的压缩性。过滤操作是确定性的、可逆的和无损的。这使得解压后的数据可以进行反向过滤,以获取原始数据。见 7.3 过滤。
PNG 图像通道中的过滤扫描线序列通过定义的一种压缩方法进行压缩(见 图 9)。连接后的过滤扫描线构成压缩阶段的输入。压缩阶段的输出是单个压缩数据流。见 10. 压缩。
分块提供了将压缩数据流分解为易于管理的数据块的方法(见 图 9)。每个数据块都有自己的冗余校验。见 11. 数据块规范。
辅助信息可能与图像关联。解码器可以忽略全部或部分辅助信息。所提供的辅助信息类型在 表 2 中描述。
| 信息类型 | 描述 |
|---|---|
| 动画信息 | 一个动画图像,定义为一系列具有关联时间、位置和处理信息的帧,如果查看器具备相应能力,则应显示该动画。对于其他情况(如打印机),将显示静态图像。 |
| 背景色 | 如果无法获得更好的选择,则在呈现图像时使用的纯色背景色。 |
| 编码独立码点 | 通过枚举元数据(如转换函数和色度原色)来标识色彩空间。最初用于 SDR 和 HDR 视频,也用于静态和动画图像。 |
| 内容光照水平信息 | 图像(或图像序列)中最亮像素的亮度以及序列中最亮帧的平均亮度水平。 |
| EXIF 信息 | 可交换图像文件格式元数据,如快门速度、光圈和方向。 |
| 伽马和色度 | 相对于所需输出强度的图像伽马值,以及图像中使用的 RGB 值的色度特性。 |
| ICC 配置文件 | 图像中采样所符合的色彩空间描述(以国际色彩联盟 (ICC) 配置文件的形式)。 |
| 图像直方图 | 图像使用每个调色板条目的频率估计。 |
| 母版显示色彩体积 | 描述用于制作内容显示器的绝对三维色域体积,包括母版显示器可以再现的最亮和最暗颜色。这有助于在显示设备上呈现图像。 |
| 物理像素尺寸 | 呈现 PNG 图像时应使用的目标像素尺寸和纵横比。 |
| 有效位 | 采样中具有意义的位数。 |
| sRGB 色彩空间 | 一种渲染意图(由国际色彩联盟定义)以及图像采样符合该色彩空间的指示。 |
| 建议调色板 | 当显示设备无法显示图像中的全部颜色范围时,可以使用的缩减调色板。 |
| 文本数据 | 与图像关联的(可能经过压缩的)文本信息。 |
| 时间 | PNG 图像最后一次修改的时间。 |
| 透明度 | 允许在 PNG 图像中未保留 Alpha 通道时重建参考图像的 Alpha 信息。 |
PNG 数据流由 PNG 签名(见 5.2 PNG 签名)后跟一系列数据块(见 11. 数据块规范)组成。每个数据块都有一个指定其功能的数据块类型。
数据块类型是四字节序列,选择这些序列是为了使其在根据 ISO 646.IRV:1991 [ISO646] 字符集解释时对应于可读标签。前四个称为关键数据块,必须根据本规范的规定进行理解和正确解释。它们是:
其余数据块类型称为辅助数据块类型,编码器可以生成,解码器可以选择性解释。
动画 PNG (APNG) 扩展了原始的静态 PNG 格式,增加了对基于帧动画图像的支持。它旨在替代传统上使用 GIF 格式 [GIF] 的简单动画图像,同时增加了对 GIF 所缺乏的 24 位图像和 8 位透明度的支持。
APNG 向后兼容 PNG 的早期版本;非动画 PNG 解码器将忽略辅助性的 APNG 专用数据块,并显示静态图像。
APNG 流是 PNG 规范先前版本中定义的普通 PNG 流,并增加了三个额外的数据块类型,用于描述动画并提供额外的帧数据。
要被识别为 APNG,acTL 数据块必须出现在流中任何 IDAT 数据块之前。acTL 结构如下所述。
概念上,在每次播放开始时,输出缓冲区应完全初始化为一个完全透明的黑色矩形,其宽度和高度尺寸来自 IHDR 数据块。
静态图像可以通过在 IDAT 之前存在单个 fcTL 数据块而被包含为动画的第一帧。否则,静态图像不是动画的一部分。
随后的帧在 fdAT 数据块中编码,其结构与 IDAT 数据块相同,只是前面加上了一个序列号。每帧有关放置和渲染的信息存储在 fcTL 数据块中。fdAT 和 fcTL 数据块的完整布局如下所述。
整个动画的边界由 IHDR 数据块的宽度和高度参数指定,无论默认图像是否是动画的一部分。如果后续帧需要额外空间,则默认图像应适当地填充完全透明的黑色像素。
每一帧在每次播放时都是相同的,因此应用程序缓存这些帧是安全的。
fcTL 和 fdAT 数据块具有从零开始的 4 字节序列号。这两种数据块类型共享该序列。此数字的目的是检测(并可选择纠正)动画 PNG 中的序列错误,因为本规范不对辅助数据块施加排序限制。
第一个 fcTL 数据块应包含序列号 0,其余 fcTL 和 fdAT 数据块中的序列号应按升序排列,没有间隙或重复。
下表说明了图像具有不止一帧,以及第二帧具有不止一个 fdAT 数据块时序列号的使用。(为清晰起见,省略了表中的 IHDR 和 IEND 数据块)。
| 序列号 | 数据块 |
|---|---|
| (none) | acTL |
| 0 | fcTL 第一帧 |
| (none) | IDAT 第一帧 / 静态图像 |
| 1 | fcTL 第二帧 |
| 2 | 第二帧的第一个 fdAT |
| 3 | 第二帧的第二个 fdAT |
| 序列号 | 数据块 |
|---|---|
| (none) | acTL |
| (none) | IDAT 静态图像 |
| 0 | fcTL 第一帧 |
| 1 | 第一帧的第一个 fdAT |
| 2 | 第一帧的第二个 fdAT |
| 3 | fcTL 第二帧 |
| 4 | 第二帧的第一个 fdAT |
| 5 | 第二帧的第二个 fdAT |
输出缓冲区是一个像素数组,其尺寸由 PNG IHDR 数据块的宽度和高度参数指定。概念上,每一帧在被合成到画布之前,都会在输出缓冲区中构建。输出缓冲区的内容可供解码器使用。输出缓冲区的角映射到画布的角。
画布是输出设备上用于显示帧的区域。画布的内容不一定对解码器可用。如果存在 bKGD 数据块,且没有更好的背景,则可以使用它来填充画布。
PNG 数据流中的错误可分为两类:
PNG 解码器应尽早检测错误,尽可能从错误中恢复,否则应优雅地失败。错误处理理念在 13.1 错误处理 中有详细描述。
本节是非规范性的。
PNG 格式提供了几个扩展点
其中一些扩展点由 W3C 保留,而另一些则可供私有使用。
PNG 数据流 由一个 PNG 签名及其后的一系列数据块组成。它是编码 PNG 图像 的结果。
使用“数据流”这一术语而不是“文件”,是为了描述一个可能只是文件一部分的字节序列。它也用于强调字节序列可能是“动态”生成和消费的,根本不会出现在存储的文件中。
PNG 数据流的前八个字节始终包含以下十六进制值
89 50 4E 47 0D 0A 1A 0A
此签名表明数据流的其余部分包含单个 PNG 图像,该图像由一系列数据块组成,以 IHDR 块开头,以 IEND 块结尾。
此签名将 PNG 数据流与其他类型的 数据流 区分开来,并允许及早发现某些传输错误。
每个 数据块 (chunk) 由三个或四个字段组成(参见 图 10)。字段的含义在 表 5 中进行了描述。数据块的数据字段可以为空。
| 名称 | 描述 |
|---|---|
| 长度 (Length) | 一个 PNG 四字节无符号整数,给出数据块数据字段中的字节数。该长度仅计算数据字段,不计算其自身、块类型或 CRC。零是一个有效的长度。尽管编码器和解码器应将长度视为无符号,但其值不得超过 231-1 字节。 |
| 数据块类型 | 定义块类型的四个字节序列。块类型的每个字节仅限于十六进制值 41 到 5A 以及 61 到 7A。这些分别对应于 ISO 646 [ISO646] 中的大写和小写字母(A-Z 和 a-z),以便于描述和检查 PNG 数据流。编码器和解码器应将块类型视为固定的二进制值,而不是字符字符串。例如,用 UCS 2 字符集中这些字母的等效项来表示块类型 IDAT 是不正确的。关于块类型的其他命名约定在 5.4 块命名约定 中讨论。 |
| 块数据 | 适用于块类型的相关数据字节(如果有)。 该字段可以为零长度。 |
| CRC | 一个四字节的 CRC,是对数据块中前面的字节计算得出的,包括块类型字段和块数据字段,但不包括长度字段。该 CRC 可用于检查数据是否损坏。即使对于不包含数据的数据块,CRC 也始终存在。参见 5.5 CRC 算法。 |
数据块数据长度可以是最大值以内的任意字节数;因此,实现者不能假设数据块在大于字节的任何边界上对齐。
选择块类型时,将其字节解释为 ISO 646 字母 [ISO646] 时具有意义。分配块类型是为了即使在未识别类型的情况下,解码器也能确定数据块的某些属性。这些规则通过允许 PNG 解码器在遇到未知数据块时决定如何处理,实现了 PNG 格式的安全、灵活扩展。
只有在解码器无法识别数据块类型时,命名规则通常才具有相关性,详见 13. PNG 解码器和查看器。
块类型的四位属性位,即每个字节的第 5 位(值 32),用于传达数据块属性。此选择意味着人类可以根据块类型每个字节对应的字母是大写(第 5 位为 0)还是小写(第 5 位为 1)来读取分配的属性。
属性位是块类型的固有部分,因此对于任何块类型都是固定的。因此,CHNK 和 cHNk 将是互不相关的块类型,而不是具有不同属性的相同数据块。
属性位的语义定义在 表 6 中。
| 名称与位置 | 定义 | 描述 |
|---|---|---|
| 辅助位:第一个字节 | 0(大写)= 关键, 1(小写)= 辅助。 |
关键数据块对于成功显示数据流的内容是必要的,例如图像头数据块 (IHDR)。解码器在尝试提取图像时,如果遇到未知类型且辅助位为 0 的数据块,应向用户指示该图像包含其无法安全解释的信息。 辅助数据块对于有意义地显示数据流的内容并非绝对必要,例如时间数据块 (tIME)。解码器在遇到未知类型且辅助位为 1 的数据块时,可以安全地忽略该块并继续显示图像。 |
| 私有位:第二个字节 | 0(大写)= 公共, 1(小写)= 私有。 |
公共数据块由 W3C 保留以供定义。私有数据块的定义在 12.10.1 私有数据块的使用 中指定。私有数据块名称的第二个字母为小写,而公共数据块名称的第二个字母为大写。 |
| 保留位:第三个字节 | 在此版本的 PNG 中为 0(大写)。 如果保留位为 1,则数据流不符合此版本的 PNG。 |
块名称第三个字母的大小写的意义被保留以用于可能的未来扩展。在本国际标准中,所有块名称的第三个字母都应为大写。 |
| 可安全复制位:第四个字节 | 0(大写)= 不可安全复制, 1(小写)= 可安全复制。 |
此属性位对纯解码器而言不重要,但 PNG 编辑器 需要它。此位定义了在修改数据流时如何正确处理未识别的数据块。PNG 编辑器 的规则在 14.2 PNG 编辑器的行为 中进一步讨论。 |
假设的块类型 "cHNk" 具有以下属性位
cHNk <-- 32 bit chunk type represented in text form
||||
|||+- Safe-to-copy bit is 1 (lower case letter; bit 5 is 1)
||+-- Reserved bit is 0 (upper case letter; bit 5 is 0)
|+--- Private bit is 0 (upper case letter; bit 5 is 0)
+---- Ancillary bit is 1 (lower case letter; bit 5 is 1)
因此,该名称表示一个辅助、公共、可安全复制的数据块。
CRC 字段是使用带预调节和后调节的标准 CRC 方法计算的,如 [ISO-3309] 和 [ITU-T-V.42] 所定义。所采用的 CRC 多项式(与 GZIP 文件格式规范 [RFC1952] 中使用的相同)为
x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
在 PNG 中,32 位 CRC 初始化为全 1,然后从最低有效位 (1) 到最高有效位 (128) 处理每个字节的数据。所有数据字节处理完毕后,CRC 将被取反(取其按位反码)。该值以 MSB 优先的顺序传输(存储在数据流中)。为了区分字节和排序,32 位 CRC 的最低有效位被定义为 x31 项的系数。
CRC 的实际计算通常采用预计算表来加速计算。参见 D. CRC 实现示例。
关于各个数据块定位的约束列在 表 7 中,并以图表形式说明:静态图像参见 图 11 和 图 12;静态图像构成第一帧的动画图像参见 图 13 和 图 14;静态图像不是动画一部分的动画图像参见 图 15 和 图 16。这些网格图表示本规范施加的定位约束。图中的线条定义了偏序关系。较高的块应出现在较低的块之前。在水平对齐并位于其他两个块类型(高于和低于水平对齐的块)之间的块,可以在它们所连接的两个较高和较低块类型之间的任何顺序中出现。与块类型相关的上标定义在 表 8 中。它指示该数据块是强制性的、可选的,还是可以出现多次。两个块类型之间的垂直条表示替代选项。
| 关键数据块 (应按此顺序出现,PLTE 除外为可选) |
||
|---|---|---|
| 块名称 | 允许出现多次 | 排序约束 |
| IHDR | No | 应位于最前 |
| PLTE | No | 在第一个 IDAT 之前 |
| IDAT | 是 | 多个 IDAT 块应连续 |
| IEND | No | 应位于最后 |
| 辅助数据块 (无需按此顺序出现) |
||
| 块名称 | 允许出现多次 | 排序约束 |
| acTL | No | 在 IDAT 之前 |
| cHRM | No | 在 PLTE 和 IDAT 之前 |
| cICP | No | 在 PLTE 和 IDAT 之前 |
| gAMA | No | 在 PLTE 和 IDAT 之前 |
| iCCP | No | 在 PLTE 和 IDAT 之前。如果存在 iCCP 块,则不应存在 sRGB 块。 |
| mDCV | No | 在 PLTE 和 IDAT 之前。 |
| cLLI | No | 在 PLTE 和 IDAT 之前。 |
| sBIT | No | 在 PLTE 和 IDAT 之前 |
| sRGB | No | 在 PLTE 和 IDAT 之前。如果存在 sRGB 块,则不应存在 iCCP 块。 |
| bKGD | No | 在 PLTE 之后;在 IDAT 之前 |
| hIST | No | 在 PLTE 之后;在 IDAT 之前 |
| tRNS | No | 在 PLTE 之后;在 IDAT 之前 |
| eXIf | No | 在 IDAT 之前 |
| fcTL | 是 | 一个可能出现在 IDAT 之前;所有其他应出现在 IDAT 之后 |
| pHYs | No | 在 IDAT 之前 |
| sPLT | 是 | 在 IDAT 之前 |
| fdAT | 是 | 在 IDAT 之后 |
| tIME | No | 无 |
| iTXt | 是 | 无 |
| tEXt | 是 | 无 |
| zTXt | 是 | 无 |
| Symbol | 含义 |
|---|---|
| + | 一个或多个 |
| 1 | 仅一个 |
| ? | 零或一 |
| * | 零或多 |
| | | 替代选项 |
所有私有和公共数据块 应当 (SHOULD) 在 [PNG-EXTENSIONS] 中列出。
公共数据块由 W3C 保留以供定义。
公共数据块旨在符合 PNG 的理念进行广泛使用。
鼓励组织和应用程序提交任何符合上述标准的数据块,由 PNG 工作组 定义为公共数据块。
作为公共数据块的定义既不是自动的也不是即时的。建议的公共数据块类型在被定义之前 不得 (SHALL NOT) 在公开可用的软件或数据流中使用。
除非必要,否则不鼓励定义新的关键数据块类型。
组织和应用程序 可以 (MAY) 为私有和实验性用途定义私有数据块。
私有数据块 不应该 (SHOULD NOT) 仅仅为了承载人类用户感兴趣的文本信息而定义。相反,应该 (SHOULD) 使用 iTXt 块,并定义相应的关键字。
在 [PNG-EXTENSIONS] 中列出私有数据块可以减少但不能消除不同应用程序将相同的私有数据块用于不兼容目的的可能性。如果使用私有数据块类型,则 应当 (SHOULD) 在数据块数据的开头存储额外的标识信息,以进一步降低冲突风险。
对于所有存储对于查看图像非绝对必要的信息的私有数据块,应当 (SHOULD) 使用辅助数据块类型,而不是关键数据块类型。
不应该 (SHOULD NOT) 定义私有关键数据块,因为包含此类数据块的 PNG 数据流不具可移植性,并且 不应该 (SHOULD NOT) 在公开可用的软件或数据流中使用。如果私有关键数据块对于某个应用程序是必不可少的,它 应当 (SHOULD) 出现在数据流的开头附近,以便标准解码器在发现无法处理该数据流之前不必读取很远。
关于定义私有数据块的更多准则,请参见 B. 私有块类型指南。
以下字段中大于或等于 128 的值是 私有字段值
这些 私有字段值 既未在本规范中定义,也未保留。
私有字段值 可以 (MAY) 用于实验性或私有语义。
私有字段值 不应该 (SHOULD NOT) 出现在公开可用的软件或数据流中,因为它们可能导致 PNG 解码器无法读取数据流,详情请见 13. PNG 解码器和查看器。
正如 4.5 PNG 图像 中所解释的,有五种类型的 PNG 图像。对应于每种类型的是一个 颜色类型 (color type),它是以下值的总和:1(使用调色板)、2(使用 真彩色 (truecolor))和 4(使用 Alpha 通道)。灰度 (greyscale) 和 真彩色 图像可以具有显式的 Alpha 通道。PNG 图像类型及相应的 颜色类型 列在 表 9 中。
| PNG 图像类型 | 颜色类型 |
|---|---|
| 灰度 | 0 |
| 真彩色 | 2 |
| 索引色 | 3 |
| 带 Alpha 的灰度 | 4 |
| 带 Alpha 的真彩色 | 6 |
每种 PNG 图像类型允许的位深度和采样深度列在 图像头 中。
如果指示了传递曲线(由 gAMA、sRGB、iCCP)或 cICP,则灰度样本表示亮度;否则表示与设备相关的灰度。如果指示了色彩空间(由 gAMA 和 cHRM、sRGB、iCCP 或 cICP),则 RGB 样本表示校准后的颜色信息;否则表示未经校准的、与设备相关的颜色。
样本值不一定与光强度成比例;gAMA 数据块指定了样本值与显示输出强度之间的关系。强烈建议查看器进行适当补偿。参见 4.3 色彩空间、13.13 解码器 Gamma 处理 和 C. Gamma 和色度。
在 PNG 数据流中,透明度可以通过四种方式之一表示,具体取决于 PNG 图像类型(参见 4.4.1 Alpha 分离 和 4.4.4 Alpha 压缩)。
图像数组中包含的 Alpha 通道具有 8 位或 16 位样本,与其它样本大小相同。每个像素的 Alpha 样本存储在像素的灰度或 RGB 样本之后。Alpha 值为零表示完全透明,值为 2采样深度 - 1 表示完全不透明。中间值表示部分透明的像素,这些像素可以与背景图像进行 合成 (composited),以产生最终图像。
像素中的颜色值不会预先乘以分配给该像素的 Alpha 值。此规则有时被称为“非关联”或“非预乘”Alpha。(另一种常见的技术是存储乘以 Alpha 值后的样本值;实际上,这样的图像已经在黑色背景上进行了 合成。PNG 不使用预乘 Alpha。因此,图像编辑器可以获取一个 PNG 图像并轻松更改其透明度。)参见 12.3 Alpha 通道创建 和 13.16 Alpha 通道处理。
所有需要多于一个字节的整数都应采用 网络字节序(如图 图 17 所示):最高有效字节在前,然后是按重要性递减顺序排列的较低有效字节(双字节整数为 MSB LSB,四字节整数为 MSB B2 B1 LSB)。一个字节的最高位(值 128)编号为位 7;最低位(值 1)编号为位 0。除非另有说明,否则数值为无符号。明确标为有符号的值采用补码表示法。
PNG 四字节无符号整数限制在 0 到 231-1 的范围内,以适应对无符号四字节值处理有困难的编程语言。
PNG 图像(或通道,参见 8. 隔行扫描和通道提取)是一个矩形像素数组,像素在每行扫描线中从左到右排列,扫描线从上到下排列。每个像素的大小由每像素位数决定。
扫描线内的像素始终打包成字节序列,像素之间没有浪费的位。扫描线始终从字节边界开始。允许的位深度和 颜色类型 受到限制,以便在所有情况下打包都简单高效。
在 颜色类型 0(灰度)的 PNG 图像中,每个像素是一个单一采样,其精度可能小于一个字节(1、2 或 4 位)。这些采样被打包到字节中,其中最左侧的采样位于字节的高位,后面是扫描线的其余采样。
在 颜色类型 3(索引色)的 PNG 图像中,每个像素是一个单一调色板索引。这些索引以与 颜色类型 0 的采样相同的方式打包到字节中。
当每个字节有多个像素时,扫描线最后一个字节的一些低位可能不会被使用。这些未使用位的内容未指定。
非 索引色 的 PNG 图像可能具有位深度为 16 的采样值。此类采样值采用 网络字节序(MSB 优先,LSB 第二)。PNG 仅允许在 8 位和 16 位采样中使用多采样像素,因此单个像素的多个采样永远不会被打包到一个字节中。
过滤方法 (filter method) 是一种应用于 扫描线 数组的变换,旨在提高其可压缩性。
PNG 标准化了一种 过滤方法 和几种可用于准备 图像数据 以进行压缩的过滤器类型。它将字节序列变换为等长的字节序列,并在前面加上一个过滤器类型字节(参见 图 18 中的示例)。
编码器应仅对隔行扫描的 PNG 图像使用单一的 过滤方法,但可以对缩减图像中的每一行扫描线使用不同的过滤器类型。智能编码器可以在不同的扫描线之间切换过滤器。选择采用哪种过滤器的方法留给编码器决定。
过滤器类型字节不被视为 图像数据 的一部分,但它被包含在发送到压缩步骤的数据流中。参见 9. 过滤。
通道提取(参见 图 4.8)将 PNG 图像拆分为一系列缩减图像(隔行扫描 PNG 图像),其中第一幅图像定义了粗略视图,后续图像增强此粗略视图,直到最后一幅图像完成 PNG 图像。这允许解码器对隔行扫描的 PNG 图像进行渐进式显示,并允许图像在动态显示时“淡入”。平均而言,隔行扫描会略微扩展数据流大小,但它可以让用户更快地获得有意义的显示效果。
本国际标准定义了两种隔行扫描方法,即方法 0 和方法 1。其他隔行扫描方法的值保留以用于未来的标准化。
使用方法 0(空方法),像素从左到右依次提取,扫描线从上到下依次提取。隔行扫描的 PNG 图像是单一的缩减图像。
方法 1,称为 Adam7,定义了图像的七个不同通道。每个通道传输参考图像中像素的子集。每个像素传输所在的通道(从 1 到 7 编号)定义为在整个图像上复制以下 8x8 模式,从左上角开始
1 6 4 6 2 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
3 6 4 6 3 6 4 6
7 7 7 7 7 7 7 7
5 6 5 6 5 6 5 6
7 7 7 7 7 7 7 7
图 4.8 显示了方法 1 的七个通道。在每个通道内,所选像素在扫描线内从左到右传输,所选扫描线从上到下依次传输。例如,通道 2 包含扫描线 0、8、16 等的像素 4、12、20 等(其中扫描线 0,像素 0 是左上角)。最后一个通道包含所有扫描线 1、3、5 等。传输顺序的定义使得在通道中传输的所有扫描线将具有相同数量的像素;这对于正确应用某些过滤器是必要的。隔行扫描的 PNG 图像由七个缩减图像的序列组成。例如,如果 PNG 图像为 16x16 像素,则第三个通道将是包含两行扫描线的缩减图像,每行包含四个像素(参见 图 4.8)。
未完全填满整数个字节的扫描线按 7.2 扫描线 中的定义进行填充。
注意 如果参考图像包含少于五列或少于五行,则某些通道将为空。
过滤通过提高压缩率来转换 PNG 图像。整个过程描述在 图 7 中,而序列化和过滤扫描线的具体细节显示在 图 18 中。
PNG 允许多种 过滤方法。隔行扫描图像中的所有缩减图像都应使用单一的 过滤方法。本规范仅定义了 过滤方法 0。其他 过滤方法 保留用于未来标准化。过滤方法 0 提供了一组五种过滤器类型,每个缩减图像中的各个扫描线可以使用不同的过滤器类型。
PNG 对应用于隔行扫描 PNG 图像的过滤器类型没有额外限制。然而,过滤器类型在所有类型的数据上效果并不相同。参见 12.7 过滤器选择。
过滤将扫描线中的字节序列转换为等长的字节序列,并在前面加上过滤器类型。过滤器类型字节仅与非空扫描线相关联。在空通道中不存在过滤器类型字节。参见 13.10 隔行扫描和渐进式显示。
无论图像的位深度或 颜色类型 如何,过滤器都应用于字节而不是像素。过滤器对表示为 7.2 扫描线 中所述的扫描线形成的字节序列进行操作。如果图像包含 Alpha 通道,则 Alpha 数据以与 图像数据 相同的方式进行过滤。
过滤器可以使用以下字节的原始值来生成新的字节值
| 名称 | 定义 |
|---|---|
| x | 正在被过滤的字节; |
| a | 对应于包含 x 的像素之前的像素中的 x 字节(或当位深度小于 8 时,x 之前的字节); |
| b | 对应于前一条扫描线中 x 的字节; |
| c | 对应于包含 b 的像素之前的像素中的 b 字节(或当位深度小于 8 时,b 之前的字节)。 |
图 19 显示了字节 x、a、b 和 c 的相对位置。
过滤方法 0 定义了五种基本过滤器类型,列于 表 11。Orig(y) 表示字节 y 的原始(未过滤)值。Filt(y) 表示应用过滤器类型后的值。Recon(y) 表示应用相应的重构函数后的值。Paeth 过滤器类型 PaethPredictor [Paeth] 定义如下。
过滤方法 0 精确指定了这五种过滤器类型,不得扩展。这确保了解码器无需解压缩数据即可确定它是否包含不受支持的过滤器类型:只需检查 11.2.1 IHDR 图像头 中的 过滤方法 即可。
| 类型 | 名称 | 过滤器功能 | 重构功能 |
|---|---|---|---|
| 0 | 无 | Filt(x) = Orig(x)
|
Recon(x) = Filt(x)
|
| 1 | Sub | Filt(x) = Orig(x) - Orig(a)
|
Recon(x) = Filt(x) + Recon(a)
|
| 2 | 向上 (Up) | Filt(x) = Orig(x) - Orig(b)
|
Recon(x) = Filt(x) + Recon(b)
|
| 3 | Average | Filt(x) = Orig(x) - floor((Orig(a) + Orig(b)) / 2)
|
Recon(x) = Filt(x) + floor((Recon(a) + Recon(b)) / 2)
|
| 4 | Paeth | Filt(x) = Orig(x) - PaethPredictor(Orig(a), Orig(b), Orig(c))
|
Recon(x) = Filt(x) + PaethPredictor(Recon(a), Recon(b), Recon(c))
|
对于所有过滤器,扫描线中第一个像素“左侧”的字节应视为零。对于引用前一条扫描线的过滤器,整个前一条扫描线以及前一条扫描线中第一个像素“左侧”的字节应被视为缩减图像第一条扫描线的零。
要撤消过滤器的效果,需要前一条扫描线上相同位置像素、当前像素正上方像素以及正上方像素左侧像素的解码值。
使用模 256 无符号算术,以便输入和输出都适合字节。无论位深度如何,过滤器都应用于每个字节。Filt 值序列作为过滤后的扫描线传输。
和 Orig(a) + Orig(b) 应在不溢出的情况下执行(至少使用九位算术)。floor() 表示如果除法有余数,结果向下取整到下一个整数;换句话说,它是整数除法或右移操作。
Paeth 过滤器类型计算三个相邻像素(左、上、左上)的简单线性函数,然后选择最接近计算值的相邻像素作为预测值。本规范中使用的算法是 Alan W. Paeth [Paeth] 技术的一种改编。
PaethPredictor 函数定义在下面的代码中。该函数的逻辑以及字节 a、b、c 和 x 的位置显示在 图 20 中。Pr 是字节 x 的预测值。
p = a + b - c
pa = abs(p - a)
pb = abs(p - b)
pc = abs(p - c)
if pa <= pb and pa <= pc then Pr = a
else if pb <= pc then Pr = b
else Pr = c
return Pr
PaethPredictor 函数内的计算应准确执行,且不得溢出。
执行比较的顺序至关重要,不得更改。该函数试图确定图像梯度在三个方向(垂直、水平或对角线)中的哪一个方向上最小。
编码器和解码器使用完全相同的 PaethPredictor 函数。
本国际标准仅定义了 PNG 压缩方法 0。其他压缩方法的值保留用于未来的标准化。PNG 压缩方法 0 是带有滑动窗口(它是 deflate 流中出现的距离的上限)的 deflate 压缩,最大为 32768 字节。Deflate 压缩源自 LZ77。
PNG 内的 Deflate 压缩数据流存储在 zlib 格式中,其结构为
| zlib 压缩方法/标志代码 | 1 字节 |
| 附加标志/校验位 | 1 字节 |
| 压缩数据块 | n 字节 |
| 校验值 | 4 字节 |
对于 PNG 压缩方法 0,zlib 压缩方法/标志代码应指定方法代码 8(deflate 压缩)和不超过 32768 字节的 LZ77 窗口大小。zlib 压缩方法编号与 IHDR 块中的 PNG 压缩方法编号不同。附加标志不得指定预设字典。
如果要压缩的数据包含 16384 字节或更少,PNG 编码器可以通过向上取整到 2 的幂(最小 256)来设置窗口大小。这减少了编码和解码所需的内存,而不会对压缩比产生负面影响。
zlib 数据流中的压缩数据存储为一系列块,每个块可以表示原始(未压缩)数据、使用固定 Huffman 编码的 LZ77 压缩数据,或使用自定义 Huffman 编码的 LZ77 压缩数据。最后一个块中的标记位将其标识为最后一个块,允许解码器识别压缩数据流的结束。关于压缩算法和编码的更多详细信息在 deflate 规范 [rfc1951] 中给出。
存储在 zlib 数据流末尾的校验值是根据数据流表示的未压缩数据计算得出的。用于计算此值的算法与用于 PNG 数据块 CRC 字段值的 CRC 计算不同。zlib 校验值主要用作交叉检查,以验证 deflate 算法实现是否正确。验证各个 PNG 数据块的 CRC 提供了 PNG 数据流未受损传输的置信度。
过滤后的扫描线序列被压缩,生成的压缩数据流被拆分为 IDAT 数据块。所有 IDAT 数据块内容的串联构成了 zlib 数据流。此数据流解压缩后得到过滤后的 图像数据。
重要的是要强调,IDAT 数据块之间的边界是任意的,可以出现在 zlib 数据流中的任何位置。IDAT 数据块边界与 deflate 块边界或 zlib 数据或任何其他特征之间不一定存在相关性。例如,完全可能出现最终的 zlib 校验值被拆分在 IDAT 数据块之间的情况。
同样,图像数据 的结构(即扫描线边界)与 deflate 块边界或 IDAT 数据块边界之间没有必需的相关性。完整的过滤后 PNG 图像由一个存储在多个 IDAT 数据块中的单一 zlib 数据流表示。
PNG 还在 iTXt、iCCP 和 zTXt 数据块中使用压缩方法 0。与 图像数据 不同,此类数据流不会跨越数据块拆分;每个此类数据块包含一个独立的 zlib 数据流(参见 10.1 压缩方法 0)。
本条款定义了本规范中使用的数据块。
关键数据块 (critical chunk) 是指成功从 PNG 数据流中解码出 PNG 图像所绝对必需的数据块。扩展数据块可以定义为关键数据块(参见 14. 编辑器),尽管强烈不鼓励这种做法。
有效的 PNG 数据流应以 PNG 签名开头,紧随其后的是 IHDR 数据块,然后是一个或多个 IDAT 数据块,并应以 IEND 数据块结束。在 PNG 数据流中只允许存在一个 IHDR 数据块和一个 IEND 数据块。
四字节数据块类型字段包含十六进制值
49 48 44 52
IHDR 数据块应是 PNG 数据流中的第一个数据块。它包含
| 宽度 | 4 字节 |
| 高度 | 4 字节 |
| 位深度 | 1 字节 |
| 颜色类型 | 1 字节 |
| 压缩方法 | 1 字节 |
| 过滤方法 | 1 字节 |
| 交错方法 | 1 字节 |
宽度和高度给出像素单位的图像尺寸。它们是 PNG 四字节无符号整数。零是无效值。
位深度是一个单字节整数,给出每个采样或每个调色板索引的位数(而非每像素位数)。有效值为 1、2、4、8 和 16,尽管并非所有颜色类型都允许所有值。参见 6.1 颜色类型和值。
颜色类型 是一个单字节整数。
对每种 颜色类型 的位深度限制旨在简化实现并禁止压缩效果不佳的组合。允许的组合定义在 表 12 中。
| PNG 图像类型 | 颜色类型 | 允许的位深度 | 解释 |
|---|---|---|---|
| 灰度 | 0 | 1, 2, 4, 8, 16 | 每个像素是一个灰度采样 |
| 真彩色 | 2 | 8, 16 | 每个像素是一个 R、G、B 三元组 |
| 索引色 | 3 | 1, 2, 4, 8 | 每个像素是一个调色板索引;必须出现一个 PLTE 数据块。 |
| 带 Alpha 的灰度 | 4 | 8, 16 | 每个像素是一个灰度采样后跟一个 Alpha 采样。 |
| 带 Alpha 的真彩色 | 6 | 8, 16 | 每个像素是一个 R、G、B 三元组后跟一个 Alpha 采样。 |
除了 索引色 PNG 图像(颜色类型 3)外,采样深度与位深度相同,其中采样深度始终为 8 位(参见 4.5 PNG 图像)。
压缩方法是一个单字节整数,指示用于压缩 图像数据 的方法。本规范仅定义了压缩方法 0(带有最大 32768 字节滑动窗口的 deflate 压缩)。所有符合规范的 PNG 图像都应使用此方案压缩。
过滤方法是一个单字节整数,指示压缩前应用于 图像数据 的预处理方法。本规范仅定义了 过滤方法 0(具有五种基本过滤器类型的自适应过滤)。详情请参见 9. 过滤。
交错方法是一个单字节整数,指示 图像数据 的传输顺序。本规范定义了两个值:0(无交错)或 1(Adam7 交错)。详情请参见 8. 隔行扫描和通道提取。
四字节数据块类型字段包含十六进制值
50 4C 54 45
PLTE 数据块包含 1 到 256 个调色板条目,每个条目是一个三字节序列,形式为
| 红色 | 1 字节 |
| 绿色 | 1 字节 |
| 蓝色 | 1 字节 |
条目数量由数据块长度确定。不能被 3 整除的数据块长度是错误的。
对于 颜色类型 3,该数据块必须出现,并且对于 颜色类型 2 和 6,它可能出现;它不得出现在 颜色类型 0 和 4 中。不得有超过一个 PLTE 数据块。
对于 颜色类型 3(索引色),必须有 PLTE 数据块。PLTE 中的第一个条目由像素值 0 引用,第二个由像素值 1 引用,依此类推。调色板条目数不得超过图像位深度可表示的范围(例如,位深度为 4 时,24 = 16)。允许拥有的条目少于位深度所允许的数量。在这种情况下,在 图像数据 中找到的任何超出范围的像素值都是错误的。
对于 颜色类型 2 和 6(真彩色 和 带 Alpha 通道的真彩色),PLTE 数据块是可选的。如果存在,它提供了一组建议的颜色(1 到 256 种),如果无法直接显示真彩色图像,则可以将真彩色图像量化为这些颜色。然而,建议将 sPLT 数据块用于此目的,而不是 PLTE 数据块。如果 PLTE 和 sPLT 数据块都不存在且图像无法直接显示,则查看系统必须执行量化。然而,通常最好由 PNG 编码器一次性完成颜色的选择。(参见 12.5 建议调色板。)
请注意,无论图像位深度如何,调色板每个采样使用 8 位(1 字节)。特别是,即使它是 16 位 真彩色 图像的建议量化版本,调色板的深度也是 8 位。
没有要求调色板条目必须全部由图像使用,也不要求它们必须全部不同。
四字节数据块类型字段包含十六进制值
49 44 41 54
IDAT 数据块包含实际的 图像数据,即压缩算法的输出流。详情请参见 9. 过滤 和 10. 压缩。
可能有多个 IDAT 数据块;如果是这样,它们应连续出现,中间没有其他数据块。压缩数据流是所有 IDAT 数据块数据字段内容的串联(请注意数据字段 可能是零长度)。
有些图像在最后一个 IDAT 数据块末尾有未使用的尾随字节。当存储整个缓冲区而不是仅存储缓冲区中已使用的部分时,可能会发生这种情况。这是不可取的。最好是编码器不包含这些未使用的字节。如果必须包含,将这些字节设置为零将防止意外的数据共享。解码器应该忽略这些尾随字节。
四字节数据块类型字段包含十六进制值
49 45 4E 44
IEND 数据块标记 PNG 数据流的结束。数据块的数据字段为空。
本规范中定义的辅助数据块列在 4.8.2 数据块类型 中。这不是它们在 PNG 数据流中出现的顺序。解码器可以忽略辅助数据块。对于每个辅助数据块,所描述的操作均假设解码器没有忽略该数据块。
四字节数据块类型字段包含十六进制值
74 52 4E 53
tRNS 数据块指定与调色板条目关联的 Alpha 值(用于 索引色 图像)或单个透明颜色(用于 灰度 和 真彩色 图像)。tRNS 数据块包含
| 颜色类型 0 | |
|---|---|
| 灰度采样值 | 2 字节 |
| 颜色类型 2 | |
| 红色采样值 | 2 字节 |
| 绿色采样值 | 2 字节 |
| 蓝色采样值 | 2 字节 |
| 颜色类型 3 | |
| 调色板索引 0 的 Alpha 值 | 1 字节 |
| 调色板索引 1 的 Alpha 值 | 1 字节 |
| ...等等... | 1 字节 |
对于 颜色类型 3(索引色),tRNS 数据块包含一系列单字节 Alpha 值,对应于 PLTE 数据块中的条目。每个条目指示对应调色板索引的像素应被视为具有指定的 Alpha 值。Alpha 值的解释与 8 位全 Alpha 通道中的相同:0 表示完全透明,255 表示完全不透明,无论图像位深度如何。tRNS 数据块所包含的 Alpha 值不得超过调色板条目数,但 tRNS 数据块所包含的值可以少于调色板条目数。在这种情况下,假定所有剩余调色板条目的 Alpha 值为 255。在通常仅需要使调色板索引 0 透明的情况下,仅需一个单字节的 tRNS 数据块;当所有调色板索引都是不透明的时,可以省略 tRNS 数据块。
对于 颜色类型 0 或 2,无论图像位深度如何,每个采样使用两个字节(参见 7.1 整数和字节序)。指定灰度采样值或 RGB 采样值的像素被视为透明(等同于 Alpha 值 0);所有其他像素被视为完全不透明(Alpha 值为 2位深度-1)。如果图像位深度小于 16,则使用最低有效位。编码器应将其他位设置为 0,解码器在使用该值之前必须将其他位屏蔽为 0。
tRNS 数据块不得出现在 颜色类型 4 和 6 中,因为在这些情况下已经存在完整的 Alpha 通道。
注意 对于 16 位 灰度 或 真彩色 数据,如 13.12 采样深度缩放 所述,仅 与 tRNS 数据块中完整的 16 位值匹配的像素 是透明的。解码器必须推迟任何采样深度缩放,直到像素被测试过透明度之后。
四字节数据块类型字段包含十六进制值
63 48 52 4D
cHRM 数据块可用于指定 PNG 图像 中使用的红、绿、蓝显示基色的 1931 CIE x,y 色度,以及引用的 白点 (white point)。有关更多信息,参见 C. Gamma 和色度。iCCP 和 sRGB 数据块提供了对色彩管理和控制更高级的支持。
cHRM 数据块包含
| 名称 | 大小 |
|---|---|
| 白点 x | 4 字节 |
| 白点 y | 4 字节 |
| 红 x | 4 字节 |
| 红 y | 4 字节 |
| 绿 x | 4 字节 |
| 绿 y | 4 字节 |
| 蓝 x | 4 字节 |
| 蓝 y | 4 字节 |
每个值都编码为 PNG 四字节无符号整数,表示 x 或 y 值乘以 100000。
0.3127 的值将存储为整数 31270。
cHRM 数据块允许在所有 PNG 数据流中使用,尽管它对于 灰度 图像几乎没有价值。
除非它是解码器所能理解的 最高优先级的颜色数据块,否则此数据块将被忽略。
四字节数据块类型字段包含十六进制值
67 41 4D 41
实际上,指定期望的显示输出强度是不够的。还需要指定期望输出的观看条件。对于 gAMA,这些是 sRGB 规范 [SRGB] 的参考观看条件。不同观看条件的调整通常由色彩管理系统处理。如果没有执行调整,误差通常很小。希望获得高色彩保真度的应用程序可能希望使用 sRGB 或 iCCP 数据块。
gAMA 数据块包含
| 图像 Gamma | 4 字节 |
该值编码为 PNG 四字节无符号整数,表示 Gamma 值 乘以 100000。
1/2.2 的 Gamma 值 将存储为整数 45455。
有关更多信息,请参见 12.1 编码器 Gamma 处理 和 13.13 解码器 Gamma 处理。
除非它是解码器所能理解的 最高优先级的颜色数据块,否则此数据块将被忽略。
四字节数据块类型字段包含十六进制值
69 43 43 50
iCCP 数据块包含
| 配置文件名称 | 1-79 字节(字符串) |
| 空分隔符 | 1 字节(空字符) |
| 压缩方法 | 1 字节 |
| 压缩配置文件 | n 字节 |
配置文件名称可以是引用配置文件的任何方便名称。它区分大小写。配置文件名称应仅包含可打印的 Latin-1 字符和空格(仅允许代码点 0x20-7E 和 0xA1-FF)。不允许使用前导、尾随和连续空格。本规范定义的唯一压缩方法是方法 0(带有 deflate 压缩的 zlib 数据流,参见 10.3 压缩的其他用途)。压缩方法条目之后是构成数据块其余部分的压缩配置文件。对此数据流进行解压缩即可得到嵌入的 ICC 配置文件。
如果存在 iCCP 数据块,则图像采样符合国际色彩联盟 [ICC][ISO_15076-1] 定义的嵌入 ICC 配置文件所代表的色彩空间。ICC 配置文件的色彩空间应为彩色图像(颜色类型 2、3 和 6)的 RGB 色彩空间,或者是 灰度 图像(颜色类型 0 和 4)的灰度色彩空间。鼓励写入 iCCP 数据块的 PNG 编码器同时写入近似该 ICC 配置文件的 gAMA 和 cHRM 数据块,以便与不使用 iCCP 数据块的应用程序兼容。
除非它是解码器所能理解的 最高优先级的颜色数据块,否则此数据块将被忽略。
除非存在 cICP 数据块,否则 PNG 数据流最多应包含一个嵌入的配置文件,无论是显式使用 iCCP 指定还是隐式使用 sRGB 数据块指定。
四字节数据块类型字段包含十六进制值
73 42 49 54
为了简化解码器,PNG 规定只能使用特定的采样深度,并进一步规定采样值应缩放到该采样深度下的全范围可能值。sBIT 数据块定义了原始有效位数的数量(可以小于或等于采样深度)。这使得 PNG 解码器即使在数据具有 PNG 本身不支持的采样深度时,也能无损地恢复原始数据。
sBIT 数据块包含
| 颜色类型 0 | |
|---|---|
| 有效灰度位数 | 1 字节 |
| 颜色类型 2 和 3 | |
| 有效红色位数 | 1 字节 |
| 有效绿色位数 | 1 字节 |
| 有效蓝色位数 | 1 字节 |
| 颜色类型 4 | |
| 有效灰度位数 | 1 字节 |
| 有效 Alpha 位数 | 1 字节 |
| 颜色类型 6 | |
| 有效红色位数 | 1 字节 |
| 有效绿色位数 | 1 字节 |
| 有效蓝色位数 | 1 字节 |
| 有效 Alpha 位数 | 1 字节 |
sBIT 中指定的每个深度都必须大于零且小于或等于采样深度(索引色图像为 8,其他颜色类型则为 IHDR 中给定的位深度)。注意,sBIT 不提供 tRNS 数据块所暗示的 Alpha 通道的采样深度;在这种情况下,Alpha 通道的所有采样位都应被视为有效的。如果不存在 sBIT 数据块,则所有通道的所有采样位都应被视为有效的。
四字节数据块类型字段包含十六进制值
73 52 47 42
如果存在 sRGB 数据块,则图像采样符合 sRGB 色彩空间 [SRGB],并应使用国际色彩联盟 [ICC] 或 [ICC-2] 定义的指定渲染意图进行显示。
sRGB 数据块包含
| 名称 | 大小 |
|---|---|
| 渲染意图 | 1 字节 |
渲染意图定义了以下值
| 值 | 名称 | 描述 |
|---|---|---|
| 0 | 可感知 (Perceptual) | 适用于优先考虑对输出设备色域进行良好适应,而牺牲比色精度的图像,例如照片。 |
| 1 | 相对比色 (Relative colorimetric) | 适用于需要色彩外观匹配(相对于输出设备的白点)的图像,例如徽标。 |
| 2 | 饱和度 (Saturation) | 适用于优先考虑保持饱和度而牺牲色相和明度的图像,例如图表和图形。 |
| 3 | 绝对比色 (Absolute colorimetric) | 适用于需要保持绝对比色的图像,例如发送至不同输出设备的图像预览(校样)。 |
建议写入 sRGB 数据块的 PNG 编码器同时也写入 gAMA 数据块(以及可选的 cHRM 数据块),以兼容不使用 sRGB 数据块的解码器。只能使用以下值。
| gAMA | |
|---|---|
| 伽马值 | 45455 |
| cHRM | |
| 白点 x | 31270 |
| 白点 y | 32900 |
| 红 x | 64000 |
| 红 y | 33000 |
| 绿 x | 30000 |
| 绿 y | 60000 |
| 蓝 x | 15000 |
| 蓝 y | 6000 |
除非它是解码器所能理解的 最高优先级的颜色数据块,否则此数据块将被忽略。
四字节数据块类型字段包含十六进制值
63 49 43 50
如果存在,cICP 数据块使用 [ITU-T-H.273] 中指定的代码点来定义图像的色彩空间(基色)、传递函数、矩阵系数和缩放因子。在处理图像时(包括解码或渲染图像时),应当使用视频格式信号。
cICP 数据块由四个 1 字节无符号整数组成,用于标识上述特征。
以下规定了 cICP 数据块的语法
| 名称 | 大小 |
|---|---|
| 原色 (Color Primaries) | 1 字节 |
| 传递函数 (Transfer Function) | 1 字节 |
| 矩阵系数 (Matrix Coefficients) | 1 字节 |
| 视频全范围标志 (Video Full Range Flag) | 1 字节 |
cICP 数据块的每个字段对应 [ITU-T-H.273] 中的同名参数。
RGB 是目前 PNG 中唯一支持的颜色模型,因此 Matrix Coefficients 应设置为 0。
如果 Video Full Range Flag 为 0(窄范围图像),推荐做法是在扩展范围内定义传递函数(如 EOTF 或反向 OETF),以便包含负值。具体做法如下
out = sign(in) * TransferFunction(abs(in))
cICP 数据块 必须位于 PLTE 和 IDAT 数据块之前。
如果解码器能够识别此数据块,它即为最高优先级的颜色数据块。
与使用 sRGB 数据块紧凑地标记 sRGB 图像的方式类似,cICP 可用于紧凑地标记 Display P3 图像 [Display-P3]。
四字节数据块类型字段包含十六进制值
6D 44 43 56
如果存在,mDCV 数据块表征内容创作点使用的母版显示颜色容量 (Mastering Display Color Volume),如 [SMPTE-ST-2086] 所指定。mDCV 数据块提供信息性静态元数据,允许目标(消费级)显示器通过比较其固有能力与原始母版显示器的能力,从而优化其色调映射决策。
mDCV 通常与 PQ [ITU-R-BT.2100] 传递函数以及额外的 cLLI 元数据一起使用,通常被称为 [HDR10](带 ST 2086 静态元数据、MaxFALL 和 MaxCLL 的 PQ)。mDCV 数据块也可包含在 HLG [ITU-R-BT.2100] 和 SDR 图像格式中(例如 [ITU-R-BT.709])。
由于 mDCV 最初是作为旨在优化视频显示目标上图像色调映射的补充静态元数据创建的,因此使用 mDCV 时必须附带 cICP 数据块,以确立图像内容的基本特征。原色和白点特征可从 cICP 数据块格式中派生。关于使用 HDR [ITU-R-BT.2100] 和 SDR [ITU-R-BT.709] 的图像的最常见用例的具体示例,可在 [ITU-T-Series-H-Supplement-19] 中找到。基本 (cICP) 特征加上补充 (mDCV) 静态元数据可提供宝贵信息,以优化色调映射决策。
Issue #319 讨论了当存在 mDCV 数据块时的色调映射行为。
对于 SDR 图像,如果 mDCV 显示器的最小/最大亮度未知,则可以从 [ITU-T-Series-H-Supplement-19] 表 11 或相关 SDR 规范中的值推导出默认特征。目前,尚无已发布的标准化方法将 SDR 图像信号从其默认观看条件(显示亮度及环境照明)转换为 mDCV 数据块中标记的条件。
以下规定了 mDCV 数据块的语法
| 名称 | 大小 | 除数 (Divisor value) |
|---|---|---|
| 母版显示原色色度(R、G、B 的 CIE 1931 x,y) | 12 字节 | 0.00002 |
| 母版显示白点色度(CIE 1931 x,y) | 4 字节 | 0.00002 |
| 母版显示最大亮度(以 cd/m2 为单位) | 4 字节 | 0.0001 |
| 母版显示最小亮度(以 cd/m2 为单位) | 4 字节 | 0.0001 |
原色被编码为三对 PNG 双字节无符号整数,顺序为 x 然后 y,每一对代表除以除数后的 x 或 y 原色色度值。排序方式以 x 色度最大的原色开始,其次是 y 色度最大的原色,最后是剩余的原色。对于 RGB 色彩空间,这对应于 R、G、B 的顺序。
白点被编码为一对 PNG 双字节无符号整数,顺序为 x 然后 y,每一对代表除以除数后的 x 或 y 白点色度值。
最大和最小亮度值被编码为 PNG 四字节无符号整数,表示除以除数后的绝对亮度值(单位:cd/m2)。
除数用于将实际值映射到存储值。例如,对于原色和白点的无量纲除数 0.00002,将色度 (0.6800, 0.3200) 存储为 {34000, 16000}。
mDCV 数据块 必须位于 PLTE 和 IDAT 数据块之前。
以下是 [ITU-R-BT.2100] HDR 的 mDCV 示例。
以下是 [Display-P3] SDR 的 mDCV 示例。
四字节数据块类型字段包含十六进制值
63 4C 4C 49
如果存在,cLLI 数据块标识 HDR 内容的两个特征
cLLI 数据块添加了静态元数据,提供了优化关联内容向特定目标显示器色调映射的机会。这是通过根据目标显示器的特定峰值亮度能力调整内容的色调映射以防止裁切来实现的。色调映射优化方法目前是主观的。
MaxCLL(最大内容光照水平)使用静态元数据值来指示整个回放序列中任何单个像素的最大光照水平(以 cd/m2 为单位,也称为尼特)。通常存在一种算法过滤器,用于消除因处理或噪声产生的虚假值,这些值可能会对下游预期的色调映射产生负面影响。
MaxFALL(最大帧平均光照水平)使用静态元数据值来指示整个回放序列中帧平均光照水平的最大值(以 cd/m2 为单位,也称为尼特)。MaxFALL 的计算方法是:首先对每一帧中所有像素的解码亮度值求平均,然后使用该值中最大的那一帧的结果。
MaxCLL 和 MaxFALL 值被编码为 PNG 四字节无符号整数。
[CTA-861.3-A] 描述了生成 cLLI 值的计算方法,但未指定任何过滤。 [HDR-Static-Meta] 描述了一种改进的方法,可以排除统计异常值、重采样过滤器引起的噪声或振铃效应,推荐用于实际实施。
[SMPTE-ST-2067-21] 第 7.5 节在 cLLI 值未知且尚未计算的情况下增加了额外信息。
Issue #319 讨论了当存在 cLLI 数据块时的色调映射行为。
MaxCLL 或 MaxFALL 为零表示该值未知或目前无法计算。
无法计算的一个例子是创建实时动画 PNG 流时,在流结束之前并非所有帧都可用以计算这些值。编码器可能希望最初使用零值,并在流结束时用计算出的值替换它。
以下规定了 cLLI 数据块的语法
| 名称 | 大小 | 除数 (Divisor value) |
|---|---|---|
| 最大内容光照水平 (MaxCLL) | 4 字节 | 0.0001 cd/m2 |
| 最大帧平均光照水平 (MaxFALL) | 4 字节 | 0.0001 cd/m2 |
PNG 提供了 tEXt、iTXt 和 zTXt 数据块,用于存储与图像关联的文本字符串,例如图像描述或版权声明。关键字用于指示每个文本字符串代表的内容。可以出现任意数量的此类文本数据块,并且允许出现多个具有相同关键字的数据块。
以下关键字是预定义的,应在适当时使用。
| 关键字值 | 描述 |
|---|---|
| Title | 图像的简短(单行)标题或说明 |
| Author | 图像创作者的姓名 |
| 描述 | 图像描述(可能很长) |
| Copyright | 版权声明 |
| Creation Time | 原始图像创建时间 |
| Software | 用于创建图像的软件 |
| Disclaimer | 法律声明 |
| Warning | 关于内容性质的警告 |
| 来源 | 用于创建图像的设备 |
| Comment | 其他评论 |
| XML:com.adobe.xmp | 可扩展元数据平台 (XMP) 信息,按 XMP 规范 [XMP] 的要求格式化。为了符合 XMP 标准,建议使用压缩标志设置为 0 的 iTXt,并将语言标签和翻译后的关键字都设置为空字符串。 |
| Collection | 图像所属的集合名称。图像可以属于一个或多个集合,每个集合由单独的文本数据块命名。 |
其他关键字 可以由任何应用程序为私有或一般用途定义。
关键字 应当是:
一般用途的关键字 应当列在 [PNG-EXTENSIONS] 中。
关键字只能包含可打印的 Latin-1 [ISO_8859-1] 字符和空格;也就是说,只允许代码点 0x20-7E 和 0xA1-FF。为减少人为误读关键字的机会,关键字中不允许出现前导空格、尾随空格和连续空格,也不允许出现 U+00A0 不换行空格,因为它与普通空格在视觉上无法区分。
关键字的拼写必须与注册的一致,以便解码器在查找特定关键字时可以使用简单的字面比较。特别是,关键字被视为区分大小写。关键字长度限制为 1 到 79 字节。
对于“Creation Time”关键字,日期格式 应当为 RFC 3339 [rfc3339] 日期-时间格式,或 RFC 1123 [rfc1123] 第 5.2.14 节中定义的日期格式。首选 RFC3339 日期-时间格式。此字段的实际格式未定义。
iTXt 数据块使用 UTF-8 编码 [rfc3629],可用于传送任何语言的字符。可以选择压缩 iTXt 数据块中的文本字符串。iTXt 支持 Unicode,因此推荐用于所有文本字符串。此外还有 tEXt 和 zTXt 数据块,其内容仅限于可打印的 Latin-1 字符集加上 U+000A 换行符 (LF)。zTXt 中的文本字符串使用 deflate 压缩算法压缩为 zlib 数据流(参见 10.3 其他压缩用途)。
四字节数据块类型字段包含十六进制值
74 45 58 74
每个 tEXt 数据块包含一个关键字和一个文本字符串,格式为:
| Keyword(关键字) | 1-79 字节(字符串) |
| 空分隔符 | 1 字节(空字符) |
| 文本字符串 | 0 个或更多字节(字符字符串) |
关键字和文本字符串由一个零字节(空字符)分隔。关键字和文本字符串都不能包含空字符。文本字符串不是以空字符结尾的(长度由数据块长度决定)。文本字符串的长度可以是从零字节到最大允许数据块大小减去关键字和空字符分隔符长度之间的任何长度。
关键字指示文本字符串代表的信息类型,如 11.3.3.1 关键字和文本字符串 中所述。
文本根据 Latin-1 字符集 [ISO_8859-1] 进行解释。文本字符串可以包含任何 Latin-1 字符。文本字符串中的换行符应表示为单个换行符(十进制 10)。除 Latin-1 中定义的字符和换行符外,其他字符在 tEXt 数据块中没有定义意义。包含 ISO/IEC 8859-1 字符集以外字符的文本应使用 iTXt 数据块进行编码。
四字节数据块类型字段包含十六进制值
7A 54 58 74
zTXt 和 tEXt 数据块在语义上是等效的,但建议对存储大块文本使用 zTXt 数据块。
一个 zTXt 数据块包含:
| Keyword(关键字) | 1-79 字节(字符串) |
| 空分隔符 | 1 字节(空字符) |
| 压缩方法 | 1 字节 |
| 压缩后的文本数据流 | n 字节 |
关键字和空字符与 tEXt 数据块中的相同。关键字未压缩。压缩方法条目定义所使用的压缩方法。本国际标准中定义的唯一值是 0(deflate 压缩)。其他值留待未来标准化。压缩方法条目后跟构成数据块其余部分的压缩文本数据流。对于压缩方法 0,此数据流是一个带有 deflate 压缩的 zlib 数据流(参见 10.3 其他压缩用途)。解压缩此数据流将得到与等效 tEXt 数据块中存储的文本完全相同的 Latin-1 文本。
四字节数据块类型字段包含十六进制值
69 54 58 74
一个 iTXt 数据块包含:
| Keyword(关键字) | 1-79 字节(字符串) |
| 空分隔符 | 1 字节(空字符) |
| 压缩标志 | 1 字节 |
| 压缩方法 | 1 字节 |
| 语言标签 | 0 个或更多字节(字符字符串) |
| 空分隔符 | 1 字节(空字符) |
| 翻译后的关键字 | 0 个或更多字节 |
| 空分隔符 | 1 字节(空字符) |
| 文本 | 0 个或更多字节 |
关键字的描述见 11.3.3.1 关键字和文本字符串。
压缩标志:0 表示未压缩文本,1 表示压缩文本。仅文本字段可以压缩。压缩方法条目定义所使用的压缩方法。本规范定义的唯一压缩方法是 0(带有 deflate 压缩的 zlib 数据流,参见 10.3 其他压缩用途)。对于未压缩文本,编码器应将压缩方法设置为 0,解码器应忽略它。
语言标签是 [BCP47] 定义的格式良好的语言标签。与关键字不同,语言标签不区分大小写。子标签必须出现在 IANA 语言子标签注册中心中。如果语言标签为空,则语言未指定。语言标签示例包括:en、en-GB、es-419、zh-Hans、zh-Hans-CN、tlh-Cyrl-AQ、ar-AE-u-nu-latn 和 x-private。
翻译后的关键字和文本均使用 UTF-8 编码 [rfc3629],且两者均不得包含零字节(空字符)。与此数据块中的其他文本数据不同,文本不是以空字符结尾的;其长度由数据块长度得出。
翻译后的关键字中不应出现换行符。在文本中,换行符应表示为单个换行符(十六进制 0A)。不鼓励在翻译后的关键字和文本中使用其余控制字符(01-09、0B-1F、7F-9F)。在 UTF-8 中,字符 80-9F(不鼓励使用)与字节 80-9F(通常是必要的)之间存在区别。
翻译后的关键字(如果不为空)应包含关键字向语言标签指示的语言的翻译,并且显示关键字的应用程序也应同时显示翻译后的关键字。
四字节数据块类型字段包含十六进制值
62 4B 47 44
bKGD 数据块指定了显示图像时使用的默认背景颜色。如果存在任何其他首选背景(无论是用户指定的还是属于较大页面(如浏览器)),都应忽略 bKGD 数据块。bKGD 数据块包含
| 颜色类型 0 和 4 | |
|---|---|
| 灰度 | 2 字节 |
| 颜色类型 2 和 6 | |
| 红色 | 2 字节 |
| 绿色 | 2 字节 |
| 蓝色 | 2 字节 |
| 颜色类型 3 | |
| 调色板索引 | 1 字节 |
对于 颜色类型 3(索引色),该值为用作背景的颜色的调色板索引。
对于 颜色类型 0 和 4(灰度、带 Alpha 的灰度),该值为背景灰度级别,范围为 0 到 (2bitdepth)-1。对于 颜色类型 2 和 6(真彩色、带 Alpha 的真彩色),该值是用作背景的颜色,以 RGB 采样给出,范围为 0 到 (2bitdepth)-1。在每种情况下,为保持一致,无论图像位深度如何,每个采样均使用两个字节。如果图像位深度小于 16,则使用最低有效位。编码器应将其他位设置为 0,解码器在使用该值之前必须将其他位掩码为 0。
四字节数据块类型字段包含十六进制值
68 49 53 54
hIST 数据块包含一系列双字节无符号整数
| 频率 | 2 字节(无符号整数) |
| ...等等... |
hIST 数据块给出了调色板中每种颜色的近似使用频率。直方图数据块仅在存在 PLTE 数据块时才可出现。如果查看器无法提供调色板中列出的所有颜色,直方图可以帮助它决定如何选择颜色的子集进行显示。
PLTE 数据块中的每个条目应恰好对应一个直方图条目。每个条目与具有该调色板索引的图像像素所占比例成正比;确切的比例因子由编码器选择。
直方图条目是近似的,例外情况是零条目表示相应的调色板条目在图像中完全未被使用。如果存在任何该颜色的像素,则直方图条目必须为非零。
注意:当调色板是 真彩色 图像的建议量化版本时,直方图必然是近似的,因为解码器映射像素到调色板条目的方式可能与编码器不同。在这种情况下,通常不应出现零条目,因为任何条目都可能被使用。
四字节数据块类型字段包含十六进制值
70 48 59 73
pHYs 数据块指定了显示图像时预期的像素大小或长宽比。它包含
| 名称 | 大小 |
|---|---|
| 每单位像素数,X 轴 | 4 字节(PNG 四字节无符号整数) |
| 每单位像素数,Y 轴 | 4 字节(PNG 四字节无符号整数) |
| 单位说明符 | 1 字节 |
单位说明符定义了以下值
| 值 | 描述 |
|---|---|
| 0 | 单位未知 |
| 1 | 单位为米 |
当单位说明符为 0 时,pHYs 数据块仅定义像素长宽比;像素的实际大小保持未指定。
如果不存在 pHYs 数据块,则假定像素为方形,且每个像素的物理尺寸未指定。
四字节数据块类型字段包含十六进制值
73 50 4C 54
sPLT 数据块包含
| 名称 | 大小 |
|---|---|
| 调色板名称 | 1-79 字节(字符串) |
| 空分隔符 | 1 字节(空字符) |
| 采样深度 | 1 字节 |
| 红色 | 1 或 2 字节 |
| 绿色 | 1 或 2 字节 |
| 蓝色 | 1 或 2 字节 |
| Alpha | 1 或 2 字节 |
| 频率 | 2 字节 |
| ...等等... |
每个调色板条目为 6 或 10 字节,包含 5 个无符号整数(红、蓝、绿、Alpha 和频率)。
可以有任意数量的条目。PNG 解码器根据采样深度字节后剩余的数据块长度确定条目数量。如果 sPLT 采样深度为 8,则该长度必须能被 6 整除;如果采样深度为 16,则必须能被 10 整除。条目应按频率递减顺序出现。不要求条目全部被图像使用,也不要求它们全部不同。
调色板名称可以是引用该调色板的任何方便名称(例如“256 色,包含 Macintosh 默认值”、“256 色,包含 Windows-3.1 默认值”、“最优 512”)。当 PNG 数据流中出现多个调色板时,调色板名称可能有助于选择适当的建议调色板。
调色板名称区分大小写,并受到与 tEXt 数据块的关键字参数相同的限制。调色板名称只能包含可打印的 Latin-1 字符和空格(只允许代码点 0x20-7E 和 0xA1-FF)。不允许使用前导、尾随和连续空格。
sPLT 采样深度应为 8 或 16。
红、绿、蓝和 Alpha 采样各为一或两个字节,具体取决于 sPLT 采样深度,与图像位深度无关。颜色采样不会预乘 Alpha,也不会针对任何背景进行预合成。Alpha 值 0 表示完全透明。Alpha 值 255(当 sPLT 采样深度为 8 时)或 65535(当 sPLT 采样深度为 16 时)表示完全不透明。sPLT 数据块可以出现在任何 颜色类型中。sPLT 中的条目使用与 PNG 图像相同的 伽马值和 色度值,但可能超出 PNG 图像色彩空间中使用的值范围;例如,在 灰度 PNG 图像中,每个 sPLT 条目通常具有相等的红、绿和蓝值,但这并非必须。同样,即使 PNG 图像不使用透明度,sPLT 条目也可以具有非不透明的 Alpha 值。
每个频率值与在该图像被合成到任何背景之前,图像中在该 RGBA 空间中最接近该调色板条目的像素比例成正比。确切的比例因子由 PNG 编码器选择;建议结果值的范围应适当地填满 0 到 65535 的范围。PNG 编码器可以人为地提高被视为“重要”的颜色的频率,例如徽标中使用的颜色或肖像的面部特征。零是一个有效的频率,表示该颜色是“最不重要”的,或者它很少(如果确实有的话)被使用。当所有频率均为零时,它们是无意义的,也就是说,无法推断出颜色在 PNG 图像中出现的实际频率。
允许有多个 sPLT 数据块,但每个数据块必须具有不同的调色板名称。
四字节数据块类型字段包含十六进制值
65 58 49 66
eXIf 数据块的数据段包含一个 Exif 配置文件,格式为 [CIPA-DC-008] 中“4.7.2 Interoperability Structure of APP1 in Compressed Data”指定的格式,不同之处在于不包括 JPEG APP1 标记、长度和 4.7.2(C) 中描述的“Exif ID code”(即“Exif”、NULL 和填充字节)。
eXIf 数据块的大小仅受 PNG 规范施加的最大 231-1 字节的限制。PNG 数据流中只允许一个 eXIf 数据块。
eXIf 数据块包含有关原始图像数据的元数据。如果图像在 Exif 配置文件创建后经过编辑,则此数据可能不再适用于 PNG 图像数据。建议除非解码器具有对 Exif 数据有效性的独立了解,否则该数据应仅被视为具有历史价值。解决 eXIf 数据块中的数据与其他 PNG 数据块中的数据之间可能存在的冲突,超出了本规范的范围。
虽然 PNG 规范允许数据块大小最大为 231-1 字节,但应用程序作者应注意,如果 Exif 配置文件要写入 JPEG [JPEG] 数据流,则 eXIf 数据块数据的总长度可能需要调整为不超过 216-9 字节,以便能够放入 JPEG APP1 标记 (Exif) 段。
前两个字节的数据是用于小端序 (Intel) 的“II”或用于大端序 (Motorola) 字节顺序的“MM”。解码器应检查前四个字节以确保它们具有以下十六进制值
49 49 2A 00 (ASCII "II", 16-bit little-endian integer 42)
或者
4D 4D 00 2A (ASCII "MM", 16-bit big-endian integer 42)
所有其他值保留供未来定义。
图像编辑应用程序应考虑 Exif 规范 [CIPA-DC-008] 的 E.3 段,该段讨论了图像更改时更新 Exif 数据的要求。编码器应遵循这些要求,但解码器不应假定该工作已经完成。
虽然编码器可以选择更新它们,但不期望如果主图像发生更改,Exif 配置文件中存在的任何缩略图都会被(或不会被)更新。
四字节数据块类型字段包含十六进制值
74 49 4D 45
tIME 数据块给出了最后一次图像修改的时间(不是初始图像创建时间)。它包含
| 名称 | 大小 |
|---|---|
| 年份 | 2 字节(完整;例如 1995,不是 95) |
| 月份 | 1 字节 (1-12) |
| 日期 | 1 字节 (1-31) |
| 小时 | 1 字节 (0-23) |
| 分钟 | 1 字节 (0-59) |
| 秒 | 1 字节 (0-60)(以允许闰秒) |
应指定通用时间 (UTC) 而不是本地时间。
tIME 数据块旨在用作在图像数据更改时自动应用并更新的时间戳。
四字节数据块类型字段包含十六进制值
61 63 54 4C
acTL 数据块声明这是一个动画 PNG 图像,给出了帧数以及循环次数。它包含
帧数 (num_frames) |
4 字节 |
播放次数 (num_plays) |
4 字节 |
每个值被编码为 PNG 四字节无符号整数。
num_frames 指示动画中的总帧数。这必须等于 fcTL 数据块的数量。0 不是有效值。1 是有效值,用于单帧 PNG。如果此值不等于实际帧数,则应将其视为错误。
num_plays 指示此动画应播放的次数;如果为 0,则动画应无限期播放。如果非零,动画应在最后一次播放结束时停在最后一帧上。
acTL 数据块必须出现在有效 PNG 数据流内的第一个 IDAT 数据块之前。
为了实现 Web 兼容性,鉴于此数据块的开发部署与将其合并到 PNG 规范之间的时间较长,此数据块名称被特殊定义为私有数据块。
四字节数据块类型字段包含十六进制值
66 63 54 4C
fcTL 数据块定义了单个帧的尺寸、位置、延迟和处置方式。每个帧都需要恰好一个 fcTL 数据块。它包含
| 名称 | 大小 |
|---|---|
序列号 (sequence_number) |
4 字节 |
width |
4 字节 |
height |
4 字节 |
x 偏移量 (x_offset) |
4 字节 |
y 偏移量 (y_offset) |
4 字节 |
延迟分子 (delay_num) |
2 字节 |
延迟分母 (delay_den) |
2 字节 |
处置操作 (dispose_op) |
1 字节 |
混合操作 (blend_op) |
1 字节 |
sequence_number 定义动画数据块的序列号,从 0 开始。它被编码为 PNG 四字节无符号整数。
width 和 height 定义随后帧的宽度和高度。它们被编码为 PNG 四字节无符号整数。它们必须大于零。
x_offset 和 y_offset 定义随后帧的 x 和 y 位置。它们被编码为 PNG 四字节无符号整数。0 是一个有效值。
帧必须在由 x_offset、y_offset、width 和 height 定义的区域内渲染。此区域不得落在默认图像之外;因此 x_offset 加上 width 不得大于 IHDR 宽度;同样,y_offset 加上 height 不得大于 IHDR 高度。
delay_num 和 delay_den 定义延迟分数的分子和分母;指示显示当前帧的时间,以秒为单位。如果分母为 0,则应将其视为 100(即 delay_num 指定 1/100 秒)。如果分子值为 0,解码器应尽快渲染下一帧,尽管查看器可能会施加合理的下限。它们被编码为双字节无符号整数。
帧时序应独立于每一帧的解码和显示所需时间,以便无论解码器实现性能如何,动画都能以相同的速率运行。
dispose_op 定义渲染此帧后要完成的帧区域处置类型;换句话说,它指定了在延迟结束时(在渲染下一帧之前)应如何更改输出缓冲区。它被编码为单字节无符号整数。
dispose_op 的有效值为:
| 0 | APNG_DISPOSE_OP_NONE |
| 1 | APNG_DISPOSE_OP_BACKGROUND |
| 2 | APNG_DISPOSE_OP_PREVIOUS |
APNG_DISPOSE_OP_NONEAPNG_DISPOSE_OP_BACKGROUNDAPNG_DISPOSE_OP_PREVIOUS如果第一个 fcTL 数据块使用的 dispose_op 为 APNG_DISPOSE_OP_PREVIOUS,则应将其视为 APNG_DISPOSE_OP_BACKGROUND。
blend_op 指定是将帧 Alpha 混合到当前输出缓冲区内容中,还是将其完全替换输出缓冲区中的区域。它被编码为单字节无符号整数。
blend_op 的有效值为:
| 0 | APNG_BLEND_OP_SOURCE |
| 1 | APNG_BLEND_OP_OVER |
如果 blend_op 为 APNG_BLEND_OP_SOURCE,则帧的所有颜色分量(包括 Alpha)都会覆盖帧输出缓冲区区域的当前内容。如果 blend_op 为 APNG_BLEND_OP_OVER,则应根据其 Alpha 将帧合成到输出缓冲区上,使用 Alpha 通道处理中描述的简单 OVER 操作。注意,示例代码的第二个变体是适用的。
注意,对于第一帧,由于每次播放开始时都会清除输出缓冲区,因此两种混合模式在功能上是等效的。
对应于默认图像的 fcTL 数据块(如果存在)具有以下限制:
x_offset 和 y_offset 字段必须为 0。width 和 height 字段必须等于 IHDR 数据块中对应的字段。如前所述,每次播放开始时,输出缓冲区必须完全初始化为完全透明的黑色。这是为了确保动画的每次播放都是相同的。只要结果保证相同,解码器可以自由地避免显式清除步骤。例如,如果默认图像包含在动画中,并且使用 APNG_BLEND_OP_SOURCE 的 blend_op,则不需要清除,因为整个输出缓冲区将被覆盖。
为了实现 Web 兼容性,鉴于此数据块的开发部署与将其合并到 PNG 规范之间的时间较长,此数据块名称被特殊定义为私有数据块。
四字节数据块类型字段包含十六进制值
66 64 41 54
fdAT 数据块对于动画的作用与 IDAT 数据块对于静态图像的作用相同;fdAT 数据块集包含所有帧的图像数据(对于将静态图像作为第一帧的动画,则是第一帧之后的所有帧)。它包含
| 名称 | 大小 |
|---|---|
序列号 (sequence_number) |
4 字节 |
帧数据 (frame_data) |
n 字节 |
除第一帧外,每帧都需要至少一个 fdAT 数据块(如果该帧由 IDAT 数据块表示)。
每一帧的压缩数据流是该帧内所有 fdAT 数据块的 frame_data 字段按序列号升序连接的结果。
由于序列号的存在,fdAT 数据块 不能为零长度;但 frame_data 字段可以为零长度。解压缩后,数据流是完整 PNG 图像的像素数据,包括每行扫描线开头的过滤字节,类似于所有 IDAT 数据块的未压缩数据。它使用与静态图像相同的位深度、颜色类型、压缩方法、过滤方法、隔行扫描方法和调色板(如果有)。
每一帧都继承了文件第一个 IDAT 数据块之前的所有关键或辅助数据块指定的每个属性,宽度和高度除外,它们来自 fcTL 数据块。
如果存在 PNG pHYs 数据块,则 APNG 图像及其 x_offset 和 y_offset 值必须与主图像以相同的方式缩放。从概念上讲,这种缩放是在将输出缓冲区映射到画布上时发生的。
为了实现 Web 兼容性,鉴于此数据块的开发部署与将其合并到 PNG 规范之间的时间较长,此数据块名称被特殊定义为私有数据块。
本条款给出了对编码器行为的要求和建议。PNG 编码器应根据前述条款中规定的格式,从 PNG 图像生成 PNG 数据流。通常,遵循此处给出的附加建议将获得最佳结果。
具备完全色彩管理能力的 PNG 编码器将执行比此处描述的更复杂的计算,并可能选择使用 iCCP 数据块。如果已知图像采样符合 sRGB 规范 [SRGB],强烈鼓励编码器写入 sRGB 数据块,而不进行额外的 伽马 处理。在这两种情况下,建议生成一个适当的 gAMA 数据块,供不识别 iCCP 或 sRGB 数据块的 PNG 解码器使用。
PNG 编码器必须确定:
写入 gAMA 数据块的值是导致 PNG 解码器以预期方式表现的值。参见 13.13 解码器伽马处理。
要应用的转换取决于图像采样的性质及其精度。如果采样以浮点数或高精度整数形式(可能来自计算机图形渲染器)表示光强度,则编码器可能在将数据量化为整数值以包含在 PNG 数据流中之前执行 伽马编码(应用指数小于 1 的幂函数)。这会导致在给定的采样深度下产生更少的条带伪影,或者在保持相同的视觉质量的同时允许更小的采样。以 0 到 1 之间的浮点值表示的强度级别可以通过以下公式转换为数据流图像采样:
integer_sample = floor((2sampledepth-1) * intensityencoding_exponent + 0.5)
如果公式中的强度是预期的输出强度,则编码指数就是 gAMA 数据块中要使用的 伽马值。
如果 PNG 编码器可用的强度是原始场景强度,则可能需要进行另一次转换。有时要求显示的图像比原始源图像具有更高的对比度。这对应于从原始场景到显示输出的端到端 传递函数,其指数大于 1。在这种情况下:
gamma = encoding_exponent/end_to_end_exponent
如果不知道原始图像拍摄或计算的条件是否需要这种对比度变化,可以假定显示强度与原始场景强度成正比,即端到端指数为 1,因此:
gamma = encoding_exponent
如果图像仅写入数据流,编码器可以自由选择编码指数。选择导致 gAMA 数据块中的 伽马值为 1/2.2 的值通常是一个合理的选择,因为它最大限度地减少了在典型视频监视器上显示的 PNG 解码器的工作。
一些图像渲染器可能同时将图像写入 PNG 数据流并将其显示在屏幕上。显示的像素应针对所使用的显示系统和观看条件进行 伽马 校正,以便用户看到预期场景的正确表示。
如果渲染器想要将显示的采样值写入 PNG 数据流,避免对数据流进行单独的 伽马编码步骤,渲染器应通过幂函数近似显示系统的 传递函数,并将指数的倒数写入 gAMA 数据块。这将允许 PNG 解码器再现源创建者在渲染时屏幕上显示的内容。
然而,渲染器计算适合显示设备的显示像素,并为数据存储和传输执行单独的 伽马编码,并安排 gAMA 数据块中具有更适合图像未来用途的值,这同样是合理的。
计算机图形渲染器通常不执行 伽马编码,而是使采样值直接与场景光强度成正比。如果 PNG 编码器接收到已经量化为整数值的采样值,则对其进行 伽马编码毫无意义;那只会导致进一步的信息丢失。编码器应直接将采样值写入 PNG 数据流。这并不意味着 gAMA 数据块应包含 1.0 的 伽马值,因为从场景强度到显示输出强度的预期端到端 传递函数并不一定是线性的。然而,预期的 伽马值可能离 1.0 不远。它可能取决于正在渲染的场景是日光场景还是室内场景等。
当采样值直接来自硬件时,原则上可以从硬件的 传递函数 和场景的照明条件推断出正确的 gAMA 值。在视频数字化仪(“图像采集卡”)的情况下,采样可能在 sRGB 色彩空间中,因为 sRGB 规范旨在与现代视频标准兼容。图像扫描仪的可预测性较差。它们的输出采样可能与输入光强度成正比,因为 CCD 传感器本身是线性的;或者扫描仪硬件可能已经应用了旨在补偿后续打印中点增益的幂函数(指数约为 0.57);或者扫描仪可能已经针对显示器上的显示对采样进行了校正。可能需要参考扫描仪手册或扫描校准目标以确定特定扫描仪的特征。应该记住,伽马 将采样与预期的显示输出联系起来,而不是与扫描仪输入联系起来。
数据流格式转换器通常不应尝试将提供的图像转换为不同的 伽马。数据应在不进行转换的情况下存储在 PNG 数据流中,并且应尽可能从源数据流中的信息推导出 伽马值。在数据流转换时改变 伽马 会导致所表示的强度级别集重新量化,从而引入额外的舍入误差,且收益甚微。直接从输入文件复制采样值到输出文件几乎总是更好的做法。
如果源数据流描述了图像的 伽马 特征,强烈鼓励数据流转换器写入 gAMA 数据块。某些数据流格式指定了显示指数(将图像采样映射到显示输出的函数指数,而不是相反方向)。如果源文件的 伽马值大于 1.0,它很可能是显示指数,则应使用此值的倒数作为 PNG 伽马值。如果源文件格式记录了图像采样与除显示输出以外的量之间的关系,那么推导 PNG 伽马值将比这更复杂。
如果 PNG 编码器或数据流转换器知道图像已经使用其 传递函数 可以通过指数为 display_exponent 的幂函数近似的显示系统令人满意地显示,则该图像可以被标记为具有 伽马值:
gamma = 1/display_exponent
写入具有近似正确值的 gAMA 数据块,要比省略该数据块并强制 PNG 解码器猜测近似 伽马值更好。如果 PNG 编码器无法推断 伽马值,最好省略 gAMA 数据块。如果必须进行猜测,则应留给 PNG 解码器来完成。
伽马 不适用于 Alpha 采样;Alpha 总是以线性方式表示。
参见 13.13 解码器伽马处理。
有关颜色问题的参考,请参见 C. 伽马和色度。
具备完全色彩管理能力的 PNG 编码器将执行比此处描述的更复杂的计算,并可能选择使用 iCCP 数据块。如果已知图像采样符合 sRGB 规范 [SRGB],强烈鼓励 PNG 编码器使用 sRGB 数据块。
如果编码器能够确定源显示器原色的色度,或者基于图像来源或运行它的硬件做出强有力的猜测,则强烈鼓励编码器输出 cHRM 数据块。如果这样做,也应写入 gAMA 数据块;如果缺少 gAMA 数据块,解码器无法对 cHRM 数据块做太多处理。
有许多关于原色和白点的建议和标准,其中一些与特定技术相关,例如 CCIR 709 标准 [ITU-R-BT.709] 和 SMPTE-C 标准 [SMPTE-170M]。
需要考虑三种情况:
对于手绘或数字编辑的图像,必须确定在制作时是在什么显示器上观看的。许多图像编辑程序允许指定所使用的显示器类型。这通常是因为它们在内部使用某种与设备无关的空间进行工作。这些程序有足够的信息来编写有效的 cHRM 和 gAMA 数据块,并强烈建议自动执行此操作。
如果编码器是作为执行全光谱渲染的计算机图像渲染器的一部分进行编译的,则应将用于从内部与设备无关的色彩空间转换为 RGB 的显示器值写入 cHRM 数据块。任何超出所选 RGB 设备色域的颜色都应映射到色域内;PNG 不存储超出色域的颜色。
如果计算机图像渲染器直接在与设备相关的 RGB 空间中进行计算,则不应写入 cHRM 数据块,除非场景描述和渲染参数已针对特定显示器进行了调整。在这种情况下,应使用该显示器的数据来构建 cHRM 数据块。
少数图像格式存储校准信息,这些信息可用于填充 cHRM 数据块。例如,TIFF 6.0 文件 [TIFF-6.0] 可以选择性地存储校准信息,如果存在该信息,则应将其用于构建 cHRM 数据块。
由近期视频设备创建的视频可能使用 CCIR 709 原色和 D65 白点 [ITU-R-BT.709],这些数据在 表 29 中给出。
| R | G | B | 白点 | |
|---|---|---|---|---|
| x | 0.640 | 0.300 | 0.150 | 0.3127 |
| y | 0.330 | 0.600 | 0.060 | 0.3290 |
一种较旧但仍然非常流行的视频标准是 SMPTE-C [SMPTE-170M],在 表 30 中给出。
| R | G | B | 白点 | |
|---|---|---|---|---|
| x | 0.630 | 0.310 | 0.155 | 0.3127 |
| y | 0.340 | 0.595 | 0.070 | 0.3290 |
不建议数据流格式转换器尝试将提供的图像转换为不同的 RGB 色彩空间。数据应在不进行转换的情况下存储在 PNG 数据流中,如果已知源原色色度,则应将其记录下来。由于色域不匹配和舍入误差,在数据流转换时进行色彩空间转换是不明智的。与 伽马 转换一样,最好以无损方式存储数据,并在最终显示图像时至多进行一次转换。
参见 13.14 解码器颜色处理。
Alpha 通道既可以看作是暂时隐藏图像透明部分的遮罩,也可以看作是构建非矩形图像的一种手段。在前一种情况下,应保留完全透明像素的颜色值以备将来使用。在后一种情况下,透明像素不携带任何有用数据,仅用于填充 PNG 所需的矩形图像区域。在这种情况下,为了获得最佳压缩效果,所有完全透明的像素都应分配相同的颜色值。
图像作者应牢记解码器可能不会完全支持透明度控制的可能性(参见 13.16 Alpha 通道处理)。因此,在可行的情况下,分配给透明像素的颜色应为合理的背景颜色。
对于不需要完整 Alpha 通道,或无法承担压缩效率损失的应用,还可以使用 tRNS 透明度数据块。
如果图像具有已知的背景颜色,则应将此颜色写入 bKGD 数据块。即使是忽略透明度的解码器,也可以使用 bKGD 颜色来填充未使用的屏幕区域。
如果原始图像具有预乘(也称为“关联”)Alpha 数据,则可以通过将每个采样值除以对应的 Alpha 值,然后乘以图像位深度的最大值,并舍入到最接近的整数,将其转换为 PNG 的非预乘格式。在有效的预乘数据中,采样值绝不会超过其对应的 Alpha 值,因此除法结果应始终在 0 到 1 的范围内。如果 Alpha 值为零,则输出黑色(零)。
当编码 PNG 中无法直接表示的采样深度的输入采样时,编码器应将采样向上缩放到 PNG 允许的采样深度。最精确的缩放方法是线性方程
output = floor((input * MAXOUTSAMPLE / MAXINSAMPLE) + 0.5)
其中输入采样的范围从 0 到 MAXINSAMPLE,输出范围从 0 到 MAXOUTSAMPLE(即 2sampledepth-1)。
“左位复制”(left bit replication)是线性缩放方法的一种近似方法,它是将有效位移位到最高位开始,并将最高位重复填充到空位中。这种方法通常比线性缩放计算更快。
假设 5 位采样被缩放到 8 位。如果源采样值为 27(在 0-31 范围内),则原始位为
4 3 2 1 0
---------
1 1 0 1 1
左位复制给出的值为 222
7 6 5 4 3 2 1 0
----------------
1 1 0 1 1 1 1 0
|=======| |===|
| Leftmost Bits Repeated to Fill Open Bits
|
Original Bits
这与线性方程计算出的值相匹配。左位复制通常给出与线性缩放相同的值,且误差从不超过 1。
一种准确度明显较低的近似方法是简单地将输入值左移并用零填充低位。此方案无法精确重现白色,因为它不会生成全 1 的最大值;其净效果是使图像略微变暗。一般不建议使用此方法,但它确实具有提高压缩效果的作用,特别是在处理大于 8 位采样深度时。由于零填充缩放在高采样深度时引入的相对误差较小,一些编码器可能会选择使用它。但是,零填充不得用于 Alpha 通道数据,因为许多解码器会将全零和全一的 Alpha 值视为特殊情况。在缩放数据中精确表示这两个值非常重要。
当编码器写入 sBIT 数据块时,要求以存储采样的高位与原始数据匹配的方式进行缩放。也就是说,如果 sBIT 数据块指定了 S 的采样深度,则存储数据的最高 S 位必须与原始 S 位数据值一致。这允许解码器通过右移来恢复原始数据。增加的低位不受限制。上述所有缩放方法均符合此限制。
在向上缩放源 图像数据 时,建议一致地填充所有采样的低位;也就是说,相同的源值应在任何像素位置生成相同的采样值。这通过减少不同采样值的数量来提高压缩率。这不是强制性要求,一些编码器可能选择不遵循它。例如,编码器可能会对低位进行抖动处理,以提高显示的图像质量,但代价是增加文件大小。
在某些应用中,原始源数据的范围可能不是 2 的幂。线性缩放方程在这种情况下仍然有效,尽管移位方法不适用。建议不要为此类图像写入 sBIT 数据块,因为 sBIT 暗示原始数据范围恰好是 0..2S-1。
建议调色板可以作为 sPLT 数据块出现在任何 PNG 数据流中,或者作为 PLTE 数据块出现在 真彩色 PNG 数据流中。无论哪种情况,建议调色板都不是 图像数据 的核心部分,但它可用于在索引色显示硬件上呈现图像。建议调色板对于在 真彩色 硬件上运行的查看器没有任何意义。
当使用 sPLT 数据块提供建议调色板时,建议编码器使用频率字段来指示调色板条目的相对重要性,而不是将它们全部留为零(表示未定义)。频率值最容易计算为“最近邻”计数,即如果不应用抖动,每个 RGBA 调色板条目的近似使用情况。(这些计数通常作为开发建议调色板的结果“免费”获得。)因为建议调色板包含透明度信息,所以应针对未合成的图像进行计算。
即使对于索引色图像,sPLT 也可用于为无法显示 PLTE 数据块中存在的所有颜色的查看器定义替代的简化调色板。如果 PLTE 数据块在 颜色类型 6 的图像中出现而没有 bKGD 数据块,则计算调色板的情况未指定。
一种在 真彩色 PNG 数据流中包含建议调色板的较旧方法是使用 PLTE 数据块。如果使用此方法,直方图(频率)应出现在单独的 hIST 数据块中。PLTE 数据块不包含透明度信息。因此,对于 颜色类型 6(带 Alpha 的真彩色)的图像,建议出现 bKGD 数据块,并且调色板和直方图应参照在指定背景颜色上合成后的图像进行计算。此定义对于确保为具有分数 Alpha 值的像素生成有用的调色板条目是必要的。生成的调色板可能仅对在相同背景颜色上呈现图像的查看器有用。建议 PNG 编辑器 如果更改或删除了 颜色类型 6 图像中的 bKGD 数据块,则删除或重新计算调色板。
对于 颜色类型 2(真彩色)的图像,建议 PLTE 和 hIST 数据块仅参照 RGB 数据计算,忽略任何透明颜色规范。如果数据流使用透明度(具有 tRNS 数据块),查看器可以轻松调整生成的调色板以用于其预期的背景颜色(参见 13.17 直方图和建议调色板的使用)。
为了提供建议调色板,sPLT 数据块在以下方面比 PLTE 数据块更灵活
使用 sPLT 数据块的 PNG 编码器也可以选择编写一个由 PLTE 和 hIST 数据块表示的建议调色板,以便与不识别 sPLT 数据块的解码器兼容。
本规范定义了两种隔行扫描方法,其中一种是不隔行扫描。隔行扫描为解码器渐进式显示图像提供了便利的基础,如 13.10 隔行扫描和渐进式显示 中所述。
对于 颜色类型 3(索引色)的图像,过滤类型 0(无)通常是最有效的。具有 256 色或更少颜色的彩色图像几乎总是应该以 索引色 格式存储;真彩色 格式可能会大得多。
对于位深度小于 8 的图像,也建议使用过滤类型 0。对于低位深度的灰度图像,在极少数情况下,先将图像扩展为 8 位表示,然后再应用过滤可能会获得更好的压缩效果。
对于 真彩色 和 灰度 图像,五种过滤器中的任何一种都可能是最有效的。如果编码器使用固定过滤器,Paeth 过滤器类型最有可能是最好的。
为了获得 真彩色 和 灰度 图像的最佳压缩效果,并且如果压缩效率重于压缩速度,推荐的方法是自适应过滤,即为每一行扫描线选择一种过滤器类型。每个独特的图像将具有一组对其表现最好的不同过滤器。编码器可以尝试每种过滤器组合以找到最适合特定图像的压缩方式。但是,当穷举搜索不可接受时,以下是一些可能表现良好的通用启发式方法:使用所有五种过滤器计算输出扫描线,并选择给出输出绝对值之和最小的过滤器。(在此测试中,将输出字节视为带符号的差值。)这种方法通常优于任何单一的固定过滤器类型选择。
根据这些建议进行的过滤在与本规范定义的两种隔行扫描方法结合使用时非常有效。
编码器可以根据需要将压缩数据流划分为 IDAT 数据块。(允许多个 IDAT 数据块,以便编码器可以在固定数量的内存中工作;通常数据块大小将对应于编码器的缓冲区大小。)每个 IDAT 数据块仅包含一个数据字节的 PNG 数据流是有效的,尽管非常浪费空间。(零长度 IDAT 数据块也是有效的,尽管更浪费。)
每个文本数据块必须提供一个非空的关键字。如果没有更好的文本描述,可以使用通用关键字“Comment”。如果使用用户提供的关键字,编码器应检查它是否符合关键字的限制。
iTXt 数据块使用 Unicode 的 UTF-8 编码,因此可以存储任何语言的文本。tEXt 和 zTXt 数据块使用 Latin-1 (ISO 8859-1) 字符编码,这限制了在这些数据块中可以使用的字符范围。编码器应优先使用 iTXt 而非 tEXt 和 zTXt 数据块,以便在不丢失数据的情况下允许更广泛的字符集。编码器在存储文本时,必须将使用本地 旧版字符编码 的字符转换为适当的编码。
创建 iTXt 数据块时,编码器应遵循 编码标准 中的 UTF-8 编码。
编码器应劝阻创建单行长度超过 79 个 Unicode 码点 的文本,以方便阅读。建议小于 1024 字节的文本项应使用未压缩的文本数据块输出。建议基础标题和作者关键字应使用未压缩的文本数据块输出。将大型文本数据块放置在 图像数据 之后(IDAT 数据块之后)可以在某些情况下加快图像显示,因为解码器会先解码 图像数据。建议小型文本数据块(例如图像标题)出现在 IDAT 数据块之前。
编码器 可以 使用私有数据块来携带不需要被其他应用程序理解的信息。
编码器 可以 将非保留字段值用于实验或私有用途。
所有辅助数据块都是可选的,编码器无需编写它们。但是,鼓励编码器在信息可用时编写标准的辅助数据块。
本条款给出了一些关于 PNG 解码器行为和查看器行为的要求和建议。查看器向用户呈现解码后的 PNG 图像。由于查看器和解码器行为密切相关,此处将解码器和查看器一并处理。对 PNG 解码器的唯一绝对要求是它必须成功读取任何符合前述章节中指定格式的数据流。然而,遵循以下额外建议通常会获得最佳结果。
PNG 数据流中的错误分为两类:传输错误和语法错误(参见 4.10 错误处理)。
传输错误的示例包括以“文本”或“ascii”模式传输,其中字节代码 13 和/或 10 可能会在整个数据流中被添加、删除或转换;意外终止,其中数据流被截断;或者存储设备上的物理错误,其中一个或多个块(通常每个 512 字节)会有乱码或随机值。语法错误的一些示例包括行过滤器的无效值、无效的压缩方法、无效的数据块长度、索引图像中第一个 IDAT 数据块之前缺少 PLTE 数据块,或者存在多个 gAMA 数据块。PNG 解码器应按以下方式处理错误
三类 PNG 数据块与此哲学相关。出于此分类的目的,“未知数据块”是指其类型对解码器作者真正未知的数据块,或者作者选择将其视为未知的数据块,因为对该数据块类型的默认处理对于程序的目的来说已经足够。其他数据块称为“已知数据块”。基于此定义,三类数据块如下
有关数据块命名约定的描述,请参见 5.4 数据块命名约定。
PNG 数据块类型被标记为“关键”或“辅助”,取决于这些数据块对于提取可查看图像是否至关重要(如 IHDR、PLTE 和 IDAT),还是对于理解数据流结构至关重要(如 IEND)。这是一种特定类型的关键性,并不一定与每个可设想的解码器相关。例如,其唯一目的是提取文本注释(例如版权信息)的程序不需要可查看的图像,但应该 正确解码 UTF-8。另一个解码器可能认为 tRNS 和 gAMA 数据块对其正常执行至关重要。
语法错误总是涉及已知数据块,因为未知数据块中的语法错误无法被检测到。PNG 解码器必须根据其要求和情况确定语法错误是致命的(不可恢复)还是非致命的。例如,大多数解码器可以忽略无效的 IEND 数据块;文本提取程序可以忽略 IDAT 的缺失;图像查看器无法从索引图像中的空 PLTE 数据块中恢复,但它可以忽略 真彩色 图像中无效的 PLTE 数据块;提取 Alpha 通道的程序可以忽略无效的 gAMA 数据块,但可能认为存在两个 tRNS 数据块是致命错误。除语法错误以外的异常情况应按以下方式处理
当发生致命条件时,解码器应立即失败,在适当的情况下向用户发出错误信号,并可选择继续显示用户已经可见的任何 图像数据(即“优雅地失败”)。整个应用程序无需终止。
当发生非致命错误时,解码器应在适当的情况下向用户发出警告信号,从错误中恢复,并继续正常处理。
解码索引色 PNG 时,如果遇到超出范围的索引,解码器在处理此错误的方式上历来有所不同。将像素显示为不透明黑色是一种常见的错误恢复策略,现在本规范对此有要求。旧实现会有所不同,因此编码器不得依赖此行为。
不计算 CRC 的解码器应将明显的语法错误解释为损坏的迹象(另请参见 13.2 错误检查)。
压缩数据块(IDAT、zTXt、iTXt、iCCP)中的错误可能导致缓冲区溢出。deflate 解压缩器的实现者应防范这种可能性。
APNG 旨在允许在读取整个 数据流 之前增量显示帧。这意味着某些错误可能直到动画进行到一半时才会被检测到。强烈建议解码器在遇到任何错误时丢弃所有后续帧,停止动画,并恢复显示静态图像。在动画开始前检测到错误的解码器应显示静态图像。如果适当,可以向用户显示错误消息。
解码器应将乱序的 APNG 数据块视为错误。支持 APNG 的 PNG 编辑器 应使用序列号将它们恢复到正确的顺序。
PNG 错误处理哲学在 13.1 错误处理 中进行了描述。
未知数据块类型不应被视为错误,除非它是关键数据块。
通过查看所有四个字节是否在代码范围 41-5A 和 61-7A(十六进制)内,可以检查数据块类型的合理性;请注意,这仅对未识别的数据块类型进行即可。如果已知总数据流大小(来自文件系统信息、HTTP 协议等),也可以检查数据块长度的合理性。如果不检查 CRC,丢失/添加的数据字节或错误的数据块长度可能导致解码器失去同步,并将后续数据误解为数据块头。
对于已知长度的数据块(如 IHDR),解码器应将意外的数据块长度视为错误。本规范的未来扩展不会向现有数据块添加新字段;相反,将添加新的数据块类型来携带新信息。
应检查已知数据块字段中的意外值(例如 IHDR 数据块中的意外压缩方法)并将其视为错误。但是,建议仅在关键数据块中将意外字段值视为致命错误。辅助数据块中的意外值可以通过忽略整个数据块(就像它是一个未知数据块类型一样)来处理。(此建议假设数据块的 CRC 已被验证。在不检查 CRC 的解码器中,将任何意外值视为指示数据流已损坏更为安全。)
标准 PNG 图像应使用压缩方法 0 进行压缩。IHDR 数据块的压缩方法字段是为了可能的未来标准化或专有变体而提供的。解码器应检查此字节,如果它包含未识别的代码,则报告错误。有关详细信息,请参见 10. 压缩。
PNG 数据流由一系列显式类型的数据块组成。其内容由规范定义的数据块实际上可能包含任何内容,包括恶意代码。IEND 数据块之后也可能存在数据,这些数据可能包含任何内容,包括恶意代码。由于解码 PNG 图像,在接收者的计算机上执行此类恶意代码的风险尚未可知。然而,恶意应用程序可能会将此类代码隐藏在看起来无辜的图像文件中,然后执行它。
目前无法指定与未来数据块类型相关的可能安全风险。在定义未来的公共数据块时将考虑安全问题。与未知或未实现的数据块类型相关的附加安全风险是不存在的,因为此类数据块将被忽略,或者最多被复制到另一个 PNG 数据流中。
iTXt、tEXt 和 zTXt 数据块包含旨在作为纯文本显示的关键字和数据。iCCP 和 sPLT 数据块包含旨在作为纯文本显示的关键字。如果解码器在显示此类文本时没有过滤掉控制字符,特别是 ESC(转义)字符,则某些系统或终端可能会出现不理想和不安全的行为。建议解码器过滤掉控制字符以避免此风险;参见 13.7 文本数据块处理。
对于 eXIf 数据块,Exif 规范 [CIPA-DC-008] 没有包含明确要求标记“值偏移量”指针必须实际上指向文件内有效地址的规定。此要求仅是暗示的。(参见第 4.6.2 段,其中描述了 Exif IFD 结构。)无论如何,解码器都应准备好遇到无效指针并适当地处理它们。
每个数据块都以长度字段开头,这使得编写不受尝试溢出缓冲区的欺诈性数据块影响的解码器变得更加容易。每个数据块末尾的 CRC 为意外损坏的数据提供了强大的防御。PNG 签名字节提供了对常见文件传输错误的早期检测。
无法检查 CRC 的解码器可能会受到数据损坏的影响。此类损坏唯一可能的后果是图像内像素显示不正确。如果未检查 IHDR 数据块的 CRC 并且宽度或高度字段损坏,可能会发生更糟的事情。参见 13.2 错误检查。
编写不良的解码器可能会受到缓冲区溢出的影响,因为数据块可能非常大,长达 231-1 字节。但编写良好的解码器将能毫无困难地处理大块数据。
历史上,一些图像编辑工具通过仅将已修订区域的 Alpha 通道设置为零来执行修订,而没有同时删除实际的图像数据。仅仅依赖此类图像视觉外观的用户会面临隐私风险,因为实际的图像数据可以很容易地恢复。
类似地,一些图像编辑工具历史上通过重写 IHDR 中的宽度和高度而无需重新编码图像数据来执行剪裁,因此图像数据扩展到了新宽度和高度之外,并且可能被恢复。
具有 eXIf 数据块的图像可能包含自动包含的数据,例如摄影 GPS 坐标,如果用户不知道 PNG 图像包含此数据,这可能会成为隐私风险。(包含 EXIF 的其他图像格式,如 JPEG/JFIF,具有相同的隐私风险)。
解码器应通过简单的四字节字面值比较来识别数据块类型;对数据块类型执行大小写转换是不正确的。遇到辅助位为 1 的未知数据块的解码器可以安全地忽略该数据块并继续显示图像。试图提取图像的解码器在遇到辅助位为 0(指示关键数据块)的未知数据块时,应向用户指出图像包含其无法安全解释的信息。
解码器应通过数值测试指定位来测试未知数据块类型的属性。测试字符是大写还是小写是低效的,如果使用了特定于语言环境的大小写定义,甚至是不正确的。
解码器不应将保留位设置为 1 标记为错误,因为 PNG 规范的某些未来版本可能会为此位定义含义。将设置了此位的数据块视为与其他未知数据块类型相同的方式处理已足够。
解码器不需要测试数据块类型的私有位,因为它没有功能意义,用于避免 W3C 定义的数据块与私有定义的数据块之间的冲突。
所有辅助数据块都是可选的;解码器可以忽略它们。但是,鼓励解码器在适当且可行的情况下解释这些数据块。
非正方形像素可以表示(参见 11.3.4.3 pHYs 物理像素尺寸),但查看器不需要考虑它们;查看器可以将任何 PNG 数据流呈现为好像其像素是正方形一样。
当显示器的像素纵横比与 PNG 数据流中定义的物理像素尺寸的纵横比不同时,强烈鼓励查看器重新缩放图像以进行正确显示。
当 pHYs 数据块具有 0 的单位说明符(单位未知)时,解码器的行为可能取决于两个“每单位像素数”值的比率,但不应取决于它们的大小。例如,包含 (ppuX, ppuY, unit) = (2, 1, 0) 的 pHYs 数据块等同于包含 (1000, 500, 0) 的数据块;两者同样有效地表明图像像素的高度是宽度的两倍。
查看器处理图像和显示器的像素纵横比之间差异的一种合理方法是水平或垂直扩展图像,但不要同时进行。比例因子可以使用以下浮点计算获得
image_ratio = pHYs_ppuY / pHYs_ppuX
display_ratio = display_ppuY / display_ppuX
scale_factor_X = max(1.0, image_ratio/display_ratio)
scale_factor_Y = max(1.0, display_ratio/image_ratio)
因为保持图像区域等其他方法也是合理的,而且允许忽略 pHYs 数据块,所以作者不应假设所有查看应用程序都会使用此缩放方法。
除了修正像素纵横比外,查看器可能有理由执行额外的水平和垂直缩放。例如,查看器可能希望缩小太大而无法适合显示器的图像,或者扩展发送到高分辨率打印机的图像,使其看起来与显示器上的大小相同。
如果实际可行,PNG 解码器应有一种方式向用户显示数据流中找到的所有 iTXt、tEXt 和 zTXt 数据块。即使解码器不识别特定的文本关键字,用户也可能能够理解它。
处理 tEXt 和 zTXt 数据块时,解码器可能会遇到非允许的字符。有些可以安全显示(例如 TAB、FF 和 CR,分别为十六进制 09、0C 和 0D),但其他字符,特别是 ESC 字符(十六进制 1B),可能会造成安全隐患(因为显示硬件或软件可能会采取意外的操作)。解码器不应尝试直接显示在 tEXt 或 zTXt 数据块中遇到的任何非 Latin-1 字符(换行符和可能的 TAB、FF、CR 除外)。相反,它们应该被忽略或以可见符号(如“\nnn”)显示。参见 13.3 安全考虑。
处理 iTXt 数据块时,解码器应遵循 编码标准 中的 UTF-8 解码。
即使建议编码器将换行符表示为换行符(十六进制 0A),也建议解码器不要依赖于此;最好识别所有常见的换行组合(CR、LF 和 CR-LF)并将每个组合显示为单个换行符。TAB 可以扩展为到达 8 的列倍数所需的适当空格数。
在具有非 Latin-1 旧版字符编码 的系统上运行的解码器应重新映射字符代码,以便正确显示 Latin-1 字符。不支持的字符应替换为系统适当的替换字符(例如 U+FFFD 替换字符、U+003F 问号或 U+001A SUB)或映射到可见符号(例如“\nnn”)。仅当字符是解码系统上的可打印字符时才应显示。某些字节值可能会被解码系统解释为控制字符;为了安全起见,在此类系统上运行的解码器不应显示这些控制字符。
即使建议编码器避免创建超过 79 个字符的行,解码器也应准备好显示在换行符之间包含任意数量可打印字符的文本数据块。
本规范中使用的压缩技术不需要在解压缩开始前获得整个压缩数据流。因此,显示可以在整个解压缩数据流可用之前开始。本规范未来版本中的任何通用压缩方法极不可能不具有此属性。
必须强调的是,IDAT 数据块边界没有语义意义,可以在压缩数据流中的任何点出现。图像数据 的结构(例如扫描线边界)与 deflate 块边界或 IDAT 数据块边界之间没有必需的相关性。完整的 图像数据 由存储在若干 IDAT 数据块中的单个 zlib 数据流表示;假设不止于此的解码器是不正确的。某些编码器实现可能会输出这些结构确实相关的相关数据流,但解码器不能依赖于此。
为了反转过滤器的效果,解码器可能需要使用同一行上前一个像素、上一行中当前像素正上方的像素以及上述像素左侧像素的解码值。这意味着解码器始终需要至少存储一行 图像数据。即使某些过滤器类型不引用上一条扫描线,解码器在解码每条扫描线时也需要存储它,因为下一条扫描线可能会使用引用它的过滤器类型。参见 7.3 过滤。
解码器必须能够读取隔行扫描图像。如果参考图像包含少于 5 列或少于 5 行,某些过程将为空。编码器和解码器应正确处理这种情况。特别是,过滤器类型字节仅与非空扫描线相关联;空缩减图像中不存在过滤器类型字节。
在慢速传输链路上接收图像时,查看器可以通过渐进式显示隔行扫描图像来改善感知的性能。这意味着每接收到一个缩减图像,就会基于到目前为止接收到的数据显示完整图像的近似值。通过将每个接收到的像素扩展以填充覆盖接收到的像素下方和右侧尚未传输的像素位置的矩形,可以获得一种简单而悦目的效果。此过程可以通过以下 ISO C 代码进行描述 [ISO_9899]
/*
variables declared and initialized elsewhere in the code:
height, width
functions or macros defined elsewhere in the code:
visit(), min()
*/
int starting_row[7] = { 0, 0, 4, 0, 2, 0, 1 };
int starting_col[7] = { 0, 4, 0, 2, 0, 1, 0 };
int row_increment[7] = { 8, 8, 8, 4, 4, 2, 2 };
int col_increment[7] = { 8, 8, 4, 4, 2, 2, 1 };
int block_height[7] = { 8, 8, 4, 4, 2, 2, 1 };
int block_width[7] = { 8, 4, 4, 2, 2, 1, 1 };
int pass;
long row, col;
pass = 0;
while (pass < 7)
{
row = starting_row[pass];
while (row < height)
{
col = starting_col[pass];
while (col < width)
{
visit(row, col,
min(block_height[pass], height - row),
min(block_width[pass], width - col));
col = col + col_increment[pass];
}
row = row + row_increment[pass];
}
pass = pass + 1;
}
函数 visit(row,column,height,width) 获取下一个传输的像素,并使用像素指示的颜色绘制指定高度和宽度的矩形,其左上角位于指定的行和列。注意,行和列是从左上角的 0,0 开始测量的。
如果查看器正在将接收到的图像与背景图像合并,则只绘制接收到的像素位置(visit() 函数仅设置指定行和列处的像素,而不是整个矩形)可能更方便。随着新图像逐渐替换旧图像,这会产生“淡入”效果。此方法的一个优点是可以在每个像素被替换时进行适当的 Alpha 或透明度处理。如上所述绘制矩形将覆盖以后可能需要的背景图像像素,如果这些位置最终接收到的像素结果是完全或部分透明的。仅当背景图像没有存储在屏幕外的任何位置时,这才会成为问题。
为了实现 PNG 通用互操作性的目标,解码器应接受所有类型的 PNG 图像:索引色、真彩色 和 灰度。在索引色显示硬件上运行的查看器需要能够将 真彩色 图像简化为索引色以供查看。此过程称为“颜色量化”。
颜色量化的一种简单、快速的方法是将图像简化为固定调色板。通常使用具有均匀颜色间距的调色板(“色立方体”)来最小化每像素的计算量。对于照片类图像,建议进行抖动处理以避免在平滑渐变中出现难看的轮廓;然而,抖动引入了可能令人反感的颗粒感。
通过使用专门为图像选择的调色板,渲染质量可以大幅提高,因为色立方体通常有许多在任何特定图像中未使用的条目。此方法需要更多的工作,首先是选择调色板,其次是将单个像素映射到最近的可用颜色。PNG 允许编码器提供建议调色板,但并非所有编码器都会这样做,并且建议调色板在任何情况下都可能不合适(它们可能颜色过多或过少)。因此,高质量的查看器将需要随时准备调色板选择例程。大的查找表通常是映射单个像素到调色板条目的最可行方式,并具有足够的速度。
颜色量化的实现非常多。PNG 示例实现 libpng (http://www.libpng.org/pub/png/libpng.html) 包含了用于此目的的代码。
解码器可能希望将 PNG 数据缩放到较小的采样深度(数据精度)以进行显示。例如,16 位数据将需要简化为 8 位深度,以便在大多数现代显示硬件上使用。将 8 位数据简化为 5 位深度也很常见。
最准确的缩放是通过以下线性方程实现的
output = floor((input * MAXOUTSAMPLE / MAXINSAMPLE) + 0.5)
其中
MAXINSAMPLE = (2sampledepth)-1
MAXOUTSAMPLE = (2desired_sampledepth)-1
一种准确度稍低的转换是通过简单地向右移动 (sampledepth - desired_sampledepth) 位来实现的。例如,要将 16 位采样简化为 8 位,可以丢弃低字节。在许多情况下,移位方法对于显示目的而言足够准确,而且它肯定快得多。(但是,如果正在进行 伽马 校正,则可以将采样重缩放合并到 伽马 校正查找表中,如 13.13 解码器伽马处理 中所说明的那样。)
如果解码器需要向上缩放采样(例如,如果 帧缓冲区 的采样深度比 PNG 图像大),它应使用 12.4 采样深度缩放 中描述的线性缩放或左位复制。
当 sBIT 数据块存在时,可以通过向右移动到 sBIT 指定的采样深度来恢复参考 图像数据。请注意,线性缩放不一定会重现原始数据,因为编码器不需要使用线性缩放来向上缩放数据。但是,编码器被要求使用一种保留高位的方法,因此移位总是有效的。这是移位被认为比线性缩放更准确的唯一情况。解码器无需关注 sBIT 数据块;存储的图像是 IHDR 数据块指示的采样深度的有效 PNG 数据流;然而,在使用 sBIT 在将原始采样缩放到适合显示之前恢复它们通常比忽略 sBIT 产生更准确的显示。
将像素值与 tRNS 数据块值进行比较以检测透明像素时,比较应精确执行。因此,透明像素检测应在降低采样精度之前完成。
能够进行全色彩管理的查看器将执行比此处描述的更复杂的计算。
为了使图像显示程序产生正确的色调再现,有必要考虑采样与显示输出之间的关系,以及显示系统的 传递函数。这可以通过计算来完成
sample = integer_sample / (2sampledepth - 1.0)
display_output = sample1.0/gamma
display_input = inverse_display_transfer(display_output)
framebuf_sample = floor((display_input * MAX_FRAMEBUF_SAMPLE)+0.5)
其中 integer_sample 是数据流中的采样值,framebuf_sample 是写入 帧缓冲区 的值,MAX_FRAMEBUF_SAMPLE 是 帧缓冲区 采样的最大值(8 位为 255,5 位为 31 等)。第一行将整数采样转换为归一化的浮点值(范围 0.0 到 1.0),第二行转换为与所需显示输出强度成比例的值,第三行考虑显示系统的 传递函数,第四行转换为整数 帧缓冲区 采样。零的任何正幂次幂均为零。
可以在第二行和第三行之间插入一个步骤来调整 display_output,以考虑实际观看条件与参考观看条件之间的差异。但是,这种调整需要考虑遮盖眩光、黑电平映射和色彩外观模型,所有这些都不能通过幂函数很好地近似。此处未描述此类计算。如果忽略观看条件,错误通常很小。
显示 传递函数 通常可以通过幂为 display_exponent 的幂函数来近似,在这种情况下,第二行和第三行可以合并为
display_input = sample1.0/(gamma * display_exponent) = sampledecoding_exponent
以便仅执行一次幂计算。对于彩色图像,整个计算分别针对 R、G 和 B 值进行。
伽马值 可以直接从 gAMA 数据块中获取。或者,应用程序可能希望允许用户通过影响 伽马值 来调整显示图像的外观。例如,用户可以手动设置一个默认值为 1.0 的参数 user_exponent,应用程序可以设置
gamma = gamma_from_file / user_exponent
decoding_exponent = 1.0 / (gamma * display_exponent)
= user_exponent / (gamma_from_file * display_exponent)
用户会将 user_exponent 设置为大于 1 以调暗中间色调,或小于 1 以提亮它们。
包含零的 gAMA 数据块是无意义的,但可能是错误出现的。解码器应忽略它,编辑器可以丢弃它并向用户发出警告。
没有必要为每个像素执行超越数学计算。相反,可以计算出一个查找表,给出每个可能采样值的正确输出值。这对于图像(对于 8 位精度)仅需要 256 次计算,而不是每个像素 1 或 3 次计算。对于索引色图像,除非图像使用透明度并在不均匀的背景下显示,否则调色板的一次性校正已足够。
如果无法进行浮点计算,可以使用整数算术和预计算的对数表来计算 伽马 校正表。示例代码出现在 [PNG-EXTENSIONS] 中。
当传入图像具有未知的 伽马值(gAMA、sRGB 和 iCCP 均不存在)时,独立图像查看器应选择一个可能的默认 伽马值,但如果结果证明太暗或太亮,则允许用户选择一个新的。默认的 伽马值 可能取决于有关图像的其他知识,例如它是来自互联网还是来自本地系统。为了保持一致性,HTML 等文档格式或 SVG 等矢量图形的查看器应以与处理其他未标记图像相同的方式处理具有未知 伽马值 的嵌入或链接 PNG 图像。
在实践中,通常很难确定应该使用什么值的显示指数。在没有内置 伽马 校正的系统中,显示指数完全由 CRT 决定。除非对所使用的特定 CRT 有详细的校准测量,否则应使用 2.2 的显示指数。
许多现代 帧缓冲区 具有用于执行 伽马 校正的查找表,在这些系统上,显示指数值应该是查找表和 CRT 组合的指数。可能无法从查看器应用程序内部查出查找表包含什么,在这种情况下,可能有必要要求用户提供显示系统的指数值。不幸的是,不同的制造商使用不同的方式来指定查找表中应该包含什么,因此对系统 伽马值 的解释是与系统相关的。
真实显示器的响应实际上比单个数字(显示指数)所能描述的要复杂得多。如果可以获得显示器光输出作为电压输入函数的实际测量值,则上述计算的第三行和第四行可以用这些测量值的查找表替换,以找到最接近给定所需亮度的实际 帧缓冲区 值。
有关颜色问题的参考,请参见 C. 伽马和色度。
在许多情况下,PNG 数据流中的 图像数据 将被视为与设备相关的 RGB 值并显示,无需修改(适当的 伽马 校正除外)。这提供了 PNG 图像最快的显示速度。但除非查看器使用与原始图像作者所使用的完全相同的显示硬件,否则颜色不会与原始作者看到的完全相同,特别是对于较暗或近中性的颜色。cHRM 数据块提供的信息允许比单独的 伽马 校正更接近的色彩匹配。
cHRM 数据可用于将 图像数据 从 RGB 转换为 XYZ,并由此进入感知线性色彩空间(如 CIE LAB)。颜色可以被分区以生成最佳调色板,因为 CIE LAB 中两种颜色之间的几何距离与这些颜色看起来的不同程度密切相关(这与 RGB 或 XYZ 空间不同)。生成的颜色调色板一旦转换回 RGB 色彩空间,就可以用于显示或写入 PLTE 数据块。
作为图像处理应用程序一部分的解码器也可以将 图像数据 转换为 CIE LAB 空间进行分析。
在色彩保真度至关重要的应用中(如产品设计、科学可视化、医学、建筑或广告),PNG 解码器可以将 图像数据 从源 RGB 转换为查看图像所用的显示器的显示 RGB 空间。这涉及计算从源 RGB 到 XYZ 的矩阵和从 XYZ 到显示 RGB 的矩阵,然后结合它们以产生整体转换。PNG 解码器负责实现色域映射。
在具有色彩管理系统 (CMS) 的平台上运行的解码器可以将 图像数据、gAMA 和 cHRM 值传递给 CMS 以进行显示或进一步处理。
提供彩色打印设施的 PNG 解码器可以使用 Level 2 PostScript 中的设施来指定已校准 RGB 空间或与设备无关的色彩空间(如 XYZ)中的 图像数据。这将比简单的 RGB 到 CMYK 转换提供更好的色彩保真度。PostScript 语言参考手册 [PostScript] 给出了示例。此类解码器负责实现源 RGB(在 cHRM 数据块中指定)与目标打印机之间的色域映射。然后,PostScript 解释器负责生成所需的颜色。
PNG 解码器可以使用 cHRM 数据来计算彩色图像的准确灰度表示。从 RGB 到灰度的转换仅仅是计算 XYZ 的 Y(亮度)分量,它是 R、G 和 B 值的加权和。权重取决于显示器类型,即 cHRM 数据块中的值。PNG 解码器可能希望对没有 cHRM 数据块的 PNG 数据流执行此操作。在这种情况下,合理的默认值将是 CCIR 709 原色 [ITU-R-BT.709]。除非 PNG 图像确实是针对此类显示器进行色彩平衡的,否则不应使用原始 NTSC 原色。
bKGD 数据块给出的背景颜色通常用于填充图像周围未使用的屏幕空间,以及图像内的任何透明像素。(因此,即使图像不使用透明度,bKGD 也是有效且有用的。)如果没有 bKGD 数据块,查看器将需要决定合适的背景颜色。在没有其他信息可用时,8 位 sRGB 色彩空间中如 153 的中灰色将是一个合理的选择。透明的黑色或白色文本和深色阴影(很常见)在此背景下都将是可读的。
具有呈现图像特定背景的查看器(如 Web 浏览器)应忽略 bKGD 数据块,实际上用其首选背景颜色或背景图像覆盖 bKGD。
bKGD 数据块给出的背景颜色不应被视为透明,即使它恰好与 tRNS 数据块给出的颜色匹配(或者在 索引色 图像的情况下,指代被 tRNS 数据块标记为透明的调色板索引)。否则,人们将不得不想象在“背景后面”有东西来进行合成。背景颜色要么用作背景,要么被忽略;它不是 PNG 图像和某些其他背景之间的中间层。
事实上,bKGD 和 tRNS 数据块指定相同的颜色是很常见的,因为那样的话,如果不实现透明度处理的解码器将给出预期的显示,至少在没有部分透明像素存在时是这样。
Alpha 通道可用于将前景图像合成到背景图像上。PNG 数据流定义了前景图像和透明度遮罩,但不定义背景图像。PNG 解码器不需要支持这种最通用的情况。预计大多数解码器将能够支持针对单个背景颜色的合成。
用于计算合成采样值的方程是
output = alpha * foreground + (1-alpha) * background
其中 Alpha 以及输入和输出采样值表示为 0 到 1 范围内的分数。此计算应使用强度采样(而不是 伽马 编码的采样)执行。对于彩色图像,计算分别针对 R、G 和 B 采样进行。
以下代码说明了将前景图像合成到背景图像的一般情况。它假设前景图像的原始像素数据可用于背景图像,并且输出到用于显示的 帧缓冲区。其他变体也是可能的;请参见代码下方的注释。该代码允许前景图像和背景图像的采样深度和 伽马值 均不相同,且不一定适合显示系统。在实践中,在未先检查的情况下,不应做出关于相等的假设。
此代码是 ISO C [ISO_9899],为方便在下面的注释中引用而添加了行号。
01 int foreground[4]; /* image pixel: R, G, B, A */
02 int background[3]; /* background pixel: R, G, B */
03 int fbpix[3]; /* frame buffer pixel */
04 int fg_maxsample; /* foreground max sample */
05 int bg_maxsample; /* background max sample */
06 int fb_maxsample; /* frame buffer max sample */
07 int ialpha;
08 float alpha, compalpha;
09 float gamfg, linfg, gambg, linbg, comppix, gcvideo;
/* Get max sample values in data and frame buffer */
10 fg_maxsample = (1 << fg_sample_depth) - 1;
11 bg_maxsample = (1 << bg_sample_depth) - 1;
12 fb_maxsample = (1 << frame_buffer_sample_depth) - 1;
/*
* Get integer version of alpha.
* Check for opaque and transparent special cases;
* no compositing needed if so.
*
* We show the whole gamma decode/correct process in
* floating point, but it would more likely be done
* with lookup tables.
*/
13 ialpha = foreground[3];
14 if (ialpha == 0) {
/*
* Foreground image is transparent here.
* If the background image is already in the frame
* buffer, there is nothing to do.
*/
15 ;
16 } else if (ialpha == fg_maxsample) {
/*
* Copy foreground pixel to frame buffer.
*/
17 for (i = 0; i < 3; i++) {
18 gamfg = (float) foreground[i] / fg_maxsample;
19 linfg = pow(gamfg, 1.0 / fg_gamma);
20 comppix = linfg;
21 gcvideo = pow(comppix, 1.0 / display_exponent);
22 fbpix[i] = (int) (gcvideo * fb_maxsample + 0.5);
23 }
24 } else {
/*
* Compositing is necessary.
* Get floating-point alpha and its complement.
* Note: alpha is always linear; gamma does not
* affect it.
*/
25 alpha = (float) ialpha / fg_maxsample;
26 compalpha = 1.0 - alpha;
27 for (i = 0; i < 3; i++) {
/*
* Convert foreground and background to floating
* point, then undo gamma encoding.
*/
28 gamfg = (float) foreground[i] / fg_maxsample;
29 linfg = pow(gamfg, 1.0 / fg_gamma);
30 gambg = (float) background[i] / bg_maxsample;
31 linbg = pow(gambg, 1.0 / bg_gamma);
/*
* Composite.
*/
32 comppix = linfg * alpha + linbg * compalpha;
/*
* Gamma correct for display.
* Convert to integer frame buffer pixel.
*/
33 gcvideo = pow(comppix, 1.0 / display_exponent);
34 fbpix[i] = (int) (gcvideo * fb_maxsample + 0.5);
35 }
36 }
变体
/*
* Gamma encode for storage in output datastream.
* Convert to integer sample value.
*/
gamout = pow(comppix, outfile_gamma);
outpix[i] = (int) (gamout * out_maxsample + 0.5);此外,当 alpha 为零时,必须处理背景像素,而不是简单地跳过。因此,第 15 行需要用第 17-23 行的副本替换,但处理的是背景像素值而不是前景像素值。/*
* Convert frame buffer value into intensity sample.
*/
gcvideo = (float) fbpix[i] / fb_maxsample;
linbg = pow(gcvideo, display_exponent);然而,这可能会导致一些舍入误差,因此如果可能,最好保留原始的背景像素。注意:在浮点运算中,不需要进行溢出或下溢检查,因为输入采样值保证在 0 和 1 之间,且合成结果始终在输入值之间(含边界)。使用整数运算时,可能需要进行舍入误差分析以确保没有溢出或下溢。
在显示带有完整 alpha 通道的 PNG 图像时,能够将图像与某个背景(即使只是黑色)进行合成非常重要。忽略 alpha 通道会导致那些由关联 alpha 表示法转换而来的 PNG 图像看起来不正确。(当然,如果 alpha 通道是独立的透明度遮罩,则忽略 alpha 是一个有用的选项:它允许恢复图像中隐藏的部分。)
即使解码器没有实现真正的合成逻辑,处理只包含零和一 alpha 值的图像也很简单。(对于使用 tRNS 数据块的灰度和真彩色 PNG 数据流,这一点是隐含成立的;对于索引色 PNG 数据流,检查 tRNS 数据块是否包含 0 和 255 以外的值很容易。)在这种简单情况下,透明像素被背景颜色替换,其他像素保持不变。
如果解码器仅具备此程度的透明度能力,它应该通过将所有非零 alpha 值视为完全不透明或通过抖动来处理完整的 alpha 通道。这两种方法对于从关联 alpha 格式转换而来的图像都不会产生很好的效果,但这总比什么都不做要好。将完整 alpha 抖动到二进制 alpha 非常类似于将灰度抖动到黑白,不同之处在于所有完全透明和完全不透明的像素在抖动过程中应保持不变。
对于在索引色硬件上运行且试图显示真彩色图像,或者索引色图像的调色板对于帧缓冲区而言太大的查看器,编码器可能已在 sPLT 数据块中提供了一个或多个建议调色板。如果根据大小或名称发现其中一个合适,PNG 解码器可以使用该调色板。采样深度与解码器需求不同的建议调色板可以使用采样深度重缩放进行转换(参见 13.12 采样深度重缩放)。
当背景为纯色时,查看器应将图像和建议调色板与该颜色进行合成,然后将生成的图像量化为结果 RGB 调色板。当图像使用透明度且背景不是纯色时,通常没有建议调色板是有用的。
对于真彩色图像,建议调色板也可以在 PLTE 数据块中提供。如果图像有 tRNS 数据块且背景是纯色,查看器将需要调整建议调色板以适应其所需的背景颜色。为此,应将最接近 tRNS 颜色的调色板条目替换为所需的背景颜色;或者,如果查看器能够处理比 PLTE 条目更多的颜色,也可以为背景颜色添加一个调色板条目。
对于颜色类型 6(带 alpha 的真彩色)的图像,任何 PLTE 数据块都应设计用于在由 bKGD 数据块指定的颜色背景上显示图像。如果查看器打算使用不同的背景,或者缺少 bKGD 数据块,则可能应该忽略该调色板。查看器可以使用建议调色板在与预期不同的背景上进行显示,但结果可能不会太好。
如果查看器在比纯色背景更复杂的背景上呈现透明真彩色图像,建议调色板不太可能是合成图像的最佳选择。在这种情况下,最好对真彩色 PNG 图像和背景图像执行真彩色合成步骤,然后对生成的图像进行颜色量化。
在真彩色 PNG 数据流中,如果 PLTE 和 sPLT 数据块同时出现,PNG 解码器可以从中选择,同时牢记上述不同的透明度语义。
当查看器无法提供 PNG 数据流中调色板所使用的颜色数量时,sPLT 和 hIST 数据块中的频率信息非常有用。如果查看器仅短缺少量颜色,通常只需从调色板中删除使用最少的颜色即可。若要大幅减少颜色数量,最好选择全新的代表颜色,而不是尝试使用现有调色板的子集。这相当于执行一次新的颜色量化步骤;然而,可以使用现有的调色板和直方图作为输入数据,从而避免扫描 IDAT 数据块中的图像数据。
如果没有提供建议调色板,解码器可以自行开发一个,代价是对 IDAT 数据块中的图像数据进行额外的扫描。或者,可以使用默认调色板(通常是颜色立方体)。
另请参见 12.5 建议调色板。
建议作者在考虑引入新数据块类型之前,先查看本规范和 [PNG-EXTENSIONS] 中的现有数据块类型。预计在 [PNG-EXTENSIONS] 中的数据块类型支持程度将低于本规范中定义的类型。
PNG 编辑器的两个示例是:一个添加或修改文本数据块的程序,以及一个向真彩色 PNG 数据流添加建议调色板的程序。普通图像编辑器不是PNG 编辑器,因为它们通常在读取图像时丢弃所有未识别的信息。
为了允许将新数据块类型添加到 PNG,必须建立所有数据块类型的排序要求规则。否则,PNG 编辑器在遇到未知数据块时将不知道该怎么办。
示例:考虑一种假设的新辅助数据块类型,它是安全复制的,并且如果 PLTE 存在,则要求出现在 PLTE 之后。如果程序试图添加一个 PLTE 数据块且不识别该新数据块,它可能会将 PLTE 数据块插入错误的位置,即在新数据块之后。通过要求 PNG 编辑器丢弃所有未知数据块可以防止此类问题,但这是一种非常不受欢迎的解决方案。相反,PNG 要求辅助数据块不具有这样的排序限制。
为了防止此类问题并允许未来扩展,对 PNG 编辑器的行为和允许的数据块排序要求都设置了约束。安全复制位定义了在正在修改的数据流中处理未识别数据块的正确方式。
数据块排序的规则如下。
这些规则是以将数据块从输入数据流复制到输出数据流的方式表达的,但如果 PNG 数据流是在原地修改的,它们也以明显的方式适用。
另请参见 5.4 数据块命名约定。
不更改图像数据的PNG 编辑器不应更改 tIME 数据块。tEXt、zTXt 和 iTXt 数据块中的创建时间关键字可用于用户提供的时间。
关键数据块可能有任意的排序要求,因为 PNG 编辑器被要求在遇到未知关键数据块时终止。例如,IHDR 有具体的排序规则,即它必须始终首先出现。PNG 编辑器,或者实际上任何 PNG 写入程序,都必须了解并遵循其可以生成的任何关键数据块类型的排序规则。
辅助数据块类型最严格的排序规则是:
任何特定辅助数据块类型的实际排序规则可能更宽松。请参见 5.6 数据块排序中标准辅助数据块类型的排序规则。
解码器不得对任何辅助数据块的定位做出超出数据块排序规则所规定的假设。特别是,假设特定的辅助数据块类型相对于其他辅助数据块有任何特定的定位是永远无效的。
示例:假设特定的私有辅助数据块紧接在 IEND 之前是不安全的。即使它总是由特定程序写在该位置,PNG 编辑器也可能在其之后插入了其他辅助数据块。但假设该数据块将保留在 IDAT 和 IEND 之间的某个位置是安全的。
除了标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。
本文档中的关键字 MAY、MUST、SHALL、SHOULD 和 SHOULD NOT 仅在以全大写形式出现时(如图所示),应按 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释。
本条款涉及 PNG 数据流、PNG 编码器、PNG 解码器和 PNG 编辑器的一致性。
本条款规范的主要目标是:
一致性是针对 PNG 数据流以及 PNG 编码器、解码器和编辑器定义的。
本条款涉及 PNG 数据流和实现要求,包括 PNG 编码器、PNG 解码器和 PNG 编辑器允许的差异范围。本条款不直接涉及编码器、解码器或编辑器的环境、性能或资源要求。
本条款的范围仅限于 PNG 数据流公开交换的规则。
如果满足以下条件,PNG 数据流即符合本规范。
如果 PNG 编码器满足以下条件,则其符合本规范。
如果 PNG 解码器满足以下条件,则其符合本规范。
如果 PNG 编辑器满足以下条件,则其符合本规范。
这更新了现有的 image/png 互联网媒体类型,属于 image 顶级类型。本附录符合 BCP 13 和 W3CRegMedia。
PNG 文档由一组明确类型化的“数据块”集合组成。对于 PNG 规范中定义的每种数据块类型(gIFx 除外),与这些数据块相关联的唯一作用是导致图像在接收方的显示器或打印机上呈现。
gIFx 数据块类型用于封装应用程序扩展数据,对该数据的使用可能会带来安全风险,尽管目前尚无已知风险。同样,无法评估与未来数据块类型相关的安全风险,特别是未注册的数据块。然而,PNG 工作组的意图是不允许包含“可执行”数据的数据块成为注册数据块。
文本数据块 tEXt、iTXT 和 zTXt 包含可以以注释等形式显示的数据。一些操作系统或终端可能允许显示带有嵌入控制字符的文本数据,以执行诸如重新映射键、创建文件等操作。因此,本规范建议在直接显示之前对文本数据块进行控制字符过滤。
PNG 格式专门设计用于促进文件传输错误的早期检测,并利用循环冗余校验来确保其数据块中所含数据的完整性。
此注册更新了之前的注册
本附录符合 BCP 13 和 W3CRegMedia。
APNG 文档由一组明确类型化的“数据块”集合组成。对于 PNG 规范中定义的每种数据块类型(gIFx 除外),与这些数据块相关联的唯一作用是导致动画图像在接收方的显示器上呈现。
gIFx 数据块类型用于封装应用程序扩展数据,对该数据的使用可能会带来安全风险,尽管目前尚无已知风险。同样,无法评估与未来数据块类型相关的安全风险,特别是未注册的数据块。然而,PNG 工作组的意图是不允许包含“可执行”数据的数据块成为注册数据块。
文本数据块 tEXt、iTXt 和 zTXt 包含可以以注释等形式显示的数据。一些操作系统或终端可能允许显示带有嵌入控制字符的文本数据,以执行诸如重新映射键、创建文件等操作。因此,本规范建议在直接显示之前对文本数据块进行控制字符过滤。
PNG 格式专门设计用于促进文件传输错误的早期检测,并利用循环冗余校验来确保其数据块中所含数据的完整性。
如果有人创建了一个包含无关静态图像和动画图像数据块的 APNG 文件,使用不支持 APNG 格式的工具的人将只能看到静态图像,而不会意识到额外内容的存在。这可能会被用于例如绕过审核。
image/apng 自 2015 年以来已在广泛、未注册的使用中。动画 PNG 直到 2022 年才成为官方 PNG 规范的一部分。此注册加上 PNG 规范(第三版)将官方文档与已经广泛部署的现实相统一。
本节是非规范性的。
以下规定了私有数据块定义的准则:
本节是非规范性的。
伽马值是一个数值参数,用于描述图像采集和再现中遇到的某些非线性传递函数的近似值。伽马值是幂律函数中的指数。例如,函数:
强度 = (电压 + 常数)指数
被用于模拟 CRT 显示器的非线性。通常假设(如本国际标准中那样)该常数为零。
就本规范而言,考虑通用图像管线中可能出现非线性传递函数的五个位置是方便的,这些位置可以用幂律来建模。与每个位置相关的特征指数被赋予了一个特定的名称。
| input_exponent | 图像传感器的指数。 |
| encoding_exponent | 由写入数据流的流程或设备执行的任何传递函数的指数。 |
| decoding_exponent | 由读取图像数据流的软件执行的任何传递函数的指数。 |
| LUT_exponent | 在帧缓冲区和显示设备之间应用的传递函数的指数(通常是通过查找表应用的)。 |
| output_exponent | 显示设备的指数。对于 CRT,这通常是一个接近 2.2 的值。 |
定义一些描述某些复合传递函数或阶段组合的额外实体是方便的。
| display_exponent | 在帧缓冲区和显示设备的显示表面之间应用的传递函数的指数。display_exponent = LUT_exponent * output_exponent
|
| 伽马函数 (gamma) | 将显示输出强度映射到 PNG 数据流中采样的函数指数。gamma = 1.0 / (decoding_exponent * display_exponent) |
| end_to_end_exponent | 将图像传感器输入强度映射到显示输出强度的函数指数。这通常是 1.0 到 1.5 范围内的值。 |
PNG gAMA 数据块用于记录伽马值。解码器可以使用此信息以及关于显示环境的额外信息,以实现或近似所需的显示输出。
关于此主题的额外信息可在 [GAMMA-FAQ] 中找到。
以下示例代码(信息性)代表了 PNG 数据块中采用的 CRC(循环冗余校验)的实际实现。(另请参见 ISO 3309 [ISO-3309] 或 ITU-T V.42 [ITU-T-V.42] 获取正式规范。)
示例代码使用 ISO C [ISO_9899] 编程语言。 表 31 中的提示可能有助于非 C 语言用户更轻松地阅读代码。
| 运算符 | 描述 |
|---|---|
&
|
按位 AND 运算符。 |
^
|
按位异或运算符。 |
>>
|
按位右移运算符。当应用于此处所示的无符号量时,右移会在左侧插入零。 |
!
|
逻辑 NOT 运算符。 |
++
|
“n++”递增变量 n。在“for”循环中,它在变量被测试后应用。 |
0xNNN
|
0x 引入一个十六进制(以 16 为底)常量。后缀 L 表示长整型值(至少 32 位)。 |
/* Table of CRCs of all 8-bit messages. */
unsigned long crc_table[256];
/* Flag: has the table been computed? Initially false. */
int crc_table_computed = 0;
/* Make the table for a fast CRC. */
void make_crc_table(void)
{
unsigned long c;
int n, k;
for (n = 0; n < 256; n++) {
c = (unsigned long) n;
for (k = 0; k < 8; k++) {
if (c & 1)
c = 0xedb88320L ^ (c >> 1);
else
c = c >> 1;
}
crc_table[n] = c;
}
crc_table_computed = 1;
}
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
should be initialized to all 1's, and the transmitted value
is the 1's complement of the final running CRC (see the
crc() routine below). */
unsigned long update_crc(unsigned long crc, unsigned char *buf,
int len)
{
unsigned long c = crc;
int n;
if (!crc_table_computed)
make_crc_table();
for (n = 0; n < len; n++) {
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
}
return c;
}
/* Return the CRC of the bytes buf[0..len-1]. */
unsigned long crc(unsigned char *buf, int len)
{
return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
}
本节是非规范性的。
本附录提供了 PNG 软件开发人员的一些互联网资源位置。受互联网性质影响,该列表不完整且易于更改。
ICC 配置文件规范可在以下网址获得:https://www.color.org/
有一个 PNG 的万维网站点,网址为 http://www.libpng.org/pub/png/。该页面是获取关于 PNG 和 PNG 相关工具当前信息的中心位置。
关于 deflate 的额外文档和可移植 C 代码,以及优化的 CRC 算法实现,可从 zlib 网站 https://www.zlib.net/ 获取。
一个可移植 C 语言示例实现 libpng 可在 http://www.libpng.org/pub/png/libpng.html 获得。libpng 的示例查看器和编码器应用程序可在 http://www.libpng.org/pub/png/book/sources.html 获得,并在 PNG: The Definitive Guide [ROELOFS] 中有详细描述。测试图像也可以从 PNG 网站访问。
本节是非规范性的。
Video Full Range Flag 的解释更好添加了三个先前定义但非官方的动画 PNG (APNG) 数据块
这使 PNG 规范与广泛部署的行业实践保持一致。
添加了 cICP 数据块(视频信号类型识别的编码无关码点),其中包含 [ITU-T-H.273] 中定义的图像格式元数据,使 PNG 能够包含 [ITU-R-BT.2100] 高动态范围 (HDR) 和宽色域 (WCG) 图像。
对于定义图像颜色空间的数据块,如果存在多个,则优先顺序明确定义。
先前定义的 eXIf 数据块已从 PNG-Extensions 文档 [PNG-EXTENSIONS] 移至本规范正文,以反映其日益增长的使用。
为了帮助 HDR 内容的色调映射,添加了 mDCV 数据块(包含有关母版制作中使用的显示器的元数据)和 cLLI(包含有关峰值和平均亮度水平的元数据)。这实现了异构平台上更准确的颜色匹配
澄清了包含 ICC 配置文件的 iCCP 数据块可以包含符合 ICC.1 规范任何版本的配置文件。PNG 第二版仅引用了当时最新的 ICC.1 v2,尽管此后使用更高版本也已成为行业惯例。
澄清了索引色 PNG 的越界索引处理
澄清了未知和无效辅助数据块的错误恢复
纳入了所有 PNG 第二版勘误表。值得注意的是,澄清了当嵌入 HTML 或 SVG 等格式时,具有未知伽马值的 PNG 图像必须被视为未标记图像
响应社区反馈的各种编辑澄清
引用更新为最新版本
标记更正和链接修复
文档源重新格式化以使用 ReSpec
有关 W3C 推荐标准 PNG 规范版本 1.0 与 PNG 第二版 之间更改的列表,请参见 PNG 第二版更改列表
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自
引用自