Skip to content

AVIF

currentMigrated from docs/images/AVIF.mdx at 37c3317fd058; modified for Encode Wiki · CC BY-SA 4.0

AVIF is AV1 intra-frame coding stored in a HEIF/ISO-BMFF container. It is the format to reach for when you want the smallest lossy images that every current browser can display, and it also gives you 10- and 12-bit depth, HDR signalling, alpha and animation. It is a poor choice for lossless archival, and encoding is slower than JPEG or WebP.

The container is the same family as HEIC; the payload is the AV1 video codec, so any AV1 encoder can in principle produce AVIF images.

Strengths

  • Very good lossy compression on photos and on flat graphics. At low and medium bitrates it beats JPEG and WebP by a wide margin; against JPEG XL it usually produces smaller files at web-delivery quality, while JPEG XL pulls ahead at very high quality and in lossless.
  • 8-, 10- and 12-bit, 4:2:0 / 4:2:2 / 4:4:4 / monochrome, wide gamut and HDR signalling (PQ, HLG), ICC or CICP colour, and a separate alpha plane.
  • Animation using real inter-frame video coding, which makes it a far better animated format than GIF or animated WebP for most clips.
  • Royalty-free, and supported by every current browser.

Weaknesses

  • Slower encoding than JPEG, WebP or JPEG XL. libaom at its slowest speeds (-s 0–3) and on large images takes seconds to minutes per file.
  • Weak lossless mode. It is usually larger than lossless WebP or JPEG XL, and sometimes larger than PNG.
  • No JPEG-style progressive decode: a plain AVIF shows nothing until enough of the file has arrived. Layered “progressive” files exist in the AVIF 1.2 spec and avifenc --progressive can write them, but check your target decoders before relying on them.
  • Smooth gradients can band and fine texture can smear at low bitrates, and 4:2:0 bleeds saturated colour edges and small coloured text.
  • Very large images need tiling or a grid, which costs a little efficiency and can leave faint seams.
PlatformStill AVIFNotes
Chrome85+Other Chromium browsers follow their Chromium version
Firefox93+Animated AVIF from Firefox 113
Edge121+
Safari16.4+ on macOS, 16.1+ on iOSSafari 16.1–16.3 on macOS worked only on Ventura
Android system decoderAndroid 12+ (8-bit)10-bit decoding is optional per device

Browser versions are from MDN’s AVIF data and Android’s supported media formats. Desktop OS thumbnailers, editors and messaging apps are patchier than browsers; see image and audio support for how to check a given file.

Profiles matter less than they used to, but they still bound what a conservative decoder accepts. The Baseline brand (MA1B) is AV1 Main profile (8/10-bit, 4:2:0 or monochrome) at level 5.1 or lower; the Advanced brand (MA1A) is High profile (adds 4:4:4) up to level 6.0. Larger images are built from a grid of tiles.

avifenc from libavif is the standard encoder. It takes PNG, JPEG or Y4M input and calls an AV1 backend (libaom, SVT-AV1 or rav1e, whatever your build includes).

Terminal window
avifenc -q 65 -s 4 input.png output.avif

-q and -s are the two knobs you will actually turn. The defaults are -q 60 and -s 6. Pick the quality by eye at a fast speed, then encode the final file at -s 4 or slower; speeds below 4 cost a lot of time for a small gain.

OptionWhat it does
-q 0..100Colour quality; 100 is lossless AV1 coding. Not comparable between backends or libavif releases.
--qalpha 0..100Alpha quality, inherited from -q unless set. Use --qalpha 100 if the alpha edge must stay clean.
-s 0..10Speed; lower is slower and smaller. Default 6.
-d 8/10/12Output bit depth; follows 8-bit input by default. Use 10 for HDR and high-bit-depth sources. -d 10 is also common for 8-bit sources because it reduces banding in smooth gradients.
-y 444/422/420/400Chroma format. auto gives 4:4:4 for PNG, keeps the subsampling of a JPEG and uses 4:0:0 for greyscale PNG.
--sharpyuvSharper RGB→4:2:0 conversion; only does anything with -y 420.
-c aom/svt/rav1eChoose the backend.
-j NWorker threads (default all).
-a KEY=VALUEPass a backend option, e.g. -a tune=iq. libaom keys can be limited to one plane with color: or alpha:.
-lLossless: sets RGB-identity, full-range, 4:4:4 defaults.
--cicp P/T/M, --iccSignal colour primaries/transfer/matrix or attach an ICC profile.

avifenc keeps 4:4:4 for PNG input, and libaom handles 4:4:4 well, so the extra chroma usually costs little. Keep it for screenshots, UI, line art and coloured text, where 4:2:0 visibly bleeds colour. Use -y 420 (plus --sharpyuv) when you need the smallest photo files or files that stay within the Baseline brand and AV1 Main profile that hardware decoders support.

Since libavif 1.4.0, avifenc with libaom 3.13 or newer encodes still images (YUV, not RGB-matrix) with tune=iq by default, and maps -q to quantizers with a formula designed for it. tune=iq is libaom’s still-image mode, added in 3.12: it was developed with SSIMULACRA2 as a guide and checked visually, and uses Variance Boost, adaptive CDEF and quantization matrices. Alpha is encoded with tune=psnr, because tune=ssim causes ringing on alpha.

The older recipe of -a tune=ssim -a end-usage=q -a cq-level=… is obsolete: use -q and leave the tune alone. Because tune=iq was shaped around SSIMULACRA2, check comparisons against other tunes by eye as well.

BackendNotes
libaomThe default and the usual best choice for stills: full chroma and bit-depth support, tune=iq, and the most intra-coding work behind it.
SVT-AV1Faster, but libavif’s SVT adapter is 4:2:0 only, 8/10-bit. A PNG defaults to 4:4:4, so -c svt without -y 420 fails with “Only support 420 now”. The libaom -a keys do not apply.
rav1eWorks, but is slow for stills and lacks libaom’s still-image tuning.

libheif’s heif-enc --avif is a second frontend with the same backends and its own defaults (quality 50); its plugin parameter tables are in the reference below. AVIF is also writable from FFmpeg and ImageMagick, which go through libavif or libheif.

  • Alpha is stored as a separate monochrome AV1 image, so it has its own quality (--qalpha). Use -p only if you intend premultiplied (associated) alpha.
  • HDR: keep the source’s real transfer function and primaries (--cicp 9/16/9 for PQ BT.2020, 9/18/9 for HLG) and encode at 10 bit or more. Tagging SDR pixels as PQ does not make them HDR. In builds with gain-map support, avifenc converts gain maps embedded in JPEG input (--qgain-map, --ignore-gain-map).
  • Animation: pass several PNGs with --fps, or pipe Y4M from FFmpeg: ffmpeg -i in.mp4 -pix_fmt yuv420p -f yuv4mpegpipe - | avifenc --stdin out.avif. Firefox plays animated AVIF from version 113.
  • A lossless AV1 stream does not make the file lossless: RGB→YUV conversion and 4:2:0 are lossy unless you use -l.
  • avifenc copies Exif, XMP and ICC from PNG and JPEG input and turns the Exif orientation into AVIF irot/imir transforms. Use --ignore-exif, --ignore-xmp or --ignore-icc to drop them; dropping the ICC profile of a wide-gamut source changes its colours.
  • Re-encoding an AVIF from a previous lossy AVIF compounds loss; keep the original source.

Any AV1 encoder can produce AVIF; see aomenc, SVT-AV1 and rav1e. Rachel Barker’s tinyavif is a minimal AVIF encoder written to show how AVIF and AV1 work, not for production.

  • AV1 is the video codec underneath.
  • JPEG XL has lossless JPEG recompression and a stronger lossless and high-quality story.
  • WebP is the older, faster, 8-bit-only alternative.
  • HEIC uses the same container with HEVC.

The tables below are the full avifenc and libheif AVIF plugin parameter references. Reading option tables explains the Default column.

avifenc 1.4.2 complete parameter reference

