Using AVIF to compress images on your site

Jai Krishnan
Jai Krishnan
Wan-Teh Chang
Wan-Teh Chang
Jeremy Wagner
Jeremy Wagner

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 greater than 50% savings vs. JPEG.

The image using AVIF
1120 by 840 AVIF at 18,769 bytes (click to enlarge)
The image using JPEG
1120 by 840 JPEG at 20,036 bytes (click to enlarge)

Additionally, AVIF adds codec and container support for new image features such as High Dynamic Range and Wide Color Gamut, film grain synthesis, and progressive decoding.

What's New

Since landing AVIF support in Chrome M85, AVIF support in the open source ecosystem has improved on a number of fronts.

Libaom

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.
Using speed=6, cq-level=18, for 8.1 MP images

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

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

cd 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.

cd ext

The next command will pull the libaom source code and build libaom statically.

./aom.cmd

Change directory to libavif.

cd ..

4. Build the command line encoding tool, avifenc

It is a good idea to create a build directory for avifenc.

mkdir build

Change to the build directory.

cd build

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 ..

Build avifenc.

make

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:

avifenc
--min 0Set min quantizer for color to 0
--max 63Set max quantizer for color to 63
--minalpha 0Set min quantizer for alpha to 0
--maxalpha 63Set max quantizer for alpha to 63
-a end-usage=qSet the rate control mode to Constant Quality (Q) mode
-a cq-level=QSet quantize level for both color and alpha to Q
-a color:cq-level=QSet quantize level for color to Q
-a alpha:cq-level=QSet quantize level for alpha to Q
-a tune=ssimTune for SSIM (default is to tune for PSNR)
--jobs JUse J worker threads (default: 1)
--speed SSet 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.

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

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 ./avifenc

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.

Effects on Largest Contentful Paint (LCP)

Images are a common candidate for the Largest Contentful Paint (LCP) metric. One common recommendation for improving the loading speed of LCP images is to ensure that an image is optimized. By reducing a resource's transfer size, you're improving its resource load time, which is one of the four key phases to target when dealing with LCP candidates that are images.

Using an image CDN is strongly recommended when optimizing images, as it requires much less effort than setting up image optimization pipelines in your website's build process or manually using encoder binaries to optimize images by hand. However, image CDNs may be cost-prohibitive for some projects. If this is the case for you, consider the following when optimizing with the avifenc encoder:

  • Familiarize yourself with the options the encoder offers. You may find additional savings while still retaining sufficient image quality by experimenting with some of AVIF's available encoding features.
  • AVIF provides both lossy and lossless encoding. Depending on an image's contents, one type of encoding may perform better than another. For example, photographs which are normally served as JPEGs will probably do best with lossy encoding, whereas lossless encoding is likely best for images containing simple details or line art normally served as PNG.
  • If using a bundler with community support for imagemin, consider using the imagemin-avif package to enable your bundler to output AVIF image variants.

By experimenting with AVIF, you may be able to realize an improvement for your website's LCP times in cases where the LCP candidate is an image. For more information on optimizing LCP, read the guide on optimizing LCP.

Conclusion

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.