WebP随手记

用了这么久的WebP图片,最近在项目中发现对其了解得还是很不够,便以此文整理记录WebP相关知识点。

如果你能看到下面这张图,说明你当前的webview环境支持webp图片。

avatar.webp

如果你能看到下面这张动图,说明你当前的webview环境支持webp动图。

demo-animation.webp

介绍

WebP is a modern image format that provides superior lossless and lossy compression for images on the web. Using WebP, webmasters and web developers can create smaller, richer images that make the web faster.

WebP由Google在2010年发布,是一种现代图像格式,可为Web上的图像提供出色的无损和有损压缩。使用WebP,网站管理员和Web开发人员可以创建更小,更丰富的图像,从而使Web更快。

与PNG相比,WebP无损(loseless)图像的尺寸要小26%。在同等的SSIM(Structural Similarity Index,结构相似性)质量指数下,WebP有损(lossy)图像比同类JPEG图像小25-34%

Lossless WebP支持透明性(也称为Alpha通道),而仅增加了22%的字节数。对于可以接受有损RGB压缩的情况,有损WebP还支持透明性,与PNG相比,文件大小通常小3倍。

并且,Google于2014年提出了动态WebP,拓展WebP使其支持动图能力。动态WebP相比GIF支持更丰富的色彩,并且也占用更小空间,更适应移动网络的动图播放。

与PNG相比

对于libpng而言,lossy WebP不仅具有最高质量(转换)而且具有ZopfliPNG(下表1)的PNG压缩密度,其编码(下表2)和解码(下表3)的速度与PNG的速度大致相当。

p-1.png

无损WebP 、有损带透明WebP vs PNG

p-10.png

1000张网络中的PNG,对其进行压缩后,与对应的无损WebP以及有损带透明WebP比较。可见绝大部分图片经过两种WebP压缩后均比PNG要小。

lossless WebP的编码时间较长,是PNG的5倍以上,但解码速度与PNG差不多,甚至很多时候比PNG快。而WebP在编码时占用内存比PNG高25%,解码时比PNG低30%。

动态WebP vs APNG

APNG是一种基于PNG的编码,对动图的编码方式类似于WebP,都是对变化的区域进行编码。虽然理论上单张WebP要比PNG小,但有些整合成动图形式后WebP会比APNG更大:

p-11.jpg

详见专门的对比demo:http://littlesvr.ca/apng/gif_apng_webp1.html

与JPEG相比

下表显示了JPEG质量参数Q的三个不同值(50、75和95)的实验结果。质量参数50和95分别表示低比特率和高比特率下的图像压缩。我们还包括了JPEG质量参数75,因为它通常是JPEG图像的推荐质量等级。

p-2.png

与GIF相比

WebP优势:

  • WebP支持24位RGB和8位透明通道,GIF仅支持8位色彩及1位透明度。
  • WebP支持无损和有损两种模式,而且对于动态图,能同时结合有损和无损的图片。而GIF仅支持无损的压缩。WebP的有损压缩技术也更好地适应从现实世界视频中创建的动图。
  • WebP相比GIF占用更小的空间。Animated GIFs转换为有损WebP减少64%,转换成无损WebP减少19%,这对移动网络十分重要。
  • WebP使用更短的解码时间,WebP所用解码时间是GIF的57%。

劣势:

  • 其实还是环境支持不够,添加WebP支持到浏览器需要添加较多代码。

p-12.jpg

详见专门的对比demo:https://isparta.github.io/compare-webp/index_a.html#12

工具&使用

转换工具

imageMaigck

imageMaigck是一个通用型的图像处理工具,可在服务端及客户端运行使用,并且可以借助nodejs的gm包实现一些脚本服务。其基本使用可见之前整理的文章《ImageMagick和gm》

cwebp,dwebp

cwebp/dwebp的谷歌官方提供的webp转换工具,官方提供了windows/linux/mac 三个系统版本的工具,其介绍和安装可见《Getting cwebp,dwebp,and the WebP Libraries》。cwebp可以将JPEG,PNG或TIFF编码成WebP;

1
cwebp [options] -q quality input.png -o output.webp

其中option可选:

  • loss(有损压缩,默认)
  • lossless(无损压缩)
  • q:质量指数(压缩率),有损压缩有效,无损压缩忽略
  • o:输入图片名称格式
  • cwebp [options] input_file -o output_file.webp

其他选项:

  • -- string: 显式地指定输入文件。如果输入文件以’-‘开头,这个选项是有用的。这个选项必须最后显示。之后的其他选项将被忽略
  • -h-help: 简单的使用说明
  • -H-longhelp: 详细的使用说明
  • -version: 版本号
  • -lossless: 对图像进行无损编码
  • -q {float}: 指定压缩因素,范围是0-100,默认为75
  • -z {int}: 在0-9之间切换无损耗压缩模式,0级最快,9级最慢。快速模式产生的文件大小比较慢的文件要大。默认是6。如果-q或者-m之后被使用,-z将无效。
  • -alpha_q {int}: 在0-100之间指定alpha压缩系数,默认100
  • -preset {string}: 指定一组默认的参数
  • -m {int}: 在0-6之间指定压缩方法。默认值为4。
  • -resize {width} {height}: 指定宽高
  • -crop {x_position} {y_position} {width} {height}: 裁剪[x_position, y_position, width, height]区域的图像,裁剪的区域大小必须在源图像大小中
  • -mt: 如果可能的话,使用多线程编码
  • -low_memory: 减少对有损编码的内存使用
  • -size {int}: 指定目标大小(单位bytes),并不是实际结果的大小,实际结果会通过选择编码的方式,尽可能接近这一目标。如果同时指定了-size和-psnr,-psnr将无效。
  • -psnr {float}: 指定目标的PSNR(in dB),并不是实际结果的大小,实际结果会通过选择编码的方式,尽可能接近这一目标。如果同时指定了-size和-psnr,-psnr将无效。
  • -pass {int}: 设置最大传递次数,范围为1-10,默认是1。如果-size或-psnr被使用,而-pass没有被使用,则默认-pass为6。
  • -af: 自动过滤,该算法将花费额外的时间来优化过滤强度,以达到平衡的质量。
  • -jpeg_like: 更改内部参数映射,以更好地匹配JPEG压缩的预期大小。这个标记通常会生成一个与它的JPEG等价的输出文件(用于相同的-q设置),但是不会产生更少的视觉失真。
  • -f {int}: 指定过滤器的强度,范围在0(不过滤)-100(最大过滤),值越高图像就越平滑,典型的值通常在20-50之间。
  • -sharpness {int}: 指定过滤的锐度,范围在0(强)-7(弱)之间,默认为0。
  • -strong: 使用强过滤,默认使用。
  • -nostrong: 禁用强过滤。
  • -sharp_yuv: 如果需要的话,使用更精确和更清晰的RGB-YUV转换。注意,这个过程比默认的“快速”RGB-YUV转换要慢。
  • -sns {int}: 指定空间噪声形成的振幅,范围为0(弱)-100(强),默认为50。
  • -segments {int}: 在sns算法的分割过程中,改变分区的数量。范围在1到4之间。默认值是4。
  • -partition_limit {int}: 通过限制某些宏块使用的比特数来降低质量。范围是0(没有降级,默认值)到100(完全降级)。
  • -v: 打印额外的信息。
  • -print_psnr: 计算和报告平均PSNR(峰值信噪比)。
  • -print_ssim: 计算和报告平均SSIM。
  • -print_lsim: 计算和报告本地相似性度量。
  • -progress: 报告编码进展百分比。
  • -quiet: 不打印任何东西。
  • -short: 只打印简短的信息。
  • -map {int}: 输出额外的编码信息的ascii-映射。可能的映射值范围从1到6。这只是为了帮助调试。
  • -s {width} {height}: 指定输入文件实际上是由Y’CbCr实例组成,遵循ITU-R BT.601建议。
  • -pre {int}: 指定一些预处理步骤。
  • -alpha_filter {string}: 指定阿尔法平面的预测过滤方法。
  • -alpha_method {int}: 指定用于alpha压缩的算法:0或1。0表示没有压缩,1使用WebP无损格式压缩。缺省值是1。
  • -exact: 在透明区域保留RGB值。默认是关闭的,以帮助压缩。
  • -blend_alpha {int}: 该选项将alpha通道(如果存在)与源文件中指定的背景颜色混合为0xrrggbb。然后,alpha通道被重置为不透明值255。
  • -noalpha: 使用该选项将丢弃alpha通道。
  • -hint {string}: 指定输入图像类型的提示。可能的值是:照片、图片或图表。
  • -metadata {string}: 将输入文件的员输入复制到输出文件,有效值为all, none, exif, icc, xmp。默认为none。
  • -noasm: 禁用所有汇编优化。

dwebp可以将WebP解码成PNG。

1
dwebp iutput.webp -o output.png

其中选型:

  • -h: 打印用法总结。
  • -version: 打印版本号。
  • -o {string}: 指定输出文件名
  • --string: 显式地指定输入文件。如果输入文件以’-‘开头,这个选项是有用的。这个选项必须最后显示。之后的其他选项将被忽略。
  • -bmp: 将输出格式更改为未压缩的BMP。
  • -tiff: 将输出格式更改为未压缩的TIFF。
  • -pam: 将输出格式更改为PAM(保留alpha)。
  • -ppm: 将输出格式更改为PPM(丢弃alpha)。
  • -pgm: 将输出格式更改为PGM。
  • -yuv: 将输出格式更改为原始YUV。
  • -nofancy: 不适用fancy。
  • -nofilter: 即使是位流需要,也不要使用循环过滤过程。这可能会在不兼容的输出上产生可见的块,但是这会使解码速度更快。
  • -dither {strength}: 指定0到100之间的抖动强度。
  • -nodither: 禁用所有抖动(默认)。
  • -mt:如果可能的话,使用多线程进行解码。
  • -crop {x_position} {y_position} {width} {height}: 裁剪[x_position, y_position, width, height]区域的图像,裁剪的区域大小必须在源图像大小中。
  • -flip: 垂直解码图像。
  • -scale {width} {height}: 将解码的图像压缩到指定宽高。
  • -v: 打印额外的信息(特别是解码时间)。
  • -noasm: 禁用所有汇编优化。

webpmux

webmux也是处理webp的工具,从静态的webp images创建动态的webp,或者从动态的webp提取静态的webp images。以及管理XMP/EXIF数据和ICC描述文件。

语法

  • webpmux -get GET_OPTIONS INPUT -o OUTPUT
  • webpmux -set SET_OPTIONS INPUT -o OUTPUT

其中选型:

  • -get 选项:GET_OPTIONS
    • icc : 获得 ICC profile
    • exif : 获得 EXIF metadata
    • xmp : 获得 XMP metadata
    • frame n : 从动态webp文件中获得第n帧(n=0代表最后一帧率)
  • -set 选项:SET_OPTIONS
    • icc file.icc : 设置 ICC profile
    • exif file.exif : 设置 EXIF metadata
    • xmp file.xmp : 设置 XMP metadata
  • -strip 选项:STRIP_OPTIONS
    • icc : Strip ICC profile
    • exif : Strip EXIF metadata
    • xmp : Strip XMP metadata
  • -duration 选项:DURATION_OPTIONS
    • 修改帧的特定间隔的持续时间。这个选项只对动画WebP有效,对单帧文件没有影响。从第一帧开始,0代表最后一帧。
    • duration[,start[,end]]
      • -duration d\ : 设置整个动画的持续时间
      • -duration d, f\ : 设置f帧到d帧的持续时间
      • -duration d, start, end\ : 设置开始帧到结束帧的持续时间
  • -frame 选项:FRAME_OPTIONS
    • 从静态的webp images创建一个动态的webp文件
    • file_i +di[+xi+yi[+mi[bi]]]
      • file_i : 第i张webp文件
      • xi,yi : 该帧图像的偏移量
      • di : 到下一帧开始的暂停时间
      • mi : 该帧图像的处理方式,0没有背景,1有背景
      • bi : 该帧图像的混合方式,+b有混合,-b没有混合
    • -loop n
      • 循环次数,0代表无限循环,有效范围是0-65535,默认为0
    • -bgcolor A,R,G,B
      • 画布的背景颜色

