Ahammed Rashad

Why We Switched to AVIF

Why we chose AVIF over JPEG and PNG for our previews at Tessact: smaller files, good image quality, and transparency.

At Tessact, we were storing video thumbnails and sprite sheets as PNGs. They worked, but every preview added more data to store and transfer. We wanted smaller files without losing image quality or transparency.

Comparing JPEG and AVIF

We started with a single frame, encoded as JPEG and AVIF at the same dimensions. Could AVIF keep more detail at the same file size, or give us similar quality in a smaller file?

Use the tabs to compare both cases, then drag the slider to inspect the details. The encoder settings use different scales.

Colour studio interior encoded as JPEGAVIF · 19.6 KBJPEG · 18.9 KB
JPEG18.9 KBencoder setting 5
AVIF19.6 KBencoder setting 26
Budget≈ 20 KBeach at 1440 × 810

In the similar-quality example, AVIF uses 37.6 KB against 78.4 KB for JPEG. That was a useful reduction for thumbnails, but file size wasn’t our only requirement.

Keeping transparency

Some previews contain motion graphics with transparent backgrounds. JPEG flattens those backgrounds, so it couldn’t replace PNG for these images. AVIF keeps the alpha channel, as PNG does.

Switch between light and dark backgrounds below to see how that affects the preview in an interface.

LightDark
JPEGFlattened · 341.3 KB sheet
AVIFTransparent · 170.6 KB sheet

JPEG carries its flattened background into the interface. AVIF keeps the space around the ribbon transparent across both themes.

Sprite sheets for scrubbing

The moving ribbon above isn’t a video. It uses a sprite sheet: 48 frames packed into a single 6 × 8 image. Moving across the preview below picks a frame from that sheet, without loading a video. We use the same approach for scrubbing at Tessact, where production sheets hold more than 100 frames and stay below 500 KB.

Drag to scrub0.00 s
48 motion frames · 2 seconds2888.5 KB PNG170.6 KB AVIF

Loading smaller previews

Packing frames into one image makes scrubbing simple, but the whole sheet still has to load. This demo sheet went from 2888.5 KB as PNG to 170.6 KB as AVIF, while keeping transparency.

The grid uses the same sheet for each preview. Switch formats to compare the data transferred. The time shown is a theoretical transfer at 10 Mbps, not a measured page-load time; decoding and network latency will vary.

AVIF≈ 0.14 sraw transfer at 10 Mbps

Adding AVIF to our existing pipeline

AVIF gave us smaller images with good visual quality and kept the transparency we needed. The remaining problem was fitting it into the pipeline we already had.

We were extracting frames with FFmpeg 4.4.2 and building PNG sprite sheets with Pillow. We expected the same FFmpeg step to write AVIF, but the build that came with Ubuntu 22.04 didn’t have the encoder we needed.

Replacing FFmpeg brought other problems. An external PPA was a dependency we didn’t control. Static builds were harder to maintain, and upgrading the system was already causing conflicts with Python packages in our stack.

So we kept FFmpeg for extracting PNG frames and used the libavif CLI to encode thumbnails and sprite sheets as AVIF.

We didn’t need to change how frames were extracted. Adding AVIF at the end gave us smaller thumbnails and sprite sheets while keeping the transparency we needed.