欢迎使用 AVIF 下一代图片编码
后知后觉 暂无评论

AVIF (AV1 Image File Format),其实看到全名就能知道了大概,这个图片格式就是使用著名的 AV1 视频解码器进行编码的一种图片格式。自然也就继承了 AV1 格式本身的所有优点。

简介

那么就可以简单聊聊 AV1 了,AV1 (AOMedia Video 1)Alliance for Open Media(开放媒体联盟)开发的新一代视频编码格式,Alphabet(Google)、Apple、Netflix 等巨头都有参与,这个格式也是为了取代其前身 VP9。目前 Netflix 已经在其流媒体平台提供了 AV1 编码支持。

编码原理等就不在此赘述了,想了解的请移步 带你走进新一代图片编码格式 AVIF,作者描述得很简洁、直观。

对比

对比其他常用图片格式,比如 JPEG,PNG,WEBP 等,AVIF 具有更加良好的压缩率和相对质量。

与 JPEG、JPEG-XR、JPEG2000 和 PNG 格式相比,AVIF 兼容 HDR(高动态范围成像)。它支持全分辨率的 10 位和 12 位颜色,所生成的图像比其他已知格式小 10 倍。

下面显示的是来自柯达数据集的一张原始源图像以及采用 JPEG 444 @ 20,429 字节和 AVIF 444 @ 19,788 字节重新编码后的图像。

可见 JPEG 编码在天空、池塘和屋顶上显示出非常明显的块状伪影。 AVIF 编码要好得多,块状伪影更少,尽管屋顶上有一些模糊和纹理损失。考虑到大约 59 倍的压缩系数(原始图像的尺寸为 768x512,因此与压缩图像的 20k 字节相比,它需要 768x512x3 字节),这仍然是一个了不起的结果。

An-original-image-from-the-Kodak-dataset(!AVIF)

▲ Kodak original image @PNG

JPEG-444-@-20429-bytes(!AVIF)

▲ JPEG 444 @ 20,429 bytes

AVIF-444-@-19788-bytes(!AVIF)

▲ AVIF 444 @ 19,788 bytes

参见更多例图可以参考 AVIF for Next-Generation Image Coding

本地编码 AVIF

构建 libavif

克隆源码

git clone https://github.com/AOMediaCodec/libavif.git

安装依赖

sudo apt install build-essential cmake ninja-build

进入 libavif 扩展目录

cd libavif/ext/

执行命令拉取 libaom 源码并构建

./aom.cmd

如果看到如下报错

--- aom_configure: Detected CPU: x86_64
CMake Error at build/cmake/aom_configure.cmake:141 (message):
  Unable to find assembler.  Install 'yasm' or 'nasm.' To build without
  optimizations, add -DAOM_TARGET_CPU=generic to your cmake command line.
Call Stack (most recent call first):
  CMakeLists.txt:62 (include)

-- Configuring incomplete, errors occurred!

需要安装 yasm 支持,然后重新执行构建命令。

sudo apt install yasm

构建完成后返回上一层,创建构建文件夹,开始编译 libavif

cd ../
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DAVIF_LOCAL_AOM=1 -DAVIF_CODEC_AOM=1 -DBUILD_SHARED_LIBS=0 -DAVIF_BUILD_APPS=1 ../

如果看到如下报错

-- libavif: Enabling warnings for GCC
-- Checking for module 'libyuv'
--   No package 'libyuv' found
-- libavif: libyuv not found; libyuv-based fast paths disabled.
-- libavif: Codec enabled: aom (encode/decode)
CMake Error at /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:165 (message):
  Could NOT find JPEG (missing: JPEG_LIBRARY JPEG_INCLUDE_DIR)
Call Stack (most recent call first):
  /usr/share/cmake-3.18/Modules/FindPackageHandleStandardArgs.cmake:458 (_FPHSA_FAILURE_MESSAGE)
  /usr/share/cmake-3.18/Modules/FindJPEG.cmake:100 (find_package_handle_standard_args)
  CMakeLists.txt:486 (find_package)


-- Configuring incomplete, errors occurred!

这是因为缺少 libyuv 依赖。

编译 libyuv

编译 libyuv 库,克隆源码

git clone https://chromium.googlesource.com/libyuv/libyuv 

参考 官方说明 进行编译并构建成安装包

cd libyuv/
mkdir out
cd out
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j4
make package

比如在 Ubuntu 22.04 系统上执行时可见报错:

CMake Error at /usr/share/cmake-3.22/Modules/Internal/CPack/CPackRPM.cmake:822 (message):
  RPM package requires rpmbuild executable
