image-webp
| Language | Rust |
|---|---|
| License | MIT or Apache-2.0 |
| Repository | github.com/image-rs/image-webp |
| Documentation | docs.rs/image-webp |
| Depends on | nothing outside Rust (no C code) |
| Read / write | yes / lossless only; decodes lossy, lossless, alpha, animation, ICC, Exif, XMP |
image-webp is the WebP codec of the image crate, also usable on its own. The decoder handles every WebP feature in safe Rust and is fuzzed. The encoder writes lossless (VP8L) files only; for lossy encoding use the webp crate, which binds libwebp.
It works with raw byte buffers: you get pixels as &mut [u8] in RGB or RGBA order.
Installation#
Shell
cargo add image-webp
Basic usage: decode a WebP#
Rust
use std::fs::File;
use std::io::BufReader;
use image_webp::WebPDecoder;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = BufReader::new(File::open("in.webp")?);
let mut decoder = WebPDecoder::new(file)?;
let (width, height) = decoder.dimensions();
let has_alpha = decoder.has_alpha();
println!("{width} x {height}, alpha: {has_alpha}, animated: {}", decoder.is_animated());
let size = decoder.output_buffer_size().ok_or("image too large")?;
let mut pixels = vec![0u8; size]; // RGBA if has_alpha, else RGB
decoder.read_image(&mut pixels)?;
Ok(())
}
How to encode a lossless WebP#
Rust
use std::fs::File;
use std::io::BufWriter;
use image_webp::{ColorType, WebPEncoder};
fn save(path: &str, rgba: &[u8], width: u32, height: u32) -> Result<(), Box<dyn std::error::Error>> {
let out = BufWriter::new(File::create(path)?);
let encoder = WebPEncoder::new(out);
encoder.encode(rgba, width, height, ColorType::Rgba8)?; // also L8, La8, Rgb8
Ok(())
}
set_icc_profile, set_exif_metadata and set_xmp_metadata on the encoder add metadata chunks.
How to read the frames of an animated WebP#
read_frame composes each frame onto the canvas and returns its duration in milliseconds:
Rust
let mut decoder = WebPDecoder::new(BufReader::new(File::open("anim.webp")?))?;
if decoder.is_animated() {
println!("{} frames, loop: {:?}", decoder.num_frames(), decoder.loop_count());
let mut frame = vec![0u8; decoder.output_buffer_size().unwrap()];
for i in 0..decoder.num_frames() {
let duration_ms = decoder.read_frame(&mut frame)?;
println!("frame {i}: {duration_ms} ms");
}
}
How to read Exif, XMP and the ICC profile#
Rust
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 profile: {} bytes", icc.len());
}
println!("lossy: {}", decoder.is_lossy());
Tips#
- Decode from memory with
WebPDecoder::new(std::io::Cursor::new(bytes)). set_memory_limitcaps allocations when decoding untrusted files.