image
| Language | Rust |
|---|---|
| License | MIT or Apache-2.0 |
| Repository | github.com/image-rs/image |
| Documentation | docs.rs/image, image::codecs::avif |
| Depends on | ravif and rav1e for encoding (pure Rust, avif feature, on by default); mp4parse and the C library dav1d for decoding (avif-native feature) |
| Read / write | yes (with avif-native) / yes, still images; 8-bit encoding |
image is the most used Rust image crate: it loads and saves many formats into common buffer types (RgbaImage, DynamicImage) and resizes, crops and converts them. For AVIF it has 2 separate features:
avif(in the default features):AvifEncoder, built on ravif. Pure Rust.avif-native:AvifDecoder, which parses the container with Mozilla’s mp4parse and decodes AV1 with dav1d. dav1d is a C library that must be installed on the system (found with pkg-config).
Without avif-native, image::open("x.avif") fails with an unsupported-format error.
Installation#
Shell
cargo add image # includes AVIF encoding
cargo add image --features avif-native # also AVIF decoding
# dav1d for avif-native
sudo apt install libdav1d-dev # Debian / Ubuntu
brew install dav1d # macOS
vcpkg install dav1d # Windows
Basic usage: convert PNG to AVIF#
The output format comes from the file extension:
Rust
use image::ImageReader;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let img = ImageReader::open("in.png")?.decode()?;
println!("{} x {}", img.width(), img.height());
img.save("out.avif")?; // default speed and quality
Ok(())
}
How to set AVIF speed and quality#
Create the encoder yourself to choose speed (1-10, lower is slower and smaller) and quality (1-100):
Rust
use image::codecs::avif::AvifEncoder;
use std::fs::File;
use std::io::BufWriter;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let img = image::open("in.png")?;
let out = BufWriter::new(File::create("out.avif")?);
let encoder = AvifEncoder::new_with_speed_quality(out, 6, 70);
img.write_with_encoder(encoder)?;
Ok(())
}
How to encode a raw RGBA buffer to AVIF#
Rust
use image::codecs::avif::AvifEncoder;
use image::{ExtendedColorType, ImageEncoder};
fn encode(rgba: &[u8], width: u32, height: u32) -> image::ImageResult<Vec<u8>> {
let mut out = Vec::new();
AvifEncoder::new_with_speed_quality(&mut out, 8, 60)
.write_image(rgba, width, height, ExtendedColorType::Rgba8)?;
Ok(out)
}
How to decode an AVIF file#
Needs the avif-native feature and the dav1d library:
Rust
fn main() -> Result<(), Box<dyn std::error::Error>> {
let img = image::open("photo.avif")?; // DynamicImage
println!("{} x {}, {:?}", img.width(), img.height(), img.color());
img.save("photo.png")?;
Ok(())
}
How to get AVIF dimensions without decoding#
Rust
let (width, height) = image::image_dimensions("photo.avif")?; // needs avif-native
Tips#
- AVIF encoding through rav1e is very slow in debug builds; build with
--releaseor setopt-level = 3for dependencies in the dev profile. AvifEncoder::with_num_threads(Some(n))limits the rayon threads the encoder uses.- For animated AVIF or 10/12-bit output, use libavif from C, or ravif directly for 10-bit stills.