使用

页面——picture标签

<picture> 元素通过包含零或多个 <source> 元素和一个 <img> 元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的子 <source> 元素,如果没有匹配的,就选择 <img> 元素的 src 属性中的URL。然后,所选图像呈现在 <img> 元素占据的空间中。

如:

1
2
3
4
<picture>
<source srcset="logo.webp" type="image/webp">
<img src="logo.png" alt="Site Logo">
</picture>

p-3.png

文件结构

一个WebP文件表示一个静态图片或动画,并可选的包含透明度、色彩配置文件和元数据等。WebP使用VP8关键帧编码以有损方式压缩图像数据,或者WebP无损编码(以及将来可能的其他编码)。

WebP容器(即WebP的RIFF容器)允许在WebP基本用例(即,包含编码为VP8关键帧的单个图像的文件)之上的功能支持。 WebP容器为以下内容提供附加支持:

  • 无损压缩。可以使用WebP无损格式无损压缩图像。
  • 元数据。图像可能具有以EXIF或XMP格式存储的元数据。
  • 透明度。图像可能具有透明度,即Alpha通道。
  • 颜色配置文件。图像可能具有国际色彩协会描述的嵌入式ICC配置文件。
  • 动画。一幅图像可能有多个帧,并且它们之间有停顿,使其成为动画。

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

Container Format Name WebP
Filename Extension .webp
MIME-type image/webp
Uniform Type Identifier org.webmproject.webp

RIFF文件格式

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

RIFF文件的基本元素是一个块。它包括:

1
2
3
4
5
6
7
8
9
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Chunk FourCC: 32 bits。用于块识别的ASCII四字符代码。
  • Chunk Size: 32 bits (uint32)。
  • Chunk Payload: Chunk Size bytes。数据有效载荷。如果“块大小”为奇数,则添加一个填充字节(应为0)。
  • ChunkHeader(‘ABCD’):这用于描述单个块的FourCC和块大小标头,其中“ ABCD”是该块的FourCC。该元素的大小为8个字节。

RIFF有一个约定,所有大写字母的FourCC是适用于任何RIFF文件格式的标准块,而特定于文件格式的FourCC都是小写的。 WebP不遵循此约定。

WebP文件首部

1
2
3
4
5
6
7
8
9
 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 bits。ASCII字符RIFF。
  • File Size:32 bits (uint32)。文件大小,以字节为单位。
  • WEBP:32 bits。ASCII字符WEBP,标识这是WebP文件

有损WebP简要文件格式

这种文件格式支持有损编码,但不包含透明度以及其他拓展特性,可以被许多旧版本软件支持。

1
2
3
4
5
6
7
 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 chunk:

1
2
3
4
5
6
7
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Chunk Header:VP8块首部,定义了VP8比特流数据的大小,以及该帧VP8数据的长宽等信息。

VP8 data:VP8比特流数据。

VP8比特流格式的定义可参考rfc6386,主要定义了如何将图像数据转换成YUV格式。

无损WebP简要文件格式

这种格式用在无损WebP编码(可选透明)并且不要求拓展特性时。需要注意的是,较旧的WebP软件可能不支持该格式。

1
2
3
4
5
6
7
 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 chunk:

1
2
3
4
5
6
7
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

属性意义类似于有损WebP的简要格式,其中VP8L的定义可参考文档:https://chromium.googlesource.com/webm/libwebp/+/master/doc/webp-lossless-bitstream-spec.txt

拓展格式

拓展格式包括:

  • VP8X用于指明使用的特性
  • 可选的‘ICCP’用于色彩配置
  • 可选的‘ANIM’用于动画控制
  • 可选的‘EXIF’用于EXIF元数据
  • 可选的‘XMP’用于XMP元数据

