AVIF: The Modern Image Format — Complete Technical Guide
AVIF (AV1 Image File Format) is an open, royalty-free image format based on the AV1 video codec, standardised by the Alliance for Open Media (AOM) in 2019. AVIF combines the ISOBMFF container (the same box structure used by MP4 and HEIF) with AV1's intra-frame encoding algorithms to deliver images that are significantly smaller than JPEG, PNG, and WebP at the same perceptual quality. As of 2024, AVIF is supported by Chrome, Firefox, Edge, Safari 16+, Android 12+, and iOS 16+.
Container Structure: ISOBMFF + HEIF
AVIF files are HEIF (High Efficiency Image File Format, ISO 23008-12) containers that store AV1 image items. The top-level structure follows ISOBMFF box layout:
ftyp — File Type Box
major_brand: "avif"
compatible_brands: ["avif", "mif1", "miaf", "MA1B"|"MA1A"]
meta — Metadata Box (contains item information)
hdlr — Handler Reference Box ("pict")
pitm — Primary Item Box (ID of the primary image item)
iloc — Item Location Box (byte offsets of each item's data)
iinf — Item Info Box (array of item type entries)
iref — Item Reference Box (relationships between items)
iprp — Item Properties Box
ipco — Item Property Container
av1C — AV1 Codec Configuration Box (sequence header OBU)
ispe — Image Spatial Extents (width × height)
pixi — Pixel Information (bits per channel)
colr — Colour Information (ICC profile or nclx colour primaries)
pasp — Pixel Aspect Ratio
mdat — Media Data Box (actual AV1 bitstream payload)
For animated AVIF (AVIS), the structure changes: the ftyp lists "avis" as the major brand and the file contains a moov box with a track of AV1 frames, identical to how animated HEIF uses a video track.
AV1 Intra-Frame Encoding for Images
AVIF uses AV1 keyframes (intra-coded frames — no inter prediction from other frames). AV1's intra coding tools include:
- 77 intra prediction modes: directional (angle-based), DC, smooth/smooth_v/smooth_h, Paeth, and chroma-from-luma
- Variable transform sizes: 4×4 to 64×64 DCT, ADST (Asymmetric Discrete Sine Transform), FLIPADST, IDENTITY, WHT
- Loop filters: deblocking, CDEF (Constrained Directional Enhancement Filter), loop restoration (Wiener filter and self-guided filter)
- Film grain synthesis: the encoder signals film grain parameters instead of encoding the actual noise; the decoder synthesises visually matching grain — substantially reducing file size for noisy sources like scanned film
- 10/12-bit colour: exceeds JPEG's 8-bit limit, enabling HDR, wide colour gamut (P3, BT.2020)
- Alpha channel: stored as a separate AV1 auxiliary image item
Colour Space and HDR Support
AVIF's colr box carries colour space information via two mechanisms:
- ICC profile: embedded colour profile (any ICC profile — sRGB, Display P3, ProPhoto RGB, etc.)
- nclx: signals CICP (Coding Independent Code Points) values:
colour_primaries: 1=BT.709/sRGB, 9=BT.2020, 12=Display P3transfer_characteristics: 1=BT.709, 13=sRGB, 16=PQ (SMPTE ST 2084), 18=HLGmatrix_coefficients: 0=identity/RGB, 1=BT.709, 9=BT.2020 NCL
For HDR AVIF: 10-bit depth, colour_primaries=9 (BT.2020), transfer=16 (PQ/HDR10).
FFmpeg and libavif Encoding
# Convert JPEG/PNG to AVIF using ffmpeg (quality 0=best, 63=worst)
ffmpeg -i input.jpg \
-c:v libaom-av1 \
-still-picture 1 \
-crf 23 \
-cpu-used 8 \
output.avif
# Using avifenc (libavif reference encoder — better quality control)
# Install: brew install libavif / apt install libavif-bin
avifenc --min 20 --max 30 --speed 6 input.png output.avif
# --min/--max: quantiser range (0=lossless, 63=worst)
# --speed 0-10: 0=slowest/best, 10=fastest/worst (default 6)
# Lossless AVIF
avifenc --lossless input.png output_lossless.avif
# 10-bit colour AVIF with Display P3 profile
avifenc --depth 10 --cicp 12/13/6 --speed 4 input_p3.png output_hdr.avif
# cicp: colour_primaries/transfer/matrix
# Animated AVIF from video (each frame encoded as AV1 intra)
ffmpeg -i input.mp4 \
-c:v libaom-av1 -cpu-used 8 \
-vf "fps=15,scale=640:-1" \
output_animated.avif
# Batch convert PNG directory to AVIF
for f in *.png; do
avifenc --min 20 --max 30 --speed 6 "$f" "${f%.png}.avif"
done
Python AVIF Processing
from PIL import Image
import pillow_avif # pip install pillow-avif-plugin
# Requires: pip install Pillow pillow-avif-plugin
# Or Pillow >= 9.1.0 which includes built-in AVIF support on platforms with libavif
# Open AVIF
img = Image.open('photo.avif')
print(f"Size: {img.size}, Mode: {img.mode}")
# Convert JPEG to AVIF
img = Image.open('photo.jpg').convert('RGB')
img.save(
'photo.avif',
format='AVIF',
quality=80, # 0–100 (higher = better quality = larger file)
speed=6, # 0–10 encoding speed (0=slowest, best quality)
)
# Save with transparency (RGBA → AVIF with alpha)
img_rgba = Image.open('logo.png').convert('RGBA')
img_rgba.save('logo.avif', format='AVIF', quality=85)
# Batch convert a directory
import pathlib
for src in pathlib.Path('images/').glob('*.jpg'):
img = Image.open(src).convert('RGB')
dst = src.with_suffix('.avif')
img.save(str(dst), format='AVIF', quality=80, speed=6)
print(f"{src.name} → {dst.name} "
f"({src.stat().st_size//1024} KB → {dst.stat().st_size//1024} KB)")
AVIF vs JPEG vs WebP vs HEIC
| Feature | JPEG | WebP | AVIF | HEIC |
|---|---|---|---|---|
| Compression vs JPEG | 1× | ~30% better | ~50% better | ~50% better |
| Alpha channel | No | Yes | Yes | Yes |
| Lossless | No | Yes | Yes | Yes |
| HDR / 10-bit | No | No | Yes | Yes |
| Animation | No | Yes | Yes | Yes |
| Film grain synthesis | No | No | Yes | No |
| Royalty-free | Yes | Yes | Yes | No |
| Chrome support | ✓ | ✓ | ✓ (v85+) | Limited |
| Firefox support | ✓ | ✓ | ✓ (v93+) | No |
| Safari support | ✓ | Limited | ✓ (16+) | ✓ |
| Encode speed | Fast | Fast | Slow | Moderate |
Typical file size comparison for a high-quality web photo (1200×800):
| Format | Quality setting | File size |
|---|---|---|
| JPEG | q=85 | ~120 KB |
| WebP | q=85 | ~85 KB |
| AVIF | q=80 (libavif) | ~55–70 KB |
| AVIF lossless | — | ~180 KB |
| PNG | — | ~350 KB |
HTML Serving with <picture> Fallback
<picture>
<!-- Modern browsers: AVIF first (smallest) -->
<source srcset="photo.avif" type="image/avif">
<!-- Fallback: WebP for browsers without AVIF -->
<source srcset="photo.webp" type="image/webp">
<!-- Universal fallback: JPEG -->
<img src="photo.jpg" alt="A descriptive caption" width="1200" height="800"
loading="lazy" decoding="async">
</picture>
Apache / Nginx Content Negotiation
# Apache .htaccess — serve AVIF/WebP when available and Accept header matches
<IfModule mod_rewrite.c>
RewriteEngine On
# AVIF
RewriteCond %{HTTP_ACCEPT} image/avif
RewriteCond %{REQUEST_FILENAME}.avif -f
RewriteRule ^(.*)\.(jpe?g|png)$ $1.avif [T=image/avif,E=accept:1]
# WebP fallback
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_FILENAME}.webp -f
RewriteRule ^(.*)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=accept
</IfModule>
Common Pitfalls
- AVIF encoding is slow. libaom-av1 at speed 0–4 produces excellent quality but takes seconds per image. For production pipelines, use speed 6+ or consider alternative encoders like SVT-AV1 via
avifenc. Precompute all AVIF files at build/upload time. - Safari < 16 does not support AVIF. Always provide JPEG or WebP fallbacks via
<picture>or content negotiation. - Quantiser scale is counter-intuitive. In
avifenc,--min 0 --max 0means lossless; higher values mean worse quality. This is the opposite of JPEG quality (which is percentage-based, higher = better). - AVIF thumbnails in macOS Finder. macOS 13 (Ventura) added AVIF preview support. Older macOS versions show a generic file icon for AVIF files.
Related conversions
Most teams that read this guide convert images in one of these directions: