WebP 容器规范

简介

WebP 是一种图片格式,它使用 (i) VP8 关键帧编码以有损方式压缩图片数据,或者 (ii) WebP 无损编码。这些编码方案应比 JPEG、GIF 和 PNG 等旧格式更高效。它针对通过网络(例如网站)快速传输图片进行了优化。WebP 格式也与其他格式具有同等的功能(颜色配置文件、元数据、动画等)。本文档介绍了 WebP 文件的结构。

WebP 容器(即 WebP 的 RIFF 容器)可在 WebP 的基本用例(即包含编码为 VP8 关键帧的单张图片)的基础上及更基本的功能支持。WebP 容器为以下各项提供了额外的支持:

  • 无损压缩:可以使用 WebP 无损格式对图像进行无损压缩。

  • 元数据:图片可能包含以可交换图片文件格式 (Exif) 或可扩展元数据平台 (XMP) 格式存储的元数据。

  • 透明度:图片可能有透明度,即 alpha 通道。

  • 颜色配置文件:如国际颜色联盟所述,图片可以具有嵌入式 ICC 配置文件。

  • 动画:图像可能有多个帧,并且帧之间带有暂停,这使其成为动画。

命名

建议在引用 WebP 容器时使用以下类型:

容器格式名称WebP
文件扩展名.webp
MIME 类型图片/WebP
统一类型标识符org.webmproject.webp

术语与基础知识

本文档中的关键字“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“不推荐”“可以”和“可选”应按 BCP 14 RFC 21174 中全部的大写形式显示,且仅在以下情形中显示:

WebP 文件包含静态图片(即编码的像素矩阵)或动画。还可以选择包含透明度信息、颜色配置文件和元数据。我们将像素矩阵称为图片的“画布”

区块图中的位编号从最高有效位 (MSB 0) 的 0 开始,如 RFC 1166 中所述。

以下是本文档中使用的其他术语:

读取者/写入者
读取 WebP 文件的代码称为读取器,写入此类文件的代码称为写入器。
uint16
16 位小端字节序、无符号整数。
uint24
24 位小端字节序、无符号整数。
uint32
32 位小端字节序、无符号整数。
FourCC
四字符代码 (FourCC) 是一种 uint32,通过以小端顺序串联四个 ASCII 字符而创建。这意味着“aaaa”(0x61616161) 和“AAAA”(0x41414141) 被视为不同的 FourCCs
从 1 开始
一个无符号整数字段,存储按 -1 偏移的值,例如,此类字段会将值 25 存储为 24
ChunkHeader('ABCD')
用于描述各个分块的 FourCCChunk Size 标头,其中“ABCD”是分块的 FourCC。该元素的大小为 8 个字节。

RIFF 文件格式

WebP 文件格式基于 RIFF(资源交换文件格式)文档格式。

RIFF 文件的基本元素是数据块。其中包括:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Chunk FourCC                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Chunk Size                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                         Chunk Payload                         :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
分块 FourCC:32 位
用于识别分块的 ASCII 四字符代码。
分块大小:32 位 (uint32)
区块的大小(以字节为单位),不包括此字段、区块标识符或填充。
分块载荷:Chunk Size 字节
数据载荷。如果分块大小为奇数,则会添加一个填充字节,该字节必须为 0 以符合 RIFF。

注意:RIFF 按照惯例,全大写分块 FourCC 是适用于所有 RIFF 文件格式的标准分块,而专用于某种文件格式的 FourCC 全都小写。WebP 不遵循此惯例。

WebP 文件标题

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      'R'      |      'I'      |      'F'      |      'F'      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           File Size                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      'W'      |      'E'      |      'B'      |      'P'      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
“RIFF”:32 位
ASCII 字符“R”“I”“F”“F”。
文件大小:32 位 (uint32)
文件的大小(以字节为单位),从偏移量 8 开始。此字段的最大值为 2^32 减去 10 个字节,因此整个文件的大小最多为 4 GiB 减去 2 个字节。
“WEBP”:32 位
ASCII 字符“W”“E”“B”“P”。

WebP 文件必须以含 FourCC“WEBP”的 RIFF 标头开头。标头中的文件大小为后续区块的总大小加上“WEBP”FourCC 的 4 个字节。文件不应在文件大小指定的数据之后包含任何数据。读取程序可以解析此类文件,并忽略尾随数据。由于任何分块的大小都是偶数,因此 RIFF 标头指定的大小也是偶数。以下部分介绍了各个分块的内容。

简单文件格式(有损)

如果图片需要进行有损编码,并且不需要透明度或扩展格式提供的其他高级功能,则应使用此布局。 采用此布局的文件较小,受较旧的软件支持。

简单的 WebP(有损)文件格式:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    WebP file header (12 bytes)                |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                        'VP8 ' Chunk                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

“VP8”区块:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('VP8 ')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                           VP8 data                            :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8 数据:Chunk Size 字节
VP8 比特流数据。

请注意,“VP8”FourCC 中的第四个字符是 ASCII 空格 (0x20)。

VP8 数据格式和解码指南中介绍了 VP8 比特流格式规范。请注意,VP8 帧标头包含 VP8 帧宽度和高度。我们将其假定为画布的宽度和高度。

VP8 规范介绍了如何将图像解码为 Y'CbCr 格式。如需转换为 RGB,应使用建议 BT.601。应用可以使用其他转换方法,但不同解码器的视觉效果可能有所不同。

简单文件格式(无损)

注意:旧版阅读器可能不支持采用无损格式的文件。

如果图片需要进行无损编码(具有可选的透明度通道),并且不需要扩展格式提供的高级功能,则应使用此布局。

简单的 WebP(无损)文件格式:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                    WebP file header (12 bytes)                |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                         'VP8L' Chunk                          :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

“VP8L”区块:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('VP8L')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                           VP8L data                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
VP8L 数据:Chunk Size 字节
VP8L 比特流数据。

如需查看 VP8L 比特流的现行规范,请参阅 WebP 无损比特流格式。请注意,VP8L 头文件包含 VP8L 图片宽度和高度。我们将其假定为画布的宽度和高度。

扩展文件格式

注意:旧版阅读器可能不支持使用扩展格式的文件。

扩展格式文件包含以下内容:

  • “VP8X”区块,包含文件中所用功能的相关信息。

  • 具有颜色配置文件的可选“ICCP”块。

  • 包含动画控制数据的可选“ANIM”块。

  • 图片数据。

  • 包含 Exif 元数据的可选“EXIF”分块。

  • 可选的“XMP ”块,包含 XMP 元数据。

  • 未知分块的可选列表。

对于静态图片,图片数据由单个帧组成,该帧由以下部分组成:

对于动画图片图片数据由多个帧组成。如需详细了解帧,请参阅动画部分。

重构和色彩校正所需的所有分块,即“VP8X”“ICCP”“ANIM”“ANMF”“ALPH”“VP8”和“VP8L”都必须按上述顺序显示。当重构和色彩校正所需的分块不按顺序时,读取器应失败。

元数据未知数据块可能会不按顺序显示。

说明:重构所需的区块应首先出现在文件中,以便让读取器在接收所有数据之前开始对图像进行解码。更改元数据和自定义分块的顺序以适合实现,对应用有益。

扩展的 WebP 文件标题:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                   WebP file header (12 bytes)                 |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('VP8X')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv|I|L|E|X|A|R|                   Reserved                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Canvas Width Minus One               |             ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...  Canvas Height Minus One    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
预留 (Rsv):2 位
必须是 0。读取器必须忽略此字段。
ICC 配置文件 (I):1 位
如果文件包含“ICCP”块,请设置。
Alpha (L):1 位
如果图片的任何帧包含透明度信息(“alpha”),则设置此项。
Exif 元数据 (E):1 位
如果文件包含 Exif 元数据,请设置此项。
XMP 元数据 (X):1 位
如果文件包含 XMP 元数据,请设置此项。
动画 (A):1 位
设置此图片是否为动画图片。“ANIM”和“ANMF”块中的数据应用于控制动画。
预留 (R):1 位
必须是 0。读取器必须忽略此字段。
预留:24 位
必须是 0。读取器必须忽略此字段。
画布宽度减一:24 位
画布宽度(以像素为单位),自 1 起。 画布的实际宽度为 1 + Canvas Width Minus One
画布高度减一:24 位
画布的高度,以像素为单位,以 1 为起点。 实际画布高度为 1 + Canvas Height Minus One

Canvas WidthCanvas Height 的乘积不得超过 2^32 - 1

未来规范中可能会添加更多字段。必须忽略未知字段。

动画

动画由“ANIM”和“ANMF”块控制。

“ANIM”文本块:

对于动画图片,此数据块包含动画的全局参数

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ANIM')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Background Color                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Loop Count           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
背景颜色:32 位 (uint32)
画布的默认背景颜色,以 [Blue, Green, Red, Alpha] 字节顺序表示。此颜色可用于填充帧周围画布上未使用的空间,以及第一帧的透明像素。当 Disposal 方法是 1 时,也会使用背景颜色。

注意

  • 背景颜色可以包含非不透明 Alpha 值,即使“VP8X”分块中的 Alpha 标志未设置也是如此。

  • 查看器应用应将背景颜色值视为提示,而不是使用该值。

  • 画布会在每次循环开始时清除。为此,可以使用背景颜色。

循环计数:16 位 (uint16)
动画循环播放的次数。如果为 0,则表示无限。

如果设置了“VP8X”分块中的 Animation 标志,该分块必须显示。 如果未设置 Animation 标记,且存在此分块,则必须忽略它。

“ANMF”区块:

对于动画图片,此数据块包含有关单个帧的信息。如果未设置动画标志,则不应存在此分块。

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ANMF')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Frame X                |             ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...          Frame Y            |   Frame Width Minus One     ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...             |           Frame Height Minus One              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                 Frame Duration                |  Reserved |B|D|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                         Frame Data                            :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
帧 X:24 位 (uint24)
帧左上角的 X 坐标为 Frame X * 2
帧 Y:24 位 (uint24)
帧左上角的 Y 坐标为 Frame Y * 2
帧宽度减 1:24 位 (uint24)
帧的宽度,从 1 开始。 框架宽度为 1 + Frame Width Minus One
帧高度减 1:24 位 (uint24)
帧的高度,基于 1。 帧高度为 1 + Frame Height Minus One
帧时长:24 位 (uint24)
显示下一帧前的等待时间(以 1 毫秒为单位)。 请注意,对帧时长为 0(通常 <= 10)的解释由实现定义。许多工具和浏览器会指定与 GIF 类似的最短时长。
预留:6 位
必须是 0。读取器必须忽略此字段。
混合方法 (B):1 位

指示当前帧的透明像素如何与上一个画布的相应像素混合:

  • 0:使用 alpha 混合。处理好上一帧后,使用 Alpha 混合渲染在画布上渲染当前帧(见下文)。如果当前帧没有 Alpha 通道,则假定 alpha 值为 255,从而有效地替换了矩形。

  • 1:请勿混合。处理上一帧后,通过覆盖当前帧覆盖的矩形,在画布上渲染当前帧。

处置方法 (D):1 位

指示当当前帧在画布上显示后(渲染下一帧之前)时该如何处理该帧:

  • 0:请勿丢弃。将画布保持原样。

  • 1:处理背景颜色。使用“ANIM”区块中指定的背景颜色填充当前框架所覆盖画布上的矩形

注意

  • 帧处置仅适用于帧矩形,即由帧 X帧 Y帧宽度帧高度定义的矩形。不一定能覆盖整个画布。

  • Alpha 版混合:

    假设 R、G、B 和 A 每个通道都是 8 位,并且 RGB 通道未按 alpha 预乘,那么将“dst”混合到“src”的公式为:

    blend.A = src.A + dst.A * (1 - src.A / 255)
    if blend.A = 0 then
      blend.RGB = 0
    else
      blend.RGB =
          (src.RGB * src.A +
           dst.RGB * dst.A * (1 - src.A / 255)) / blend.A
    
  • Alpha 混合应在线性颜色空间中进行,方法是考虑图片的颜色配置文件。如果颜色配置文件不存在,则假定采用标准 RGB (sRGB)。(请注意,由于灰度系数约为 2.2,因此 sRGB 也需要线性化。)

帧数据:Chunk Size - 16 字节

包含:

注意:“ANMF”载荷“帧数据”由各个填充的区块组成,如 RIFF 文件格式所述。

Alpha

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ALPH')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Rsv| P | F | C |     Alpha Bitstream...                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
预留 (Rsv):2 位
必须是 0。读取器必须忽略此字段。
预处理 (P):2 位

这些信息性位用于指示在压缩期间执行的预处理。解码器可以使用此信息在显示之前对值进行抖动或平滑处理。

  • 0:不预处理。
  • 1:降低级别。

解码器无需以任何指定方式使用此类信息。