Section titled “avifenc 1.4.2 complete parameter reference”
INPUT to —target-size
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
INPUTpath(s)requiredJPEG, PNG or Y4M input. Several inputs make an animated sequence, or the layers/cells with —layered/—grid.
OUTPUTpathrequired, unless —output is usedOutput .avif. Taken from the last positional argument unless —output is given.
--help, -hactionnot requestedPrint usage and the compiled-in codec versions.
--version, -Vactionnot requestedPrint the libavif and codec library versions.
--qcolor, -q, --qcolor:u, --qcolor:update, -q:u, -q:updateinteger 0–10060Colour quality, 0–100. 100 is lossless AV1 coding, though RGB→YUV conversion can still be lossy. The :u forms apply only to the inputs after them.
--qalpha, --qalpha:u, --qalpha:updateinteger 0–100same as qcolorAlpha quality, 0–100. Follows —qcolor unless set.
--speed, -s0–10, default or d6Encoder speed, 0 (slowest) to 10, or default/d for the codec’s own default. Slower is smaller.
--jobs, -jpositive integer or allall detected CPUsWorker threads, or all. What it controls depends on the codec.
--no-overwriteflagfalseFail instead of replacing an existing output file.
--output, -opathfinal positional filenameOutput path, instead of the last positional argument.
--lossless, -lflagfalseSet lossless defaults: quality 100, full range, 4:4:4 and identity matrix. Warns when the input can’t be stored losslessly.
--depth, -dD[,extension]input-dependentOutput bit depth, 8, 10 or 12. A second value (8,8 / 12,4 / 12,8) adds a hidden extension image for 16-bit output. Y4M keeps its own depth.
--yuv, -yauto, 444, 422, 420, 400autoChroma format: auto, 444, 422, 420 or 400. auto keeps a JPEG’s subsampling, uses 400 for greyscale PNG and 444 otherwise; Y4M keeps its format.
--premultiply, -pflagfalseMultiply colour by alpha before encoding and mark alpha as premultiplied. Changes pixel values.
--sharpyuvflagfalseSharper RGB→4:2:0 conversion (needs libsharpyuv). No effect on Y4M or non-4:2:0 output.
--stdinflagfalseRead one stream (Y4M by default) from standard input. No other input paths are allowed; the output path is still required.
--input-formatauto, jpg, jpeg, png, y4mauto for paths; y4m for stdinForce the input type: jpeg/jpg, png, y4m or auto. Needed only when the extension is misleading.
--cicp, --nclxP/T/M integers2/2/6 before input-specific handlingColour primaries/transfer/matrix as three numbers (H.273); 2 means unspecified. Tags the file; samples are not converted.
--range, -rfull/f or limited/lfull for JPEG/PNG; retained for Y4MYUV range, full or limited. Y4M input keeps its own range.
--target-sizepositive bytesdisabledAim for this file size in bytes by searching over quality. Up to 7× slower; conflicts with fixed —qcolor/—qalpha.
—progressive to —irot
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
--progressiveflagfalseWrite a two-layer image that can render progressively from one input. Needs —qcolor of at least 10; support is limited.
--layeredflagfalseEncode two to four inputs as layers of one image. Not an animation.
--grid, -gcolumns x rowsdisabledWrite a grid of COLSxROWS cells, from identical inputs or one image split evenly.
--codec, -cbuild-specific encoder IDautoPick the AV1 encoder, for example aom, rav1e or svt. Decoder-only IDs can’t encode.
--exifpayload pathpreserve input metadata if presentUse this Exif payload instead of any embedded Exif.
--xmppayload pathpreserve input metadata if presentUse this XMP payload instead of any embedded XMP.
--iccprofile pathpreserve input profile if presentUse this ICC profile instead of any embedded one. Tags the image; samples are not converted.
--timescale, --fpspositive integer30; may inherit Y4M timingSequence ticks per second. With one-tick frames this is the frame rate. Y4M frame rate is used if unset.
--creation-timenonnegative Unix seconds0: use modification timeSequence creation time in Unix seconds. 0 uses the modification time.
--modification-timenonnegative Unix seconds0: use current timeSequence modification time in Unix seconds. 0 uses the current time.
--keyframe, -kinteger0: disabledMaximum keyframe interval for sequences, in frames. 0 disables the limit.
--ignore-exifflagfalseDrop embedded Exif.
--ignore-xmpflagfalseDrop embedded XMP.
--ignore-icc, --ignore-profileflagfalseDrop the embedded ICC profile.
--ignore-gain-mapbuild-gated flagfalseDrop an embedded JPEG gain map. Needs a libavif built with gain-map conversion.
--qgain-mapbuild-gated integer 0–10060Gain map quality, 0–100. Needs a gain-map build; takes no :u form.
--paspH,V positive spacingabsentPixel aspect ratio as H,V. Metadata only.
--cropx,y,width,heightabsentClean-aperture crop as x,y,width,height. Applied at display time; pixels are not removed.
--clapeight rational componentsabsentClean aperture as eight numerator/denominator values: width, height, horizontal offset, vertical offset.
--irotinteger 0–3absentRotation in 90° steps anticlockwise (0–3). Stored as a transform.
—imir to —
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
--imir0 or 1absentMirror axis: 0 top-to-bottom, 1 left-to-right. Stored as a transform.
--clliMaxCLL,MaxPALLabsentMaxCLL,MaxPALL content light level metadata. Doesn’t make the image HDR.
--repetition-countnonnegative integer or infiniteinfiniteHow many times a sequence plays, or infinite.
--tilerowslog2, --tilerowslog2:u, --tilerowslog2:updateinteger 0–60 before automatic tilinglog2 of the number of tile rows (0–6). Setting it switches to manual tiling.
--tilecolslog2, --tilecolslog2:u, --tilecolslog2:updateinteger 0–60 before automatic tilinglog2 of the number of tile columns (0–6). Setting it switches to manual tiling.
--autotiling, --autotiling:u, --autotiling:updateflagtrueChoose AV1 tiling automatically. This is the starting mode; it is separate from a HEIF grid.
--min, --min:u, --min:updatedeprecated quantizer 0–630Deprecated minimum quantizer (0–63). Use —qcolor.
--max, --max:u, --max:updatedeprecated quantizer 0–6363Deprecated maximum quantizer (0–63). Use —qcolor.
--minalpha, --minalpha:u, --minalpha:updatedeprecated quantizer 0–630Deprecated minimum alpha quantizer (0–63). Use —qalpha.
--maxalpha, --maxalpha:u, --maxalpha:updatedeprecated quantizer 0–6363Deprecated maximum alpha quantizer (0–63). Use —qalpha.
--scaling-mode, --scaling-mode:u, --scaling-mode:updatepositive N[/D]1/1Frame or layer scaling as N[/D], for example 1/2.
--duration, --duration:u, --duration:updatepositive clock ticks1; may inherit Y4M timingFrame duration in timescale ticks for the following inputs. Applies with or without :u.
--advanced, -a, --advanced:u, --advanced:update, -a:u, -a:updateKEY[=VALUE], repeatablenonePass KEY[=VALUE] straight to the codec, for example -a tune=ssim. Repeatable. Keys are the codec’s own.
--minibuild-gated flagfalseCompact-header writer. Needs a build with AVIF_ENABLE_EXPERIMENTAL_MINI; not in current binaries.
--separatornot usedEnd of options; later arguments are filenames.

