gamut-webp 0.2.0

WebP image encoder and decoder (intra-frame VP8/VP8L still images in a RIFF container).
Documentation

gamut-webp

gamut-webp is a pure-Rust WebP encoder and decoder — a VP8/VP8L still-image bitstream wrapped in a RIFF container.

Goals

Part of the gamut workspace, this crate provides WebP encoding (and, unusually for the encoder-first workspace, decoding) that is:

  • Memory-safe on hostile input. #![forbid(unsafe_code)], deleting the memory-corruption bug class behind libwebp's CVE record (e.g. the zero-click, wormable CVE-2023-4863). Because every WebP decoder in the Rust ecosystem ultimately wraps libwebp, a clean-slate safe decoder is worth carrying here.
  • Clean-slate from the spec. Implemented directly from the VP8 / VP8L bitstream specs (see ../../references/) rather than wrapping libwebp.
  • Layered on shared crates. The container comes from gamut-riff; the bit-level primitives from gamut-bitstream; color handling from gamut-color.
  • Buildable anywhere cargo is. No C, no nasm — cross-compiles cleanly (wasm32, aarch64, musl). (The differential test suite is the one exception: it builds libwebp via libwebp-sys as a dev-dependency, so running cargo test needs a C toolchain. The shipped library does not.)

WebP is one of gamut's three initial focus formats (alongside AVIF and JPEG).

Usage

The public API follows the same shape as gamut-avif: a WebpEncoder implementing [gamut_core::EncodeImage] and a WebpDecoder implementing [gamut_core::DecodeImage], both reachable through the umbrella crate's webp feature. Both codecs are fully implemented, taking a typed ImageRef and returning a typed ImageBuf, for RGB and RGBA:

  • VP8L losslessWebpEncoder::lossless emits a conformant bit-exact stream; WebpDecoder decodes any conformant VP8L stream.
  • VP8 lossyWebpEncoder::lossy(quality) runs the full intra key-frame codec (DC/V/H/TM and per-4×4 B_PRED prediction, the simple and normal loop filters, segmentation, token partitions, and skip); WebpDecoder decodes any conformant key frame.
  • AlphaEncodeImage<Rgba8> / DecodeImage<Rgba8>. A transparent lossy image uses the extended (VP8X) format with an ALPH chunk (raw or lossless); an opaque one stays a simple file.

Status

The intra-frame still-image surface and its milestones (M0 VP8L lossless → M1 VP8L full → M2 VP8 lossy → M3 extended container + alpha) are tracked component-by-component in STATUS.md. Every component is validated against libwebp as an oracle via libwebp-sys, bit-exact in both directions (gamut↔libwebp, at the YUV-plane level for lossy), backed by internal forward/inverse round-trips, the in-crate decoder, and a malformed-input robustness corpus.

Non-core feature paths are decided in STATUS.md: alpha/transparency (VP8X + ALPH) and color/metadata chunks (ICCP ICC profiles, EXIF, XMP ) are in scope — embedded on encode and preserved on decode. Animation (ANIM/ANMF) is out of scope under the image-first charter (each frame is an independent keyframe, but multi-frame sequences don't fit the single-image API); its chunks are tracked only for container completeness.

License

Licensed under either of MIT or Apache-2.0 at your option.