fast-webp
fast-webp is a small WebP encoder crate for Rust applications that need the
ergonomics of the webp crate and a faster hot path.
It is intentionally narrow:
RgbImage,RgbaImage,DynamicImage-> WebP bytes- RGB/RGBA byte buffers -> WebP bytes
- optional JPEG/PNG response bytes -> WebP bytes via
imagecodecs
It does not try to be an image processing framework. Resize, crop, filters, metadata editing, animation, and WebP decoding are out of scope for the first version.
Why this exists
The upstream webp crate has a convenient
Encoder::from_image(&image).encode(quality) API. Internally it is organized as
a small wrapper around libwebp-sys: src/lib.rs re-exports modules,
src/encoder.rs builds an encoder/picture pipeline, and src/shared.rs owns the
WebP memory wrappers.
That shape is good for a general wrapper, but for reverse proxies and HTTP image conversion we want a shorter path:
DynamicImage/RGB/RGBA/JPEG/PNG -> RGB/RGBA bytes -> WebPEncodeRGB/RGBA -> Vec<u8>
So fast-webp keeps the public API simple and pushes the encoding hot path
through libwebp-sys with a fast encoder configuration:
WebPConfigwithmethod = 0pass = 1thread_level = 1WebPPictureImportRGBWebPPictureImportRGBAWebPEncodeWebPFree
Install
[]
= "0.1"
Runtime dependencies are deliberately close to webp:
[]
= "0.9.3"
= { = "^0.25.0", = false, = true }
Minimal encoder-only build:
[]
= { = "0.1", = false }
Only image buffer integration:
[]
= { = "0.1", = false, = ["image"] }
JPEG/PNG byte conversion through image codecs:
[]
= { = "0.1", = ["image-codecs"] }
If your proxy already decodes PNG/JPEG with another fast decoder, prefer feeding
the resulting RGB/RGBA buffer into encode_rgb or encode_rgba. That is the
fast path this crate optimizes.
Public API
Raw Buffers
Use this when you already have tightly packed RGB/RGBA pixels.
use ;
let rgb = vec!;
let webp = encode_rgb?;
let rgba = vec!;
let webp_with_alpha = encode_rgba?;
The encoder validates:
- quality is finite and in
0.0..=100.0 - width and height are non-zero
- dimensions are within
WEBP_MAX_DIMENSION width * height * channelsdoes not overflow- input length exactly matches the expected packed buffer length
image crate
Enable the image feature. It is enabled by default.
use ;
let image = open?;
let webp = encode_dynamic_image?;
write?;
Direct RgbImage / RgbaImage entry points avoid unnecessary conversion:
use ;
let rgb = open?.to_rgb8;
let webp = encode_rgb_image?;
let rgba = open?.to_rgba8;
let webp = encode_rgba_image?;
DynamicImage handling is deliberately conservative:
ImageRgb8-> RGB encodeImageRgba8-> RGBA encode- grayscale -> RGB
- grayscale + alpha -> RGBA
- higher-depth RGB ->
to_rgb8 - everything else ->
to_rgba8
JPEG/PNG bytes
Enable image-codecs for this convenience API. This keeps the default crate
small while still allowing a single-call proxy workflow when you want it.
use ;
let webp = convert_bytes_to_webp?;
Format detection is magic-byte based:
use ;
assert_eq!;
Decoder path:
- JPEG ->
imageJPEG decoder ->DynamicImage-> RGB/RGBA encode - PNG ->
imagePNG decoder ->DynamicImage-> RGB/RGBA encode
The 800 ms target for a 4 MB PNG depends mostly on PNG decode time and CPU. The
part controlled by this crate is the WebP encode path after decode: it avoids
the heavier WebPPicture setup used by generic wrappers and calls the simple
WebPEncode* functions directly. For the fastest proxy path, decode with the
fastest decoder available in your application and call encode_rgb/encode_rgba.
- PNG grayscale -> RGB
- PNG grayscale + alpha -> RGBA
Options
use WebpOptions;
let lossy = WebpOptions ;
let lossless = WebpOptions ;
For lossless mode, quality is still validated for API consistency, but the
simple libwebp lossless functions do not use it.
File Layout
src/lib.rs public facade and crate docs
src/options.rs WebpOptions
src/error.rs WebpError
src/encode.rs hot path: validation + fast WebPConfig + libwebp-sys FFI
src/bytes.rs detect_format + optional image-codecs bytes API
src/image_api.rs image crate integration
src/pixel.rs internal pixel layout and grayscale helpers
src/tests.rs unit tests for public behavior
benches/convert.rs Criterion comparison with webp crate
examples/ runnable API examples
Examples
Benchmarks
Current benchmark groups:
webpcrateDynamicImage -> WebPfast-webpDynamicImage -> WebPfast-webpJPEG bytes -> WebPfast-webpPNG bytes -> WebP
The benchmark generates images in memory so it is reproducible in CI. For proxy tuning, add your production JPEG/PNG corpus and run the same groups against those files.
Release
Tag the release from the clean commit:
After crates.io accepts the package: