Image Formats and Encoding

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

See the section bibliography for the reference material consulted while preparing these pages.

Baseline date for this page: 2026-10-07. Browser support changes faster than the formats do, so confirm anything that matters on the MDN image type guide and Can I use before you drop a fallback.

A backend that accepts user uploads receives images in whatever format the user’s phone or editor produced, and has to send each client a format it can decode, at a size it needs, with as few bytes as possible. This page covers the formats and the encoder settings that decide the trade-off. The next pages cover variants and thumbnails and the per-language libraries.

The formats

Format Compression Transparency Animation Typical use Status and licence

JPEG

Lossy (DCT), 8-bit

No

No

Photos; universal fallback

Universally supported. Baseline patents long expired.

PNG

Lossless (DEFLATE), up to 16-bit

Yes (alpha)

APNG only

Screenshots, logos, line art

Universally supported. W3C standard.

WebP

Lossy (VP8) and lossless, 8-bit

Yes, also in lossy mode

Yes

General web images

Supported by current versions of all major browsers. BSD-style licence for libwebp.

AVIF

Lossy and lossless (AV1 intra frames), 8, 10 and 12-bit, HDR

Yes

Yes (image sequences)

Photos where size matters most

Supported by current major browsers. AV1 is royalty-free. Encoding is slow.

JPEG XL

Lossy (VarDCT) and lossless, can recompress JPEG losslessly

Yes

Yes

Archives, high quality

Browser support is uneven. Check before relying on it. Royalty-free.

HEIC / HEIF

Lossy (HEVC), 8 and 10-bit

Yes

Image sequences

Default photo format on iPhones

Patent-encumbered (HEVC). Native only on Apple platforms and some Android and Windows setups. Not a web delivery format.

HEIF is the container (ISO base media file format) and HEIC is HEIF with an HEVC-coded image. AVIF is also an HEIF container, with an AV1-coded image. That is why libheif reads both, and why a tool that handles AVIF can often be extended to HEIC with one more decoder library.

Why AVIF and WebP with a JPEG fallback is the default

  • AVIF usually gives the smallest file at equal visual quality for photos, WebP is a close second and is far cheaper to encode, and both are decoded natively by the browsers most visitors use.

  • A browser that supports neither still needs a picture, so one JPEG (or PNG when transparency matters) is always produced as the last source of a <picture> element, see native HTML images.

  • Content negotiation by Accept header (the server picks the format) and <picture> source lists (the browser picks the format) both work. The <picture> approach needs no server logic and caches cleanly at a CDN. The Accept approach needs a Vary: Accept header, or the CDN will serve the wrong format to some clients.

  • Encode cost is real. An AVIF encode at a slow speed setting can take seconds per image, so run it in a worker, see upload pipelines, not in the upload request.

Rule of thumb for what to generate per image:

  1. one AVIF variant (slow encode, smallest file);

  2. one WebP variant (fast encode, wide support);

  3. one JPEG variant (or PNG for graphics with transparency) as the fallback.

Quality settings and encoder trade-offs

Quality numbers are encoder-specific: JPEG quality 80 is not WebP quality 80 and neither is AVIF quality 80. Pick settings by looking at the output, then measure with an objective metric such as SSIM or VMAF (built for video, usable on stills).

Format Starting quality Notes

JPEG

75 to 85

Use a progressive scan and a modern encoder such as MozJPEG for smaller files at the same quality.

WebP

75 to 80 lossy

The method (effort) option trades encode time for size. Use lossless for graphics.

AVIF

50 to 65 in libvips and sharp, --min/--max quantiser 20 to 40 in avifenc

The speed or effort setting dominates encode time. Higher speed numbers mean faster, larger output in libaom and SVT-AV1.

PNG

not applicable

Lossless. Quantising to a palette (pngquant) shrinks files at a visible-quality cost.

Treat these as starting points to calibrate on your own images, not as recommendations from the encoder authors.

Other settings that change size more than people expect:

Chroma subsampling

JPEG usually stores colour at half resolution (4:2:0). That is invisible on photos and visible on red text over a white background. Use 4:4:4 for UI screenshots and keep 4:2:0 for photos.

Bit depth and HDR

AVIF and JPEG XL can carry 10-bit and HDR data. For web delivery of ordinary photos, 8-bit sRGB is the safe target.

Progressive vs. baseline JPEG

Progressive JPEGs render a blurry preview first and are usually slightly smaller.

Lossless vs. lossy

Use lossless only for graphics with flat colour. Lossless photos are several times bigger than lossy ones for no visible gain.

EXIF orientation, metadata and colour profiles

  • Orientation. Phones store the picture sensor-up and add an EXIF Orientation tag. Browsers honour it for <img> (CSS image-orientation: from-image is the default), but many processing libraries do not. Apply the rotation to the pixels during processing (libvips autorot, sharp rotate() with no arguments, Pillow ImageOps.exif_transpose) and then drop the tag, otherwise the output is rotated twice or not at all.

  • Metadata stripping. EXIF can hold GPS coordinates, device serial numbers and the photographer’s name. Strip it from every public variant, see security and operations. Keep the original file, with metadata, in private storage if you need it.

  • Colour profiles. Convert wide-gamut sources (Display P3 from iPhones, Adobe RGB from cameras) to sRGB for web variants, and either embed the profile or tag the file as sRGB. Without conversion, saturated colours look dull on clients that assume sRGB. Keep a profile only when you really target wide-gamut displays.

  • HEIC from iOS. iPhones upload HEIC by default unless the app asks for a compatible format. Convert to JPEG or AVIF on ingest, with a decoder built with libheif, and treat HEIC as an input format only.

Commands

libvips

libvips is the fastest general-purpose image library for server use, and the engine behind sharp, pyvips and NetVips. The command line tool is vips.

# Resize to 1280 px wide, apply EXIF rotation, convert to sRGB, strip metadata, write an AVIF.
vips thumbnail input.heic output.avif[Q=60,effort=5,keep=none] 1280 --export-profile srgb --size down

# The same as WebP and JPEG.
vips thumbnail input.heic output.webp[Q=78,keep=none] 1280 --export-profile srgb --size down
vips thumbnail input.heic output.jpg[Q=80,optimize_coding,keep=none] 1280 --export-profile srgb --size down

vips thumbnail keeps metadata by default, so the keep=none save option is what strips it (libvips 8.15 and later; older versions use strip instead, which 8.15 deprecated). --size down stops it from enlarging images smaller than the target. vips thumbnail also shrinks on load where the format allows it, which is why it is much faster than loading the whole image first. Reference: libvips command line and the heifsave option list.

cwebp

cwebp -q 78 -m 5 -resize 1280 0 input.png -o output.webp
cwebp -lossless input.png -o output-lossless.webp

Reference: cwebp documentation.

avifenc

avifenc --min 20 --max 35 --speed 6 --jobs all input.png output.avif

avifenc ships with libavif, supplied by most Linux distributions as libavif-bin. Reference: libavif and the AV1 Image File Format specification.

JPEG XL

cjxl input.png output.jxl -d 1.0 -e 7
djxl input.jxl output.png

-d is the Butteraugli distance (0 means lossless, around 1 is visually lossless). Reference: jpeg.org JPEG XL and the libjxl repository.