WebP 容器规范

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

简介

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

WebP 容器(即适用于 WebP 的 RIFF 容器支持对 WebP 基本用例(即包含编码为 VP8 关键帧的单张图片的文件)提供功能支持。WebP 容器可为以下各项提供额外的支持:

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

  • 元数据。图片可能包含以 Exif 或 XMP 格式存储的元数据。

  • 透明度:图像可以有透明度,即 Alpha 通道。

  • 颜色配置文件:图片可能具有国际颜色联盟定义的嵌入式 ICC 配置文件。

  • 动画:一个图像可能会有多个帧,这些帧之间具有暂停点,从而形成动画效果。

本文档中的“必须”“不得”“必需”“会”“不会”“应”“不应”“建议”“不建议”“可以”和“可选”等关键词可解读为 BCP 14 此处仅列举的 RFC 2119 中的示例

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

命名

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

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

术语和基础知识

WebP 文件包含静态图片(即编码后的像素矩阵)或动画。它还可以选择包含透明度信息、颜色配置文件和元数据。如果我们只需要引用像素矩阵,则称为图像的画布。

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

读者/写入者
读取 WebP 文件的代码称为读取者,而写入它们的代码称为写入者
uint16
16 位、小端字节序,无符号整数。
uint24
24 位小端字节序,无符号整数。
uint32
一个 32 位小端的无符号整数。
FCC
FourCC(四个字符的代码)是一个uint32,通过以小端字节序的顺序串联四个 ASCII 字符而创建。这意味着“aaaa”(0x61616161) 和“AAAA”(0x41414141) 被视为不同的 FourCC
从 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 个字节,因此整个文件的大小最多为 4GiB 减去 2 个字节。
“WEBP”:32 位
ASCII 字符“W”、“E”、“B”、“P”。

WebP 文件必须以 FFFCC“WEBP”的 RIFF 标头开始。标头中的文件大小为后跟的分块的总大小,外加 4 字节的“WEBP”FourCC。文件不得包含 File Size 指定的数据。读取器可以解析此类文件,并忽略尾随数据。由于任何分块的大小都是偶数,因此 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 数据:块大小字节
VP8 比特流数据。

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

您可以在 VP8 数据格式和解码指南中找到 VP8 比特流格式规范。请注意,VP8 帧头包含 VP8 帧宽度和高度。这被假定为画布的宽度和高度。

VP8 规范说明了如何将图片解码为 Y'CbCr 格式。如需转换为 RGB,应使用 Rec. 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 数据:块大小字节
VP8L 比特流数据。

如需了解 VP8L 比特流的当前规范,请参阅 WebP 无损比特流格式。请注意,VP8L 标头包含 VP8L 映像的宽度和高度。这假定为画布的宽度和高度。

扩展文件格式

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

扩展格式文件包括:

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

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

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

  • 图片数据。

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

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

  • 可选的未知分块列表。

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

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

所有区块的放置顺序应与上面列出的顺序相同。如果某个区块出现在错误的位置,则说明该文件无效,但读者可以解析该文件,而忽略不按顺序排列的区块。

说明:通过设置分块的顺序,可以加快文件解析速度。例如,如果“ALPH”区块未出现在其所需位置,解码器可以选择停止搜索该区块。忽略延迟数据块的规则应该使需要执行完整搜索的程序获得与提前停止的结果相同的结果。

扩展的 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 位
如果文件包含 ICC 配置文件,则设置此字段。
Alpha (L):1 位
设置图片的任何帧是否包含透明度信息(“alpha”)。
Exif 元数据 (E):1 位
如果文件包含 Exif 元数据,请设置。
XMP 元数据 (X):1 位
如果文件包含 XMP 元数据,则设置此字段。
动画 (A):1 位
如果这是动画图片,请设置。应使用“ANIM”和“ANMF”分块中的数据控制动画。
预留 (R):1 位
必须为 0。读者必须忽略此字段。
预留:24 位
必须为 0。读者必须忽略此字段。
画布宽度减去 1:24 位
画布的从 1 开始的宽度(以像素为单位)。 实际画布宽度为 1 + Canvas Width Minus One
画布高度减去一:24 位
画布的高度(从 1 开始,以像素为单位)。实际画布高度为 1 + Canvas Height Minus One

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

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

动画

动画由 ANIM 和 ANMF 分块控制。

ANIM Chunk:

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

 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] 字节顺序排列。此颜色可用于填充帧周围画布上未使用的空间,以及第一帧的透明像素。当处理方法为 1 时,也会使用背景颜色。

