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 字节),这仍然是一个了不起的结果。
▲ Kodak original image @PNG
▲ JPEG 444 @ 20,429 bytes
▲ 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
下生成两个可执行文件 avifdec
和 avifenc
两个文件,分别是解码器和编码器。
重编码
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)
})()
附录
参考链接
- 「AVIF for Next-Generation Image Coding」 - Netflix Technology Blog
- 「Serving AVIF Images」 - Google Developers
- 「How to get and build the libyuv code.」 - Google Source
- 「AVIF has landed」 - jakearchibald
- 「Detect AVIF image support to use in your CSS」 - DevTo
本文由 柒 创作,采用 知识共享署名4.0
国际许可协议进行许可。
转载本站文章前请注明出处,文章作者保留所有权限。
最后编辑时间: 2022-05-03 21:24 PM