Call Stack (most recent call first):
  /usr/share/cmake-3.22/Modules/Internal/CPack/CPackRPM.cmake:1968 (cpack_rpm_generate_package)


CPack Error: Error while execution CPackRPM.cmake
CPack Error: Problem compressing the directory
CPack Error: Error when generating package: libyuv
make: *** [Makefile:71: package] Error 1

这是因为 debian 系列系统不支持 rpm 包,也没有相关构建工具,忽略此报错即可,可见目录中已经出现 libyuv-0.0.1823-linux-amd-64.deb 即为构建的安装包。

安装依赖包

sudo dpkg -i libyuv-0.0.1823-linux-amd-64.deb

补充编译依赖

sudo apt install libjpeg-dev libpng-dev

然后返回 libavif 目录重新生成编译文件

cd libavif/build
cmake -DCMAKE_BUILD_TYPE=Release -DAVIF_LOCAL_AOM=1 -DAVIF_CODEC_AOM=1 -DBUILD_SHARED_LIBS=0 -DAVIF_BUILD_APPS=1 ../

可见提示信息已经找到 libyuv 库

-- libavif: Enabling warnings for GCC
-- Checking for module 'libyuv'
--   No package 'libyuv' found
-- libavif: libyuv (1823) found; libyuv-based fast paths enabled.
-- libavif: Codec enabled: aom (encode/decode)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kane/Github/libavif/build

开始编译

make -j4
sudo make install

安装后会在 /usr/local/bin 下生成两个可执行文件 avifdecavifenc 两个文件,分别是解码器和编码器。

重编码

avifenc example.jpg example.avif --min 0 --max 63 -a end-usage=q -a cq-level=32 -a tune=ssim -a deltaq-mode=3 -a sharpness=3 -y 420
注意:这是谷歌推荐的编码参数,可以直接使用,最后添加参数 --jobs 8 可以多线程,最多可使速度提升 5 倍。

如果不想自行编译构建,也可以使用在线转换工具 Squoosh

小贴士:使用上述参数对图片进行编码,一般可使文件缩小 30-40%。

使用

目前主流浏览器(Chrome Firefox)都已经支持 AVIF,具体的支持情况可以参考 CAN I USE avif

简易

所有图片标签使用 <picture></picture> 标签进行如下改造,即可实现自动化兼容性降级,对于不支持 avif 格式的浏览器会自动降级到 jpeg 格式。

<picture>
    <source type="image/avif" srcset="https://example.com/view/public/avif/example.avif">
    <img src="https://example.com/view/public/jpeg/example.jpg" alt="AVIF" title="AVIF">
</picture>

复杂

CSS Images Module Level 4 标准中新增了 image-set 属性。

.element {
  background-image: image-set( "image.avif" type("image/avif"),
                               "image.webp" type("image/webp"),
                               "image.jpg" type("image/jpeg") );
}

浏览器会根据顺序尝试,选择浏览器已支持的格式,不过目前此方式在一些浏览器中还未实现,不过可以使用下面的替代方法。

body {
  background-color: #000;
  background-repeat: no-repeat;
  background-size: cover;
}
body.avif {
  background-image: url(./images/lions.avif);
}
body.no-avif {
  background-image: url(./images/lions.jpg);
}

使用 CSS 定义不同的格式,然后使用 js 判断浏览器是否支持,并进行替换。

async function supportsAvif() {
  if (!this.createImageBitmap) return false
  const avifData =
    'data:image/avif;base64,AAAAFGZ0eXBhdmlmAAAAAG1pZjEAAACgbWV0YQAAAAAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAC8AAAAGwAAACNpaW5mAAAAAAABAAAAFWluZmUCAAAAAAEAAGF2MDEAAAAARWlwcnAAAAAoaXBjbwAAABRpc3BlAAAAAAAAAAQAAAAEAAAADGF2MUOBAAAAAAAAFWlwbWEAAAAAAAAAAQABAgECAAAAI21kYXQSAAoIP8R8hAQ0BUAyDWeeUy0JG+QAACANEkA='
  const blob = await fetch(avifData).then((r) => r.blob())
  return createImageBitmap(blob).then(
    () => true,
    () => false
  )
}
;(async () => {
  const classAvif = (await supportsAvif()) ? 'avif' : 'no-avif'
  document.body.classList.add(classAvif)
})()

附录

参考链接

本文撰写于一年前,如出现图片失效或有任何问题,请在下方留言。博主看到后将及时修正,谢谢!
禁用 / 当前已拒绝评论,仅可查看「历史评论」。