Plugin parameters for heif-enc --avif -e aom|rav1e|svt, set with -p NAME=VALUE. The full heif-enc frontend reference is on the HEIC page.

Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
realtimebooleanfalseUse libaom’s realtime mode instead of good-quality mode. Faster, larger.
speedinteger 0–96libaom cpu-used, 0 is slowest. Realtime mode changes what the values mean.
threadsinteger 1–64CPU count, max 64 (4 if undetectable)Worker threads.
qualityinteger 0–10050Colour quality.
losslessbooleanfalseLossless colour coding.
chroma420, 422 or 444420Chroma subsampling. Lossless RGB needs 444.
tuneauto, psnr, ssim or iqautoauto picks by image type (still, sequence, alpha). iq can’t be combined with lossless.
min-qinteger 0–630Lowest quantizer index the encoder may use.
max-qinteger 0–6363Highest quantizer index the encoder may use.
alpha-qualityinteger 0–100same as qualityAlpha quality. Follows the colour quality if unset.
alpha-min-qinteger 0–63same as min-qLowest alpha quantizer. Follows min-q if unset.
alpha-max-qinteger 0–63same as max-qHighest alpha quantizer. Follows max-q if unset.
lossless-alphabooleanfalseCode alpha losslessly while colour stays lossy.
auto-tilesbooleanfalseLet libaom choose the tile layout.
enable-intrabcbooleantrueAllow intra block copy, which helps screen content.
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
speedinteger 0–108rav1e speed, 0 is slowest.
threadsinteger 1–164Worker threads.
tile-rows1, 2, 4, 8, 16, 32, 644Number of tile rows (a count, not the log2 value avifenc uses).
tile-cols1, 2, 4, 8, 16, 32, 644Number of tile columns (a count, not log2).
chroma420, 422 or 444420Chroma subsampling.
min-qinteger 0–2550Lowest quantizer rav1e may use.
qualityinteger 0–100, -q only50 (set by heif-enc)Set with heif-enc -q and mapped to a 0–255 quantizer. Not in the parameter list, so -p quality= is rejected.
losslessnot settableunsupportedNo lossless mode: -L falls back to lossy with a warning, and -p lossless= is rejected.
Parameter / aliasesType or accepted valuesDefaultPurpose and constraints
speedinteger 0–1312SVT-AV1 preset. Lower is slower and smaller.
threadsinteger 1–164Thread hint, not a guaranteed worker count.
tile-rows1, 2, 4, 8, 16, 32, 644Number of tile rows.
tile-cols1, 2, 4, 8, 16, 32, 644Number of tile columns.
qualityinteger 0–10050Quality, converted to a QP unless qp is set.
losslessboolean, SVT ≥3falseLossless coding, SVT-AV1 3 or newer. heif-enc -L on RGB input (PNG, JPEG) exits with ‘Unsupported encoder parameter’ because it also sets chroma=444, which this plugin lacks.
qpinteger 0–63unset: derived from qualityQuantizer. Overrides quality when set.
min-qinteger 0–630Lowest quantizer SVT-AV1 may use.
max-qinteger 0–6363Highest quantizer SVT-AV1 may use.
tunevq, psnr, ssim, iq, ms-ssimpsnrSVT-AV1 tune: vq, psnr, ssim, iq, ms-ssim. iq and ms-ssim need SVT-AV1 4 or newer.
chromafixed 420420Not a parameter: the plugin always encodes YCbCr 4:2:0, and -p chroma= is rejected.