image (Rust crate)
| Language | Rust |
|---|---|
| License | MIT or Apache-2.0 |
| Repository | github.com/image-rs/image |
| Documentation | docs.rs/image, image::codecs::webp |
| Depends on | image-webp for WebP (pure Rust) |
| Read / write | yes / lossless only; decodes lossy, lossless, alpha, animation |
The image crate gives one API (DynamicImage, ImageBuffer) for PNG, JPEG, GIF, WebP, AVIF, TIFF and more, plus resizing, cropping and color conversion. Its WebP support comes from the pure Rust image-webp crate and is enabled by default.
Saving to .webp writes a lossless file. For lossy WebP, decode with image and encode with the webp crate, which accepts a DynamicImage.
Installation#
Shell
cargo add image
To compile only what you need: cargo add image --no-default-features --features webp,png,jpeg.
Basic usage: convert WebP to PNG and back#
Rust
fn main() -> Result<(), image::ImageError> {
let img = image::open("in.webp")?; // format detected from content
println!("{} x {}, {:?}", img.width(), img.height(), img.color());
img.save("out.png")?;
let thumb = img.thumbnail(400, 400); // fits in 400x400, keeps aspect ratio
thumb.save("thumb.webp")?; // lossless WebP
Ok(())
}
How to get WebP dimensions without decoding#
Rust
let (width, height) = image::image_dimensions("in.webp")?;
How to save a lossless WebP with explicit options#
Rust
use std::fs::File;
use std::io::BufWriter;
use image::codecs::webp::WebPEncoder;
use image::ExtendedColorType;
let img = image::open("logo.png")?.to_rgba8();
let out = BufWriter::new(File::create("logo.webp")?);
WebPEncoder::new_lossless(out).encode(img.as_raw(), img.width(), img.height(), ExtendedColorType::Rgba8)?;
How to read the frames of an animated WebP#
Rust
use std::fs::File;
use std::io::BufReader;
use image::codecs::webp::WebPDecoder;
use image::AnimationDecoder;
let decoder = WebPDecoder::new(BufReader::new(File::open("anim.webp")?))?;
if decoder.has_animation() {
let frames = decoder.into_frames().collect_frames()?;
for (i, frame) in frames.iter().enumerate() {
let (num, den) = frame.delay().numer_denom_ms();
println!("frame {i}: {} ms", num / den);
frame.buffer().save(format!("frame{i}.png"))?;
}
}
How to read Exif and the ICC profile#
Rust
use image::ImageDecoder;
let mut decoder = WebPDecoder::new(BufReader::new(File::open("in.webp")?))?;
if let Some(exif) = decoder.exif_metadata()? {
println!("Exif: {} bytes", exif.len());
}
if let Some(icc) = decoder.icc_profile()? {
println!("ICC: {} bytes", icc.len());
}
Tips#
- Use
image::ImageReader::open(path)?.with_guessed_format()?.decode()?when file extensions can’t be trusted. - Set
image::Limitson the reader to cap memory for untrusted input.