img4avif
A fast, memory-safe Rust library that converts JPEG, PNG, WebP, and HEIC/HEIF
images to AVIF using the pure-Rust rav1e AV1 encoder. It also supports
16-bit PNG input for HDR10-style images.
Optimized for cost-sensitive, high-volume serverless workloads on AWS Lambda (Linux x86_64 / aarch64).
Table of contents
- Installation
- Quick start
- Supported input formats
- HDR10 support
- Configuration reference
- Output resolution control
- EXIF / metadata handling
- Memory guard
- Feature flags
- Performance benchmarks
- AWS Lambda deployment
- Security
- License
Installation
[]
= "0.5"
Minimum supported Rust version (MSRV)
img4avif requires Rust 1.85 or later. The MSRV is enforced in
Cargo.toml and tested in CI.
Quick Start
use ;
Lambda Cost Optimised Preset
use ;
let converter = new?;
// quality=75, speed=10, strip_exif=true, max_input_bytes=50 MiB
let avif = converter.convert?;
Supported Input Formats
| Format | Extensions | Feature flag | AVIF bit-depth |
|---|---|---|---|
| JPEG | .jpg, .jpeg |
(always on) | 10-bit (ravif auto) |
| PNG (8-bit) | .png |
(always on) | 10-bit (ravif auto) |
| PNG (16-bit / HDR10) | .png |
(always on) | 10-bit via encode_raw_planes_10_bit |
| WebP | .webp |
(always on) | 10-bit (ravif auto) |
| HEIC / HEIF | .heic, .heif |
heic-experimental |
10-bit (ravif auto) |
Format detection uses magic bytes, so file extensions are not trusted.
HDR10 support
16-bit PNG inputs
16-bit PNG files (the standard delivery format for HDR10 still images) are
decoded at full precision and converted to10-bit AVIF using
encode_raw_planes_10_bit to preserve more detail than 8-but ouput
HEIC with HDR10 metadata
Many smartphone cameras produce HDR10-tagged HEIC files. Enable the
heic-experimental Cargo feature to decode these:
[]
= { = "0.5", = ["heic-experimental"] }
⚠️ Requires
libheifinstalled on the system at link time. See Feature flags for details and licensing implications.
Configuration Reference
The Config builder lets you balance image quality, file size, and
encode speed:
Recommended starting points
- Thumbnails / Lambda / high-throughput pipelines: use
quality=70andspeed=10 - Archival photos / maximum fidelity: use
quality=95and a lower speed such as6
| Field | Type | Default | Description |
|---|---|---|---|
quality |
u8 |
80 |
Colour encoding quality (1 – 100). Higher value preserves the image quality, lower value produces smaller file size. |
alpha_quality |
u8 |
80 |
Alpha-channel quality (1 – 100) preserves visual transparency. Higher value keep the original transparency level, lower value produces smaller file size. |
speed |
u8 |
6 |
Encoder speed (1 – 10). Higher value encodes faster, lower value produces smaller file size. |
strip_exif |
bool |
true |
Strip all EXIF/IPTC/XMP metadata (recommended). |
max_input_bytes |
u64 |
104_857_600 (100 MiB) |
Maximum raw input file size. |
max_pixels |
u64 |
268_435_456 (268 MP) |
Max pixel count (width × height). |
memory_limit_bytes |
u64 |
536_870_912 (512 MiB) |
Peak memory budget for conversion. |
output_resolutions |
Vec<OutputResolution> |
[Original] |
Which resolution(s) to produce. See Output resolution control. |
All setter methods return Self for chaining:
let config = default
.quality
.alpha_quality // keep alpha visually lossless
.speed
.max_pixels
.memory_limit_bytes;
Output Resolution Control
By default img4avif encodes images at their original resolution. Use
Config::output_resolutions with any combination of OutputResolution
variants to resize before encoding.
| Variant | Target width | Behaviour |
|---|---|---|
Original |
— | No resize; encodes at source dimensions |
Width2560 |
2560 px | Shrinks to 2560 px wide if source is wider |
Width1080 |
1080 px | Shrinks to 1080 px wide if source is wider |
Rules:
- Only downscales. Images already at or below the target width are
passed through unchanged —
img4avifnever upscales. - Aspect ratio preserved. Height is computed proportionally; no cropping.
- Lanczos-3 filter is used for high-quality downsampling.
Single output at a specific width
use ;
let config = default
.output_resolutions;
let avif = new?.convert?;
Multiple outputs in one decode pass
Use convert_multi to decode once and get all requested sizes:
use ;
let config = default.output_resolutions;
let outputs: = new?.convert_multi?;
for out in &outputs
Lambda tip:
convert_multiwith all three resolutions costs only slightly more than a singleconvertcall because the decode step runs only once. The three encode passes are independent and parallelisable.
EXIF / metadata handling
By default, img4avif removes all metadata.
If you want to keep metadata, set strip_exif(false):
`:
A warning will be printed to stderr at conversion time when strip_exif = false.
Memory Guard
The [MemoryGuard] checks RSS before and after decoding. If peak RSS
exceeds memory_limit_bytes (default 512 MiB) conversion is aborted with
[Error::MemoryExceeded].
The 512 MiB default comfortably handles images up to ~25 MP RGBA8 on a 512 MB Lambda (pixel buffer ~96 MiB plus encoder working memory). For larger images, raise the limit accordingly or configure a higher-memory Lambda:
| Image size | Min recommended memory_limit_bytes |
|---|---|
| ≤ 25 MP | 512 MiB (default) |
| ≤ 50 MP | 512 MiB (default) |
| ≤ 100 MP | 768 MiB |
| ≤ 200 MP | 1024 MiB |
use ;
match converter.convert
| Platform | Memory source |
|---|---|
| Linux | /proc/self/status |
| macOS | vm_stat output |
| Windows | Not available (fail-open) |
Feature flags
| Flag | Default | Description |
|---|---|---|
dev-logging |
off | Structured pipeline logging via the log crate. Zero overhead when disabled. |
heic-experimental |
off | HEIC/HEIF decoding via libheif-rs. Requires the libheif C library at link time. |
raw-experimental |
off | Camera RAW decoding via rawloader (pure Rust, unstable API). |
dev-logging
When enabled, img4avif emits structured log records under the img4avif
target at every pipeline stage. Use any log-compatible
subscriber:
[]
= { = "0.5", = ["dev-logging"] }
= "0.11"
// Initialise the subscriber in your binary or test harness:
init;
// Then run with: RUST_LOG=img4avif=debug cargo run
| Level | What you see |
|---|---|
ERROR |
Every error path — context logged before Err(…) is returned |
WARN |
Non-fatal issues (metadata preservation, suspiciously small output) |
INFO |
Per-image milestones: dimensions, pixel format, compression ratio |
DEBUG |
Sub-step detail: quality / speed settings, RSS readings, byte counts |
When dev-logging is disabled (the default), all log macro calls expand
to () — the compiler removes them entirely, so there is zero runtime cost.
⚠️ HEIC / RAW support is experimental and opt-in. The pure-Rust HEIC ecosystem is not yet production-ready (as of Rust 1.70 / April 2024). The
heic-experimentalflag introduces a C dependency unsuitable for stock Lambda layers.⚠️ LGPL notice: the underlying
libheifC library is LGPL-licensed. Linking it makes your final binary LGPL-encumbered. Review your distribution obligations before enabling this feature in a commercial product. See NOTICE for full attribution details.
# Enable experimental HEIC/HEIF support (requires libheif C library):
[]
= { = "0.5", = ["heic-experimental"] }
# Enable experimental RAW support (pure Rust, no C):
[]
= { = "0.5", = ["raw-experimental"] }
Performance benchmarks
Measurements on an m6i.large EC2 (2 vCPU, 8 GB, Amazon Linux 2023,
RUSTFLAGS="-C target-cpu=native").
Throughput Estimates (quality=80)
| Input size | Encode time | AVIF size | Peak RSS |
|---|---|---|---|
| 1 MP (1000 × 1000 PNG, speed=6) | ~220 ms | ~45 KB | ~18 MB |
| 10 MP (3162 × 3162 PNG, speed=6) | ~1.8 s | ~350 KB | ~65 MB |
| 50 MP (8944 × 5615 PNG, speed=6) | ~9 s | ~1.6 MB | ~140 MB |
| 100 MB (5000 × 5000 PNG, speed=10) | ~12 s | ~2.2 MB | ~195 MB |
| 200 MP (16383 × 12207 PNG, speed=10) | ~60 s | ~8.5 MB | ~870 MB |
Lambda cold-start
| Metric | Value |
|---|---|
Converter::new() init time |
< 1 ms |
First convert() (64 × 64 PNG) |
< 50 ms |
Use speed=10 on Lambda to reduce CPU time at the cost of ~10–15% larger files. The
Config::lambda_cost_optimized()preset applies this automatically.
AWS Lambda Deployment
1. Build for Lambda (x86_64)
For aarch64 (Graviton2, typically cheaper):
2. Lambda Layer Configuration
# template.yaml (AWS SAM)
Layers:
- arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:layer:img4avif:1
Environment:
Variables:
# Optional: override quality at runtime
IMG4AVIF_QUALITY: "80"
3. Memory Estimates
| Image size | Minimum Lambda memory |
|---|---|
| ≤ 8 MP | 256 MB |
| ≤ 50 MP | 512 MB |
| ≤ 100 MP | 768 MB |
| ≤ 200 MP | 1024 MB+ |
License
- Licensed under the Apache License, Version 2.0.
- No GPL transitive dependencies in the default build (see LGPL note for
heic-experimental)
This product includes third-party components whose notices are listed in
NOTICE. The most notable is ravif (BSD-3-Clause), which provides
the AV1 encoder backend.