We frequently write about the bloat on websites from images, and tools like Lighthouse highlight when image loading is having a negative impact on user experience, such as increasing load time, or taking bandwidth away from more important resources. One way to fix this is to use modern compression to reduce the file size of images, and a new option for web developers is the AVIF image format. This blog post talks about recent updates to open source tooling for AVIF, introduces the libaom and libavif encoding libraries, and includes a tutorial for using these libraries to encode AVIF images efficiently.
AVIF is an image format based on the AV1 video codec, and standardized by the Alliance for Open Media. AVIF offers significant compression gains over other image formats like JPEG and WebP. While the exact savings will depend on the content, encoding settings, and quality target, we and others have seen >50% savings vs. JPEG.
AVIF supports two types of progressive decoding. Spatial scalability can be used to offer a lower resolution image for network constrained users and 'progressively' provide a higher resolution image by sending just the additional data required to fill in the high frequency details. Quality scalability offers a similar progression by steadily improving visual quality with each render.
What's New #
Since landing AVIF support in Chrome M85 last summer, AVIF support in the open source ecosystem has improved on a number of fronts.
Libaom is an open source AV1 encoder and decoder maintained by the companies in the Alliance for Open Media, and used in many production services at Google and other member companies. Between the libaom 2.0.0 release—around the same time Chrome added AVIF support—and the recent 3.1.0 release, there have been significant still image encoding optimizations added to the codebase. These include:
- Optimizations for multi-threading and tiled encoding.
- 5x reduction in memory usage.
- 6.5x reduction in CPU usage, as shown in the chart below.
These changes massively reduce the cost of encoding AVIF— particularly the most frequently loaded, or highest priority images on your site. As hardware-accelerated encoding of AV1 becomes more available on servers and cloud services, the cost to create AVIF images will continue to drop.
Libavif, the reference implementation of AVIF, is an open source AVIF muxer and parser which is used in Chrome for decoding AVIF images. It can also be used with libaom for creating AVIF images from your existing uncompressed images, or transcoding from existing web images (JPEG, PNG, etc).
Libavif recently added support for a wider range of encoder settings, including integration with more advanced libaom encoder settings. Optimizations in the processing pipeline like fast YUV-to-RGB conversion using libyuv and premultiplied alpha support further speed up the decoding process. And finally, support for the all-intra encoding mode newly added in libaom 3.1.0 brings all the libaom improvements mentioned in the above.
Encoding AVIF images with avifenc #
A quick way to experiment with AVIF is Squoosh.app. Squoosh runs a WebAssembly version of libavif, and exposes many of the same features as the command line tools. It's an easy way to compare AVIF to other formats old and new. There's also a CLI version of Squoosh aimed at Node apps.
However, WebAssembly doesn't yet have access to all the performance primitives of CPUs, so if you want to run libavif at its fastest, we recommend the command line encoder, avifenc.
To understand how to encode AVIF images, we will present a tutorial using the same source image used in our example above. To start, you will need:
You will also need to install the development packages for zlib, libpng, and libjpeg. The commands for the Debian and Ubuntu Linux distributions are:
sudo apt-get install zlib1g-dev
sudo apt-get install libpng-dev
sudo apt-get install libjpeg-dev
Building command line encoder avifenc #
1. Get the code #
Check out a release tag of libavif.
git clone -b v0.9.1 https://github.com/AOMediaCodec/libavif.git
2. Change directory to libavif #
There are many different ways you can configure avifenc and libavif to build. You can find more information at libavif. We are going to build avifenc so that it is statically linked to the AV1 encoder and decoder library, libaom.
3. Get and build libaom #
Change to the libavif external dependencies directory.
The next command will pull the libaom source code and build libaom statically.
Change directory to libavif.
4. Build the command line encoding tool, avifenc #
It is a good idea to create a build directory for avifenc.
Change to the build directory.
Create the build files for avifenc.
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0 -DAVIF_CODEC_AOM=1 -DAVIF_LOCAL_AOM=1 -DAVIF_BUILD_APPS=1 ..
You have successfully built avifenc!
Understanding the avifenc command line parameters #
avifenc uses the command-line structure:
./avifenc [options] input.file output.avif
The basic parameters for avifenc used in this tutorial are:
|--min 0||Set min quantizer for color to 0|
|--max 63||Set max quantizer for color to 63|
|--minalpha 0||Set min quantizer for alpha to 0|
|--maxalpha 63||Set max quantizer for alpha to 63|
|-a end-usage=q||Set the rate control mode to Constant Quality (Q) mode|
|-a cq-level=Q||Set quantize level for both color and alpha to Q|
|-a color:cq-level=Q||Set quantize level for color to Q|
|-a alpha:cq-level=Q||Set quantize level for alpha to Q|
|-a tune=ssim||Tune for SSIM (default is to tune for PSNR)|
|--jobs J||Use J worker threads (default: 1)|
|--speed S||Set encoder speed from 0-10 (slowest-fastest. default: 6)|
The cq-level option sets the quantize level (0-63) to control the quality for color or alpha.
You can think of cq-level as the "amount" of quantization, so a lower value yields higher quality
Higher speed settings will run faster, but produce worse compression efficiency and quality. This tutorial uses the default setting of Speed 6, which we recommend as a balance of encode speed, compression efficiency, and quality.
Create an AVIF image with default settings #
The most basic parameters for avifenc to run, are setting the input and output files.
./avifenc happy_dog.jpg happy_dog.avif
We recommend the following command line to encode an image, say at quantize level 18:
./avifenc --min 0 --max 63 -a end-usage=q -a cq-level=18 -a tune=ssim happy_dog.jpg happy_dog.avif
"--min 0 --max 63 -a end-usage=q -a cq-level=18 -a tune=ssim" are the recommended settings for AVIF images. If the image has an alpha channel, add
"--minalpha 0 --maxalpha 63". To specify different quantize levels for color and alpha, replace
"-a cq-level=18" with, say,
"-a color:cq-level=18 -a alpha:cq-level=10".
Avifenc has a lot of options that will affect both quality and speed. If you want to see the options and learn more about them just run
You now have your very own AVIF image!
Speeding up the encoder #
One parameter that may be good to change depending on how many cores you have on your machine is the
--jobs parameter. This parameter sets how many threads avifenc will use to create AVIF images. Try running this at the command line.
./avifenc --min 0 --max 63 -a end-usage=q -a cq-level=18 -a tune=ssim --jobs 8 happy_dog.jpg happy_dog.avif
This tells avifenc to use 8 threads when creating the AVIF image, which speeds up AVIF encoding by roughly 5x.
Using libaom, libavif and other open source tooling, you can get the best image quality and performance for your website using AVIF. The format is still relatively new, and optimizations and tooling integrations are actively being developed. If you have questions, comments, or feature requests, reach out on the av1-discuss mailing list, AOM Github community, and AVIF wiki.