Skip to content

v0.3.2

Choose a tag to compare

@lilith lilith released this 02 May 23:57
· 41 commits to main since this release

⚠️ YANKED — this version has been pulled from crates.io. It contains a use-after-free in StreamingDecoder::update (fixed in 0.3.4) plus other soundness issues fixed across the 0.2.x / 0.3.x series. Use 0.3.4 or later — or, recommended for new projects, switch to zenwebp, which is #![forbid(unsafe_code)] and has no FFI exposure.


0.3.2 — full zencodec trait integration, trivial swap between webpx and zenwebp.

Recommendation: Use zenwebp instead

For new projects, zenwebp is the recommended choice — equally or more capable than webpx (full feature parity with libwebp, native wasm32-unknown-unknown support that webpx cannot offer, performance and compression within noise on average), and built with #![forbid(unsafe_code)] so the whole class of FFI / memory-safety bug is structurally impossible. libwebp has a documented high-severity CVE history (CVE-2023-4863 was an actively-exploited 0-click heap overflow patched out of band in every major browser), and every libwebp wrapper that has been audited — webpx included — has shipped soundness bugs.

Trivial swap with zenwebp

webpx and zenwebp now expose identical pub mod zencodec surfaces — the same wrapper-type names, the same constructors, implementing the same zencodec traits. Switching backends is a one-line change:

// One line changes:
use webpx::zencodec::WebpEncoderConfig;       // libwebp FFI backend
// use zenwebp::zencodec::WebpEncoderConfig;  // pure-Rust backend

// Everything below is identical:
use zencodec::encode::{EncoderConfig, EncodeJob, Encoder};
let cfg = WebpEncoderConfig::lossy().with_generic_quality(85.0);
let webp = cfg.job().encoder()?.encode(pixel_slice)?.into_vec();

See examples/zencodec_swap.rs for the swap pattern end-to-end.

Added

  • zencodec Cargo feature with a new pub mod zencodec exposing WebpEncoderConfig, WebpEncodeJob, WebpEncoder, WebpAnimationFrameEncoder, WebpDecoderConfig, WebpDecodeJob, WebpDecoder, WebpStreamingDecoder, WebpAnimationFrameDecoder. Type names and method signatures mirror zenwebp::zencodec exactly.
  • All four executor traits wired:
    • zencodec::encode::Encoder on WebpEncoder — RGBA / BGRA / RGB input, ICC / EXIF / XMP metadata, generic-quality / generic-effort calibration, Limits propagation.
    • zencodec::encode::AnimationFrameEncoder on WebpAnimationFrameEncoder — accepts per-frame PixelSlices, converts cumulative-timestamp on the trait side to webpx's timestamp-per-frame model, embeds metadata after assembly.
    • zencodec::decode::Decode on WebpDecoder — full single-image decode with caller-preferred descriptor selection.
    • zencodec::decode::AnimationFrameDecoder on WebpAnimationFrameDecoder — frame-by-frame and sink-based rendering, with frame_count / loop_count accessors.
    • zencodec::decode::StreamingDecode on WebpStreamingDecoder — buffered approach (full input → single batch). A row-batch implementation against libwebp's incremental decoder is a future iteration.
  • From<webpx::Limits> for zencodec::ResourceLimits and reverse. Field-for-field mirror minus webpx's max_metadata_bytes (no zencodec counterpart, drops on round-trip).

Testing

  • 7 integration tests in tests/zencodec_integration.rs (encoder/decoder roundtrip, lossless preservation, animation roundtrip through trait surface, streaming decode through trait surface, limits propagation, capabilities table, Limits round-trip).
  • examples/zencodec_swap.rs demonstrates the swap pattern end-to-end.

Pinned to zencodec = 0.1.13 (matching zenwebp) so trait impls land on the same semver line. cargo semver-checks: no breaking changes.

Full changelog: https://github.com/imazen/webpx/blob/main/CHANGELOG.md