注意

  • 即使未设置 VP8X 分块中的 Alpha 标志,背景颜色也可以包含非不透明 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
帧宽度减去一:24 位 (uint24)
帧的从 1 开始的宽度。 帧宽度为 1 + Frame Width Minus One
帧高度减去一: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 混合,方法是考虑图片的颜色配置文件。如果没有颜色配置文件,则假定使用 sRGB。(请注意,由于伽马约为 2.2,因此 sRGB 也需要进行线性处理)。

帧数据:数据块大小 - 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:预测器 = 0
  • 方法 1:预测器 = A
  • 方法 2:预测器 = B
  • 方法 3:Predictor = clip(A + B - C)

其中 clip(v) 等于:

  • 如果 v < 0,则为 0
  • v 255(大于 255)
  • v ,否则

最终值是通过将解压缩值 X 添加到预测器并使用 modulo-256 算术将 [256..511] 范围封装到 [0..255] 中得到的:

alpha = (predictor + X) % 256

存在最左边和最顶部的像素位置的特殊情况:

  • 位置 (0, 0) 的左上角值使用 0 作为预测值。否则,
  • 对于水平过滤或渐变过滤方法,系统会使用位置 (0, y-1) 正好预测位置 (0, y) 处的最左边的像素。
  • 对于垂直过滤或渐变过滤方法,系统会使用位置 (x-1, 0) 来预测位置 (x, 0) 处的最顶层像素。

解码器无需以任何指定的方式使用这些信息。

压缩方法 (C):2 位

使用的压缩方法:

  • 0:无压缩。
  • 1:使用 WebP 无损格式进行压缩。
Alpha 位流:数据块大小 - 1 个字节

经过编码的 Alpha 比特流。

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

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

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

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

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

    说明:该维度已从其他来源已知,因此再次存储该维度会造成冗余并容易出错。

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

    说明:与其他规范相比,绿色通道可以在规范中采用额外的转换步骤,与其他可以改善压缩方式的做法是不同的。

Bitstream (VP8/VP8L)

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

比特流分块可以是 (i) 使用 VP8 分块(作为标记的第四个字符空间)作为其标记,或 (ii) 使用 VP8L 分块作为标记。

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                           :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
颜色配置文件:数据块大小字节
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 元数据:块大小字节
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 元数据:数据块大小字节
XMP 格式的图片元数据。

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

如需了解有关元数据处理的其他指导,请参阅元数据工作组的元数据处理指南

未知数据块

系统会将 RIFF 分块(如此部分中所述)的分块标记与本文档中所述的任何分块都视为未知分块

说明:允许未知数据块为将来的格式扩展提供了配置,并且允许存储任何特定于应用的数据。

一个文件可能包含未知数据块:

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

从框架组装画布

我们在此简要介绍一下,如果使用动画图片,读者必须如何组合画布。

首先,使用“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 X, 2 * Frame Y) 为起点开始渲染解码后的帧。 宽度为 Frame Width Minus One + 1 像素 x Frame Height Minus One + 1 像素的图片使用 Blending method 渲染到画布上。

画布会显示 Frame Duration 毫秒。此过程将持续到显示“ANMF”区块提供的所有帧为止。之后会开始新的循环迭代,如果所有迭代都已完成,画布将处于最终状态。

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

assert VP8X.flags.hasAnimation
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
assert next chunk in image_data is ANMF
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
    assert VP8X.canvasWidth >= frame_right
    assert VP8X.canvasHeight >= frame_bottom
    for subchunk in 'Frame Data':
      if subchunk.tag == "ALPH":
        assert alpha subchunks not found in 'Frame Data' earlier
        frame_params.alpha = alpha_data
      else if subchunk.tag == "VP8 " OR subchunk.tag == "VP8L":
        assert bitstream subchunks not found in 'Frame Data' earlier
        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 * 1ms.
    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)
+- XYZW (unknown chunk)
+- VP8L (lossless bitstream)

具有 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)