webp-anim
webp-anim is a reusable foundation for sequential, bounded-memory processing
of animated WebP frame sequences.
It preserves animation semantics while frames are inspected, decoded, resized, transformed, and re-encoded: frame order, source durations, loop count, and ANIM background color remain explicit parts of the processing contract.
The input is a complete WebP byte slice; decoded frames are processed one at a time instead of being retained as a complete RGBA sequence.
Unlike a general-purpose WebP codec wrapper, this crate focuses on the animation-aware processing pipeline above the codec layer. It keeps other application concerns out of the crate: archive handling, GUI frameworks, playback queues, and application-specific output policies are not included.
Positioning
The crate is intended to sit between a WebP codec implementation and an application-level viewer, converter, or optimizer:
WebP codec
↓
webp-anim
inspect → sequential decode → bounded frame transform → ordered encode
↓
consuming application
API at a glance
inspectclassifies a complete WebP byte slice as static or animated and returns canvas and animation metadata without decoding every frame.AnimationDecoderreads one stored animated sequence frame by frame as composited, full-canvas RGBA buffers, can inspect source durations without pixel decoding, and can reset the sequence without recreating the decoder.ResizePlanderives one aspect-ratio-preserving resize operation;ResizeWorkspacereuses its destination allocation across frames.AnimationEncoderaccepts full-canvas RGBA frames in presentation order and writes an animated WebP byte vector.transcode_animated_webpcomposes those stages for the common sequential decode-resize-encode path.
The modules under codec, inspect, model, resize, and transcode
are public for applications that need the lower-level types. The same primary
types are re-exported at the crate root for the common case.
Features
- Inspect static and animated WebP containers.
- Inspect stored animation frame durations without decoding RGBA pixels.
- Decode one stored animation sequence frame by frame.
- Reset a decoder to the stored sequence start for reuse.
- Return composited full-canvas RGBA frames.
- Preserve source frame durations without playback-time normalization.
- Resize animation frames with a reusable plan and workspace.
- Encode animated WebP frames in presentation order.
- Preserve animation loop count and ANIM background color when transcoding.
- Apply configurable input, canvas, frame-count, and RGBA buffer limits.
- Avoid retaining the complete decoded RGBA frame sequence in the processing path.
The decoder processes one stored animation sequence and reports its loop count, but does not replay frames according to that count. Playback and repetition policy belong to the consuming application.
Input and output contract
All processing APIs accept a complete WebP byte slice. inspect accepts both
static and animated WebP images. AnimationDecoder, AnimationEncoder, and
transcode_animated_webp operate on exactly one stored animated sequence;
they do not implement playback, loop replay, or application-level frame
queues.
Decoded frames are owned, tightly packed RGBA8 buffers in row-major,
full-canvas order. A frame for a width × height canvas therefore contains
width * height * 4 bytes. The decoder returns the source frame duration
without applying a playback minimum or other normalization.
The encoder requires durations that are an exact whole number of milliseconds.
It converts each duration to the cumulative WebP timestamp and flushes the
last frame duration when AnimationEncoder::finish is called. Every frame
must use the encoder canvas and the exact RGBA buffer length.
AnimationDecoder::frame_durations returns one Duration per stored frame in
source order. It reads animation-container metadata only: it does not decode
RGBA pixels or advance the decoder's sequential frame state. The durations are
subject to the decoder's configured total-duration limit.
AnimationDecoder::reset returns the existing decoder to the first stored
frame without cloning the input or creating a new native decoder. It is a
sequence reset, not a random-seek operation; the next next_frame call starts
again at the first frame.
AnimationInfo::loop_count and AnimationInfo::background_color describe the
stored WebP animation metadata. transcode_animated_webp copies both values
to the output. BackgroundColor::raw is preserved verbatim; this crate does
not assign a channel order or color-space interpretation to it.
Usage
Add the dependency:
[]
= "0.1.1"
Inspect an input:
use ;
Process an animation one frame at a time:
use ;
Inspect durations and reuse the same decoder:
use ;
The decoder owns only the input bytes and the current decoding state; callers can consume or hand off each decoded frame without collecting the complete animation in memory.
Resize and transcode one animation sequence:
use ;
transcode_animated_webp always produces an encoded result, including when
the resize operation is a no-op. The caller decides whether the encoded bytes
should replace the original input, for example by comparing output sizes.
For a keep-or-replace policy, the consuming application can make that decision after the transcode:
let result = transcode_animated_webp?;
let output = if result.bytes.len < input.len else ;
Semantics and limits
Frames are returned as composited, full-canvas RGBA buffers. Frame durations are the source durations and are not adjusted for an application's minimum playback delay. The source loop count and ANIM background color are represented as explicit values and are retained by the transcode path.
AnimationDecoder::frame_durations returns source durations in stored frame
order without advancing the RGBA decoder or decoding frame pixels.
AnimationDecoder::reset reuses the decoder and restarts sequential decoding
at the first stored frame; it does not provide random seeking.
The decoder applies configurable resource limits before and during processing. Applications should choose limits appropriate for their own input trust model and process-wide memory budget. The limits do not claim to bound allocations inside libwebp itself.
The default decoder and inspection limits are:
| Limit | Default |
|---|---|
| Input bytes | 256 MiB |
| Canvas pixels | 100,000,000 |
| Stored frame count | 10,000 |
| Total source duration | 1 hour (decoder only) |
| RGBA bytes per frame | 400 MiB |
ResizeOptions::max_output_rgba_bytes adds a destination-buffer limit for a
resize plan. DecodeLimits::for_trusted_input and
InspectLimits::for_trusted_input relax the crate-level checks, but do not
bypass libwebp or platform allocation limits. Do not use them as a substitute
for an application-wide resource policy when processing untrusted input.
Each fallible stage returns a typed error: InspectError, DecodeError,
ResizeError, EncodeError, or TranscodeError. The fast classifier
is_animated_webp_fast is intended only for routing and returns false for
malformed input; use inspect when the reason for rejection matters.
Low-level sequential pipeline
Use a reusable ResizePlan and ResizeWorkspace when processing many
frames. The workspace retains its resize state and destination buffer, while
the caller can hand each output frame directly to an AnimationEncoder:
use Duration;
use ;
The example shows the ownership and buffer contract; a real application would
replace the placeholder rgba buffer with each frame returned by
AnimationDecoder::next_frame.
Scope
This crate provides an animation-aware processing foundation. Playback control, GUI integration, worker lifecycle, archive orchestration, product presets, and application-wide concurrency or memory policies remain in the consuming application.
transcode_animated_webp is one convenience composition of the lower-level
primitives, not the only processing pipeline. Applications with different
policies can combine AnimationDecoder, ResizePlan, ResizeWorkspace, and
AnimationEncoder directly.
Reference integrations
The following public applications provide real-world integration examples:
These projects show application-level playback and optimization policies while
webp-anim remains independent of their archive, GUI, and product-specific
code.
Requirements
- Rust 1.85 or newer
- Rust 2024 Edition
The crate uses libwebp-sys for WebP decoding and encoding.
License
Licensed under the MIT License.