对于静态图像,图像数据包含一帧数据,由以下组成:

  • 一个可选的透明度子chunk
  • 1个比特流子chunk
  • 对于动态图像,图像数据则包含多帧数据。

拓展头部格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • ICC profile(I):置位时表示包含ICC配置文件。
  • Alpha(L):当图像包含透明数据时置位。
  • EXIF metadata(E)当包含EXIF元数据时置位。
  • XMP metadata(X):当包含XMP元数据时置位。
  • Animation(A):动态WebP置位,此时ANIM和ANMF数据块中的数据将会被使用来控制动画。
  • Canvas Width Minus One:画布的真实宽度是该数值+1。
  • Canvas Height Minus One:画布的真实高度是该数值+1。

动画

WebP动画被ANIM和ANMF块所控制。

ANIM Chunk:

对于一个动图,该块数据定义了动画的全局参数。

1
2
3
4
5
6
7
8
9
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Background Color: 定义画布的背景颜色,以BGRA的顺序存储。这个颜色会被填充到每帧数据没用到的区域。
  • LoopCount:循环次数,0表示无限循环。

当动画标识被置位时,该数据块必须出现。当动画标识位没出现时,该数据块会被忽略。

ANMF chunk:

对于动图,该数据块包含了一帧图像的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Frame X:该帧数据左上角X坐标为该值*2。
  • Frame Y:该帧数据左上角Y坐标为该值*2。
  • Frame Duration: 播放该帧后的延时时间,以ms为单位。
  • Blending method (B):标识如何混用前面画布的相应透明像素点。置0时,处理完前面一帧图像后,使用透明混合。置1时,不混合,渲染时直接覆盖矩形区域。
  • Disposal method (D):标识该帧数据在被显示后如何处理画布。置0时不处理;置1时将画布矩形区域转换成ANIM定义的背景颜色。
  • Frame Data:以2字节为单位,包含图像比特流数据以及可选的透明度数据。

Alpha透明

1
2
3
4
5
6
7
 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... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Pre-processing (P): 标识压缩中使用了预处理。
  • Filtering method (F): 滤波方法。0-无过滤;1-横向过滤;2-垂直过滤;3-梯度过滤。
  • Compression method (C): 0-无压缩;1-使用WebP无损格式压缩。
  • Alpha bitstream:编码的透明度比特流数据

颜色配置文件Color profile、元数据Metadata数据的文件格式类似,主要是头部ASCII码不同。

Color profile

1
2
3
4
5
6
7
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Metadata

EXIF chunk:

1
2
3
4
5
6
7
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

XMP chunk:

1
2
3
4
5
6
7
 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

原理

WebP的压缩主要分为有损压缩lossy无损压缩lossless以及有损带透明通道压缩alpha。主要原理可参照官方文档webp-compression

lossy有损WebP

有损WebP基于VP8视频编码中的预测编码方法来压缩图像数据,其基本步骤类似于JPEG压缩,主要包含格式转换、分割子块、预测编码、FDCT、量化、Z排列、熵编码,流程如下图所示,红色代表与JPEG不同的部分。

p-5.png

  • 1.格式转换:若压缩前图像数据为RGB格式,则需先进行格式转换成YUV格式,Y表示亮度分量,UV表示色度分量。之所以转换成YUV格式是因为人类视觉对亮度远比色度敏感,所以可通过适当减少色度数据的存储来节省数据占用的空间,但却不会对视觉效果造成太大影响,如可每两个或四个相邻的像素点才保存一对UV值。
  • 2.分割宏块: 接下来将数据分割成一个个8x8或16x16的宏块。
  • 3.预测编码: 预测编码的原理是基于前面编码好的宏块,预测多余的动作颜色等信息,属于帧内预测。对各宏块可使用以下几种帧内预测模式:
    • H_PRED(horizontal prediction).使用block左边的一列L来填充block中的每一列
    • V_PRED(vertical prediction):使用block上边的一行A来填充block中的每一行
    • DC_PRED(DC prediction):使用L和A中所有像素的平均值作为唯一的值填充block
    • TM_PRED(TrueMotion prediction):使用渐进的方式,记录上面一行的渐进差,以同样的差值,以L为基准拓展每一行。

