AVIF and HEIF encoding, bit depth, and speed/effort tuning
AVIF stores AV1 intra-coded frames inside a HEIF (ISO Base Media File Format) container. At comparable visual quality, AVIF typically saves 40%–50% over JPEG and 15%–25% over WebP, while supporting 8-bit, 10-bit, and 12-bit depth and wide-gamut HDR profiles.
In libvips, both AVIF and HEIC/HEIF are handled by heifload / heifsave (delegating via libheif to aom, rav1e, or svt-av1) with compression="av1".
Cross-binding AVIF parameter reference
Section titled “Cross-binding AVIF parameter reference”| Setting | govips AvifExportParams |
sharp .avif(options) |
pyvips / vips CLI heifsave |
Production guidance |
|---|---|---|---|---|
| Quality factor | Quality (default 80) |
quality (default 50) |
Q=55 / --Q 55 |
Watch the default difference: AVIF is highly efficient; 50–65 roughly matches JPEG 80–85 |
| Encoding speed / effort | Effort (0..9, default 5; legacy Speed is deprecated) |
effort (0..9, default 4) |
effort=4 / --effort 4 |
Same direction on libvips >= 8.13: 0 is fastest, 9 is slowest/best compression (use 3–5 for real-time services) |
| Lossless mode | Lossless: true |
lossless: true |
lossless=True / --lossless |
Lossless AVIF is slower and often larger than lossless WebP |
| Bit depth | Bitdepth (8 / 10 / 12) |
bitdepth (8 / 10 / 12) |
bitdepth=8 |
8 has universal browser support; 10/12 suits HDR and wide-gamut workflows |
| Chroma subsampling | — (AvifExportParams does not expose subsample_mode) |
chromaSubsampling (default '4:4:4') |
subsample_mode |
In sharp, pyvips, and CLI, set '4:2:0' (or on) for photography to reduce size and improve hardware decode compatibility |
AVIF export code across four interfaces
Section titled “AVIF export code across four interfaces”package main
import ( "fmt" "os"
"github.com/davidbyttow/govips/v2/vips")
func main() { if err := vips.Startup(nil); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer vips.Shutdown()
// Check whether the linked libvips build includes AVIF support if !vips.IsTypeSupported(vips.ImageTypeAVIF) { fmt.Fprintln(os.Stderr, "AVIF is not supported by this libvips build") os.Exit(1) }
image, err := vips.NewImageFromFile("input.jpg") if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer image.Close()
params := vips.NewAvifExportParams() params.Quality = 55 params.Bitdepth = 8 params.Effort = 4 // 0..9, lower is faster (NewAvifExportParams default is 5) params.StripMetadata = true
data, _, err := image.ExportAvif(params) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err := os.WriteFile("output.avif", data, 0o644); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) }}import sharp from 'sharp';
await sharp('input.jpg') .avif({ quality: 55, effort: 4, // 0..9, lower is faster bitdepth: 8, chromaSubsampling: '4:2:0', }) .toFile('output.avif');import pyvips
image = pyvips.Image.new_from_file("input.jpg")
# The .avif suffix selects heifsave with compression="av1" automaticallyimage.write_to_file( "output.avif", Q=55, effort=4, bitdepth=8, subsample_mode="on", keep="icc",)#!/usr/bin/env bashset -euo pipefail
vips heifsave input.jpg output.avif \ --compression av1 \ --Q 55 \ --effort 4 \ --bitdepth 8 \ --subsample-mode on \ --keep iccStreaming and libheif codec boundaries
Section titled “Streaming and libheif codec boundaries”- Streaming boundary in
govips v2.19.0:govipsprovidesSaveToWriterHeif(w, heifParams)but does not have a dedicatedSaveToWriterAvifmethod; useimage.ExportAvif(avifParams)(orSaveToWriterwithFormat: vips.ImageTypeAVIFinExportParams). libheifplugin availability: many Linux distributions buildlibheifwith AV1 plugins enabled (supporting.avif) while omitting patent-encumbered HEVC/x265 encoders (so.heicexport fails withUnsupported compression). See Missing codecs and unsupported formats for diagnostics.