Google 一直在寻找各种方法来加快网页加载速度。 一种方法是缩减网页图片的大小。在大多数网页上,图片占字节数的比例最高可达 60-65%,而网页大小是总渲染时间的主要因素。网页大小对移动设备而言尤为重要,因为在移动设备上,图片越小,带宽和电池续航时间就越长。
WebP 是由 Google 开发的一种新型图片格式,Chrome、Opera 和 Android 均支持该格式。该格式经过优化,可让网页上的图片更小、加载更快。与 PNG 和 JPEG 图片相比,在视觉质量相当的情况下,WebP 图片的大小大约会缩小 30%。此外,WebP 图片格式在功能上与其他格式也完全兼容。它支持:
有损压缩:有损压缩基于 VP8 关键帧编码。VP8 是由 On2 Technologies 创建的视频压缩格式,是 VP6 和 VP7 格式的后继者。
无损压缩:无损压缩格式由 WebP 团队开发。
透明度:8 位 Alpha 通道对图形图片很有用。Alpha 通道可与有损 RGB 搭配使用,这是目前任何其他格式都不支持的功能。
动画:支持真彩动画图片。
元数据:可能包含 EXIF 和 XMP 元数据(例如相机使用的元数据)。
色彩配置文件:可能包含嵌入的 ICC 配置文件。
由于 WebP 可以更好地压缩图片,并且支持所有这些功能,因此它是大多数图片格式(PNG、JPEG 或 GIF)的绝佳替代方案。更棒的是,您知道 WebP 还能带来新的图片优化机会吗?例如,支持带透明度的有损图片。有!WebP 是图片格式的瑞士军刀。
那么,这项魔法是如何实现的?让我们撸起袖子,一探究竟。
有损 WebP
WebP 的无损压缩使用与 VP8 相同的方法来预测(视频)帧。VP8 基于块预测,与任何基于块的编解码器一样,VP8 会将帧划分为称为宏块的较小片段。
在每个宏块中,编码器可以根据之前处理的块预测冗余的运动和颜色信息。图像帧是“关键”帧,因为它仅使用每个宏块的直接空间邻域中已解码的像素,并尝试填充其未知部分。这称为预测编码(请参阅 VP8 视频的帧内编码)。
然后,系统可以从块中减去冗余数据,从而提高压缩效率。我们只剩下一个小差异(称为残差),需要以压缩形式传输。
经过数学可逆转换(著名的 DCT,即离散余弦转换)后,残差通常包含许多零值,这些值可以更有效地压缩。然后,系统会对结果进行量化和熵编码。有趣的是,量化步骤是唯一会丢弃比特的步骤(在下图中搜索除以 QPj 的操作)。所有其他步骤都是可逆的且无损的!
下图展示了 WebP 有损压缩所涉及的步骤。与 JPEG 相比的差异化功能用红色圈出。
WebP 使用块量化,并在不同的图片片段中自适应分配位数:低熵片段使用较少的位数,高熵片段使用较多的位数。WebP 使用算术熵编码,与 JPEG 中使用的 Huffman 编码相比,可实现更好的压缩效果。
VP8 内部预测模式
VP8 内插预测模式适用于三种类型的宏块:
- 4x4 亮度
- 16x16 亮度
- 8x8 色度
这些宏块共享四种常见的内部预测模式:
H_PRED(水平预测)。使用左侧列 L 的副本填充块的每个列。
V_PRED(垂直预测)。使用上述行 A 的副本填充该块的每一行。
DC_PRED(DC 预测)。使用 A 上方行和 L 左侧列中的像素的平均值,将该块填充单个值。
TM_PRED(TrueMotion 预测)。此模式的名称源自 On2 Technologies 开发的压缩技术。除了行 A 和列 L 之外,TM_PRED 还会使用相应块上方和左侧的像素 P。A 中像素(从 P 开始)之间的水平差异会使用 L 中的像素传播到每行开头。
下图展示了 WebP 有损压缩中使用的不同预测模式。
对于 4x4 的 luma 块,还有 6 种类似于 V_PRED 和 H_PRED 的额外内插模式,但这些模式对应于在不同方向预测像素。如需详细了解这些模式,请参阅 VP8 比特流指南。
自适应块量化
为了提高图片质量,系统会将图片分割成具有明显相似特征的区域。对于这些片段中的每一个,压缩参数(量化步骤、滤波强度等)都会单独进行调整。这样可以将位重新分配到最有用的位置,从而实现高效压缩。VP8 最多允许四个片段(VP8 比特流的限制)。
为什么 WebP(有损)优于 JPEG
预测编码是 WebP 胜过 JPEG 的主要原因。块自适应量化也有很大影响。过滤功能在中/低比特率下有用。 与 Huffman 编码相比,布尔算术编码可实现 5%-10% 的压缩增益。
无损 WebP
WebP 无损编码基于使用多种不同的技术来转换图片。然后,对转换参数和转换后的图片数据执行熵编码。应用于图片的转换包括像素的空间预测、颜色空间转换、使用本地出现的调色板、将多个像素打包到一个像素中,以及 Alpha 替换。对于熵编码,我们使用 LZ77-Huffman 编码的变体,该变体使用距离值和紧凑稀疏值的二维编码。
预测器(空间)转换
空间预测利用相邻像素之间通常存在关联这一事实来减少熵。在预测器转换中,当前像素值是根据已解码的像素(按扫描线顺序)预测得出的,并且仅编码残差值(实际值 - 预测值)。预测模式决定了要使用的预测类型。图片被划分为多个方形区域,一个方形中的所有像素都使用相同的预测模式。
有 13 种不同的可能预测模式。主要像素是左侧、顶部、左上角和右上角像素。其余的颜色是左侧、顶部、左上角和右上角的组合(平均值)。
颜色(去相关)转换
颜色转换的目标是解除每个像素的 R、G 和 B 值之间的相关性。颜色转换会保持绿色 (G) 值不变,根据绿色转换红色 (R),然后根据绿色和红色转换蓝色 (B)。
与预测器转换一样,首先将图片划分为多个块,并对块中的所有像素使用相同的转换模式。对于每个分块,有三种类型的颜色转换元素:green_to_red、green_to_blue 和 red_to_blue。
减去绿色转换
“减去绿色转换”会从每个像素的红色和蓝色值中减去绿色值。存在此转换时,解码器需要将绿色值添加到红色和蓝色中。这是上述一般色彩去相关性转换的一个特例,其频率足以保证截断。
颜色索引 (palette) 转换
如果不存在太多唯一的像素值,创建颜色索引数组并将像素值替换为数组的索引,可能会更高效。颜色编号转换可实现这一点。颜色编制转换会检查图片中唯一 ARGB 值的数量。如果该数量低于阈值 (256),则会创建这些 ARGB 值的数组,然后使用该数组将像素值替换为相应的索引。
颜色缓存编码
无损 WebP 压缩会使用已见的图片碎片来重构新的像素。如果未找到任何有趣的匹配项,它还可以使用本地调色板。此调色板会持续更新,以重复使用近期的颜色。在下图中,您可以看到本地颜色缓存在扫描向下进行时,会逐步更新为最近使用的 32 种颜色。
LZ77 向后引用
向后引用是长度和距离代码的元组。长度表示要按扫描线顺序复制的像素数。距离代码是一个数字,表示之前看到的像素的位置,系统会从该位置复制像素。长度和距离值使用 LZ77 前缀编码进行存储。
LZ77 前缀编码将大整数值分为两部分:前缀代码和额外位。前缀代码使用熵代码存储,而额外的位则按原样存储(不使用熵代码)。
下图展示了使用字词匹配(而非像素)的 LZ77(2D 变体)。
带有 Alpha 通道的有损 WebP
除了有损 WebP(RGB 颜色)和无损 WebP(带 Alpha 通道的无损 RGB)之外,还有另一种 WebP 模式,允许对 RGB 通道进行有损编码,对 Alpha 通道进行无损编码。目前,任何现有图片格式都无法实现这种可能性(有损 RGB 和无损 Alpha)。目前,需要透明度的网站站长必须以 PNG 格式无损编码图片,这会导致图片大小大幅膨胀。WebP alpha 以每像素低位数编码图片,并提供了一种有效的方式来缩减此类图片的大小。与有损(质量 90)WebP 编码相比,对 Alpha 通道的无损压缩只会增加 22% 字节。
总体而言,将透明 PNG 替换为有损+alpha WebP 可平均缩减 60-70% 的大小。这已被证实是富含图标的移动网站(例如 everything.me)的绝佳吸引力。