p-6.png

  • 4.FDCT: FDCT(Forward Discrete Cosine Transform,正向离散余弦变换)是将一组空间域的像素点转变成频域中的系数,对每个宏块执行FDCT,使得变换后数据的低频部分分布在数据块的左上方,高频部分集中在右下方,其中左上角第一个系数称为直流系数,其他均为交流系数。
  • 5.量化: 量化是压缩中损失数据的主要步骤,它主要原理是把经过DCT变换后的宏块中每个数值除以量化表中对应的系数并取整。其中量化表中高频部分对应的系数比低频部分系数要大得多,则在经过量化后,高频部分的频率系数被大大衰减甚至许多被清零,而低频部分的频率系数则较好地被保留。由于人眼对低频部分更敏感,所以经过量化后再还原成图像对视觉效果影响较小,但数据得到有效的压缩。量化的最终目的是减少低频部分非零系数的幅值并增加高频部分零值系数的数量。
  • 6.Z排列: 为更便于后续的编码,需在编码前对数据块进行重新的排列,使得低频部分的数据排在前面,高频部分的数据排在后面,以增加数组中连续零值的数量,所以采用一种Z字型的排列方式。
  • 7.DPCM: 可用DPCM(Differential Pulse Code Modulation,差分脉冲编码调制)对直流系数进行编码。由于直流系数的数值较大,且相邻数据块的直流系数相差不大,所以可使用DPCM对相邻数据块间量化后的直流系数差值进行编码,从而提高压缩比。
  • 8.行程编码: 行程编码是一种根据相同数据重复多次的情况简化表示的算法,例如1111222222333按照行程编码表示为(1,4)(2,6)(3,3)。由于量化后的交流系数中包含较多连续零值系数,因此可用行程编码对它们进行编码来有效压缩数据长度。
  • 9.熵编码: 熵编码是一种无损数据压缩编码方式,WebP中采用布尔算术编码作为熵编码方式。和其它熵编码方法不同的地方在于,其他的熵编码方法通常是把输入的消息分割为符号,然后对每个符号进行编码,而算术编码是直接把整个输入的消息编码为一个数,一个满足(0.0 ≤ n < 1.0)的小数n。消息越长,编码表示它的间隔就越小,表示这一间隔所需的二进制位就越多。
  • 10.其他: WebP还有一些细节上的步骤,比如自适应分块(Adaptive Block Quantization, 对不同区域的宏块分配不同的压缩参数)、环路滤波等。
    • 自适应分块: 为了提高图像质量,将图像划分为具有明显相似特征的区域。对于这些段中的每一个,压缩参数(量化步骤,滤波强度等)均独立进行调整。通过将位重新分配到最有用的位置,可以产生有效的压缩。 VP8最多允许四个段(VP8比特流的限制)。
      p-7.jpg

基于以上压缩算法,可以得出为什么lossy WebP会比JPEG好:

  • 主要原因是预测编码。
  • 自适应分块也提供了较好表现。
  • 环路滤波在中、低比特率的情况下有较大帮助。
  • 算数编码相比霍夫曼增强了5%~10%的压缩能力。

VP8

提到WebP的有损压缩算法就不得不提到VP8视频格式。

loseless无损WebP