过滤方法 (F):2 位

下面介绍了所使用的过滤方法:

  • 0:无。
  • 1:横向过滤条件。
  • 2:纵向过滤条件。
  • 3:渐变滤镜。

对于每个像素,使用以下计算执行过滤。假设当前 X 位置周围的 Alpha 值标记为:

 C | B |
---+---+
 A | X |

我们设法计算位置 X 处的 alpha 值。首先,根据过滤方法进行预测:

  • 0 方法:predictor = 0
  • 1 方法:predictor = A
  • 方法 2:predictor = B
  • 方法 3:predictor = clip(A + B - C)

其中 clip(v) 等于:

  • 如果 v < 0,则为 0,
  • 如果 v > 255,则为 255,或
  • v 否则

最终值通过以下方式得出:将解压缩的值 X 添加到预测器,并使用模 256 算术将 [256..511] 范围封装到 [0..255] 范围中:

alpha = (predictor + X) % 256

最左边和最顶部的像素位置有一些特殊情况。例如,位置 (0, 0) 处的左上角值使用 0 作为预测器值。否则:

  • 对于水平或渐变过滤方法,系统使用正上方位置 (0, y-1) 预测位置 (0, y) 最左侧的像素。
  • 对于垂直或渐变过滤方法,位置 (x, 0) 最上方的像素是使用左侧的位置 (x-1, 0) 预测的。
压缩方法 (C):2 位

使用的压缩方法:

  • 0:不压缩。
  • 1:使用 WebP 无损格式压缩。
Alpha 比特流:分块大小 - 1 字节

已编码的 Alpha 比特流。

此可选分块包含该帧的已编码 Alpha 数据。包含“VP8L”区块的帧不应包含此区块。

说明:透明度信息已经是“VP8L”分块的一部分。

Alpha 通道数据存储为未压缩的原始数据(当压缩方法为“0”时),或使用无损格式进行压缩(当压缩方法为“1”时)。

  • 原始数据:由长度 = 宽度 * 高度的字节序列组成,包含按扫描顺序排列的所有 8 位透明度值。

  • 无损格式压缩:字节序列是隐式维度“宽 x 高”的压缩图像流(如“WebP 无损比特流格式”中所述)。也就是说,此图片数据流不包含任何描述图片尺寸的标头。

    说明:这些维度从其他来源已知,因此再次存储这些维度是多余的,并且容易出错。

    将图像流解码为 Alpha、红色、绿色、蓝色 (ARGB) 颜色值后,按照无损格式规范中描述的过程,必须从 ARGB 四元组的绿色通道提取透明度信息。

    说明:绿色通道在规范中允许具有可以改善压缩效果的额外转换步骤(与其他通道不同)。

比特流 (VP8/VP8L)

此分块包含单个帧的压缩比特流数据。

比特流区块可以是 (i)“VP8”区块,使用“VP8”(注意第四个有效字符空格)作为其 FourCC;也可以 (ii) “VP8L”区块,使用“VP8L”作为其 FourCC。

简单文件格式(有损)简单文件格式(无损)部分分别介绍了“VP8”和“VP8L”块的格式。

颜色配置文件

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('ICCP')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                       Color Profile                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
颜色配置文件:Chunk Size 字节
ICC 配置文件。

此数据块必须显示在图片数据之前。

此类分块最多只能有一个。如果有更多这样的分块,读取器可以忽略除第一个分块之外的所有分块。 如需了解详情,请参阅 ICC 规范

如果此数据块不存在,应假定 sRGB。

元数据

元数据可存储在“EXIF”或“XMP”块中。

每种类型(“EXIF”和“XMP”)最多应有一个分块。如果此类分块的数量超过 1 个,读取器可以忽略除第一个分块之外的所有分块。

数据块的定义如下:

“EXIF”区块:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('EXIF')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                        Exif Metadata                          :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Exif Metadata:Chunk Size 字节
Exif 格式的图片元数据。

“XMP ”文本块:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      ChunkHeader('XMP ')                      |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                        XMP Metadata                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
XMP 元数据:Chunk Size 字节
XMP 格式的图片元数据。

请注意,“XMP”FourCC 中的第四个字符是 ASCII 空格 (0x20)。

如需关于处理元数据的更多指导,请参阅元数据工作组的“处理元数据的准则”

未知块