无损WebP基于使用不同的技术对图像数据进行转换,包括:预测空间变换、色彩空间转换、使用调色板、多像素打包成一个像素、alpha值替换等技术。对于熵编码,则采用改进的LZ77-Huffman编码来紧凑稀疏值,它是一种对距离值的2D编码技术。

  • 预测变量(空间)转换: 通过利用相邻像素经常相关的事实,空间预测可用于减少熵。在预测器变换中,当前像素值是从已经解码的像素中预测的(按扫描线顺序),并且仅对残差值(实际预测)进行编码。预测模式确定要使用的预测类型。图像被分成多个正方形区域,一个正方形中的所有像素都使用相同的预测模式。
  • 颜色(去相关)变换: 颜色变换的目标是去相关每个像素的R,G和B值。颜色转换将保持绿色(G)值不变,基于绿色转换红色(R),然后基于绿色然后基于红色转换蓝色(B)。与预测器变换一样,首先将图像划分为块,并对块中的所有像素使用相同的变换模式。对于每个块,有三种类型的颜色转换元素:green_to_red,green_to_blue和red_to_blue。
  • 减去绿色变换: “减去绿色变换”从每个像素的红色和蓝色值中减去绿色值。存在此变换时,解码器需要将绿色值添加到红色和蓝色两者中。这是上述常规颜色去相关转换的一种特例,其频率足以保证截止。
  • 颜色索引(调色板)转换: 如果唯一的像素值不多,则创建颜色索引数组并将像素值替换为该数组的索引可能会更有效。颜色索引转换可实现此目的。颜色索引转换检查图像中唯一ARGB值的数量。如果该数字低于阈值(256),它将创建这些ARGB值的数组,然后将其用于用相应的索引替换像素值。
  • 颜色缓存编码: 无损WebP压缩使用已经看到的图像片段来重建新像素。如果找不到有趣的匹配项,它也可以使用本地调色板。该调色板会不断更新以重用最近的颜色。在下面的图片中,您可以看到随着扫描的进行,本地颜色缓存正在使用32种最近使用的颜色逐渐更新。

p-8.jpg

  • LZ77向后参考: 向后引用是长度和距离代码的元组。长度指示要按扫描线顺序复制多少像素。距离码是一个数字,指示先前看到的像素的位置,将从中复制像素。长度和距离值使用LZ77前缀编码存储。LZ77前缀编码将大整数分为两部分:前缀代码和多余的位。前缀码使用熵码存储,而多余的位按原样存储(没有熵码)。下图说明了具有字匹配(而不是像素)的LZ77(2D变体)。
    p-9.png

Alpha透明有损WebP

区别于有损WebP和无损WebP,这种编码允许对RGB频道的有损编码同时可对透明度频道进行无损编码。由于这种形式目前其他的格式还未能提供,所以目前需要使用透明度的话都会使用无损的PNG,导致大小膨胀。对于这类图片,WebP提供了较好的压缩效果。相比有损的WebP,添加透明通道只增加22%的大小。

因此,将支持透明的PNG换成无损+支持透明的WEBP可以平均节省60%-70%大小,这个已经被一些含较多Icon的移动网站证明。

动态WebP

动态WebP的原理与GIF和APNG原理类似,每一帧记录变化区域的坐标、长宽、播放延时等用于还原并播放。

兼容

web端兼容情况

p-4.png

能力检测

方式1.通过使用一张很小的webp图片确认当前环境是否支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// check_webp_feature:
// 'feature' can be one of 'lossy', 'lossless', 'alpha' or 'animation'.
// 'callback(feature, result)' will be passed back the detection result (in an asynchronous way!)
function check_webp_feature(feature, callback) {
var kTestImages = {
// 有损
lossy: "UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",
// 无损
lossless: "UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",
// 透明
alpha: "UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",
// 动画
animation: "UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"
};
let img = new Image();
img.onload = function () {
var result = (img.width > 0) && (img.height > 0);
callback(feature, result);
};
img.onerror = function () {
callback(feature, false);
};
img.src = "data:image/webp;base64," + kTestImages[feature];
}

方式2.通过canvas试图创建webp格式图片确认

1
2
window.IS_SUPPORT_WEBP = (!![].map && 
document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') === 0);

微信web不支持,微信小程序支持
iOS14开始支持

如果是原生app开发,iOS和Android都可以通过使用官方提供的解析库来支持静态WebPhttps://github.com/carsonmcdonald/WebP-iOS-examplehttps://github.com/alexey-pelykh/webp-android-backport

然而,对于动态WebP,目前只能找到facebook的开源库Fresco对其支持,不过Fresco最低仅支持API 9,且引用的相关库较多。


相关链接