如果某个 RIFF 分块(如 RIFF 文件格式部分所述)的 FourCC 不同于本文档中描述的任何分块,则会被视为“未知分块”。

说明:允许未知块为格式未来扩展提供准备,同时允许存储任何应用特定数据。

文件可能包含未知分块:

  • 添加到文件末尾(如扩展 WebP 文件标头部分中所述),或
  • 在“ANMF”分块的末尾添加该代码段,如动画部分中所述。

读取器应忽略这些分块。写入者应按原始顺序保留这些区块(除非他们特别打算修改这些区块)。

通过框架组装画布

在下文中,我们将概述对于动画图片,读取器必须如何组装画布。

首先,使用“VP8X”区块中指定的尺寸创建画布,宽 Canvas Width Minus One + 1 像素,高 Canvas Height Minus One + 1 像素。“ANIM”块中的 Loop Count 字段用于控制动画过程的重复次数。如果 Loop Count 值不为零,则为 Loop Count - 1;如果 Loop Count 为零,则为无限值。

在每次循环迭代开始时,系统会使用“ANIM”块中的背景颜色或应用定义的颜色来填充画布。

“ANMF”分块包含按显示顺序给出的各个帧。在渲染每一帧之前,系统会应用上一帧的 Disposal method

从笛卡尔坐标(2 * Frame X2 * Frame Y)开始渲染解码帧,并使用画布的左上角作为原点。Frame Width Minus One + 1(宽)x Frame Height Minus One + 1(高)像素通过 Blending method 渲染到画布上。

画布显示 Frame Duration 毫秒。此过程会一直持续到显示“ANMF”块给出的所有帧。然后,新的循环迭代开始;如果所有迭代都已完成,则画布将保持最终状态。

以下伪代码说明了渲染过程。表示法 VP8X.field 是指“VP8X”块中具有相同说明的字段。

VP8X.flags.hasAnimation MUST be TRUE
canvas ← new image of size VP8X.canvasWidth x VP8X.canvasHeight with
         background color ANIM.background_color.
loop_count ← ANIM.loopCount
dispose_method ← Dispose to background color
if loop_count == 0:
  loop_count = ∞
frame_params ← nil
next chunk in image_data is ANMF MUST be TRUE
for loop = 0..loop_count - 1
  clear canvas to ANIM.background_color or application-defined color
  until eof or non-ANMF chunk
    frame_params.frameX = Frame X
    frame_params.frameY = Frame Y
    frame_params.frameWidth = Frame Width Minus One + 1
    frame_params.frameHeight = Frame Height Minus One + 1
    frame_params.frameDuration = Frame Duration
    frame_right = frame_params.frameX + frame_params.frameWidth
    frame_bottom = frame_params.frameY + frame_params.frameHeight
    VP8X.canvasWidth >= frame_right MUST be TRUE
    VP8X.canvasHeight >= frame_bottom MUST be TRUE
    for subchunk in 'Frame Data':
      if subchunk.tag == "ALPH":
        alpha subchunks not found in 'Frame Data' earlier MUST be
          TRUE
        frame_params.alpha = alpha_data
      else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
        bitstream subchunks not found in 'Frame Data' earlier MUST
          be TRUE
        frame_params.bitstream = bitstream_data
    render frame with frame_params.alpha and frame_params.bitstream
      on canvas with top-left corner at (frame_params.frameX,
      frame_params.frameY), using Blending method
      frame_params.blendingMethod.
    canvas contains the decoded image.
    Show the contents of the canvas for
    frame_params.frameDuration * 1 ms.
    dispose_method = frame_params.disposeMethod

文件布局示例

采用 alpha 的有损编码图像可能如下所示:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- ALPH (alpha bitstream)
+- VP8 (bitstream)

无损编码图像可能如下所示:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- VP8L (lossless bitstream)
+- XYZW (unknown chunk)

包含 ICC 配置文件和 XMP 元数据的无损图片可能如下所示:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- ICCP (color profile)
+- VP8L (lossless bitstream)
+- XMP  (metadata)

包含 Exif 元数据的动画图片可能如下所示:

RIFF/WEBP
+- VP8X (descriptions of features used)
+- ANIM (global animation parameters)
+- ANMF (frame1 parameters + data)
+- ANMF (frame2 parameters + data)
+- ANMF (frame3 parameters + data)
+- ANMF (frame4 parameters + data)
+- EXIF (metadata)