zencodec is the shared trait crate that defines the common API for all zen* image codecs.
It contains no codec logic — just traits, types, and format negotiation helpers. no_std compatible (requires alloc), forbid(unsafe_code).
Import as zencodec — use zencodec::encode, zencodec::decode, etc.
| Crate | Format | Repo |
|---|---|---|
zenjpeg |
JPEG | imazen/zenjpeg |
zenwebp |
WebP | imazen/zenwebp |
zenpng |
PNG | imazen/zenpng |
zengif |
GIF | imazen/zengif |
zenavif |
AVIF | imazen/zenavif |
zenjxl |
JPEG XL | imazen/zenjxl |
zenbitmaps |
PNM/BMP/Farbfeld | imazen/zenbitmaps |
heic |
HEIC/HEIF | imazen/heic |
zentiff |
TIFF (experimental) | imazen/zentiff |
zenpdf |
PDF (experimental) | imazen/zenpdf |
Every codec follows a three-layer pattern:
Config → reusable, Clone + Send + Sync, 'static — consumed by job()
Job → per-operation, owns config + stop token + limits + metadata
Executor → borrows pixel data or file bytes, consumes self to produce output
ENCODE: EncoderConfig → EncodeJob → Encoder / AnimationFrameEncoder
DECODE: DecoderConfig → DecodeJob<'a> → Decode / StreamingDecode / AnimationFrameDecoder
Config lives in a struct and gets shared across threads. A web server keeps one JpegEncoderConfig at quality 85 for all requests and clones it per-request. Calling job() consumes the config — clone first if you need it again. Job owns its config, cancellation token, resource limits, and metadata. Executor borrows pixels or bytes and consumes itself to produce output.
Each layer also has object-safe Dyn* variants for codec-agnostic dispatch:
DynEncoderConfig → DynEncodeJob → DynEncoder / DynAnimationFrameEncoder
DynDecoderConfig → DynDecodeJob → DynDecoder / DynStreamingDecoder / DynAnimationFrameDecoder
Blanket impls generate the dyn API automatically — codec authors implement the generic traits and get dyn dispatch for free.
use std::borrow::Cow;
use zenjpeg::{JpegEncoderConfig, JpegDecoderConfig};
use zencodec::encode::{EncoderConfig, EncodeJob, Encoder};
use zencodec::decode::{DecoderConfig, DecodeJob, Decode};
// Encode
let config = JpegEncoderConfig::new().with_generic_quality(85.0);
// (assuming pixels: PixelSlice from your pipeline)
let output = config.job().encoder()?.encode(pixels.as_slice())?;
let jpeg_bytes = output.into_vec();
// Decode
let config = JpegDecoderConfig::new();
let decoded = config.job().decoder(Cow::Borrowed(&jpeg_bytes), &[])?.decode()?;
let pixels = decoded.into_buffer();Color management is not the codec's job. Decoders return native pixels with ICC/CICP metadata. Encoders accept pixels as-is and embed the provided metadata. The caller handles CMS transforms.
Format negotiation over conversion. Decoders take a ranked &[PixelDescriptor] preference list and pick the first they can produce without lossy conversion. Pass &[] for native format.
Capabilities over try/catch. Codecs declare their capabilities as const EncodeCapabilities / DecodeCapabilities structs. Check before calling instead of catching UnsupportedOperation errors.
Pixel types from zenpixels. All pixel interchange types (PixelSlice, PixelBuffer, PixelDescriptor, etc.) are defined in the zenpixels crate. All zen* crates depend on zenpixels directly.
| Module | Contents |
|---|---|
zencodec::encode |
EncoderConfig, EncodeJob, Encoder, AnimationFrameEncoder, EncodeOutput, EncodeCapabilities, EncodePolicy, best_encode_format, dyn dispatch traits (DynEncoderConfig, DynEncodeJob, DynEncoder, DynAnimationFrameEncoder) |
zencodec::decode |
DecoderConfig, DecodeJob, Decode, StreamingDecode, AnimationFrameDecoder, DecodeOutput, DecodeCapabilities, DecodePolicy, DecodeRowSink, SinkError, OutputInfo, SourceEncodingDetails, negotiate_pixel_format, is_format_available, dyn dispatch traits (DynDecoderConfig, DynDecodeJob, DynDecoder, DynStreamingDecoder, DynAnimationFrameDecoder) |
zencodec::gainmap |
GainMapInfo, GainMapParams, GainMapChannel, GainMapDirection, GainMapPresence — cross-codec gain map types (ISO 21496-1) |
zencodec::helpers |
Codec implementation helpers (not consumer API) — shared boilerplate for trait implementors |
| root | ImageFormat, ImageFormatDefinition, ImageFormatRegistry (format detection via ImageFormatRegistry::detect()), ImageInfo, Metadata, Orientation, OrientationHint, ResourceLimits, LimitExceeded, ThreadingPolicy, UnsupportedOperation, CodecErrorExt, find_cause, Unsupported, Extensions, AnimationFrame, OwnedAnimationFrame, Cicp, ContentLightLevel, MasteringDisplay, StopToken, Unstoppable |
zencodec has no feature flags. The full API is always available.
- Contains no codec logic — traits, types, and format detection only.
ImageFormatenum is not extensible at runtime (theCustomvariant requires a&'staticdefinition).- Always
no_std+alloc(nostdfeature gate).
Rust 1.93+, 2024 edition.
| State of the art codecs* | zenjpeg · zenpng · zenwebp · zengif · zenavif (rav1d-safe · zenrav1e · zenavif-parse · zenavif-serialize) · zenjxl (jxl-encoder · zenjxl-decoder) · zentiff · zenbitmaps · heic · zenraw · zenpdf · ultrahdr · mozjpeg-rs · webpx |
| Compression | zenflate · zenzop |
| Processing | zenresize · zenfilters · zenquant · zenblend |
| Metrics | zensim · fast-ssim2 · butteraugli · resamplescope-rs · codec-eval · codec-corpus |
| Pixel types & color | zenpixels · zenpixels-convert · linear-srgb · garb |
| Pipeline | zenpipe · zencodec · zencodecs · zenlayout · zennode |
| ImageResizer | ImageResizer (C#) — 24M+ NuGet downloads across all packages |
| Imageflow | Image optimization engine (Rust) — .NET · node · go — 9M+ NuGet downloads across all packages |
| Imageflow Server | The fast, safe image server (Rust+C#) — 552K+ NuGet downloads, deployed by Fortune 500s and major brands |
* as of 2026
archmage · magetypes · enough · whereat · zenbench · cargo-copter
And other projects · GitHub @imazen · GitHub @lilith · lib.rs/~lilith · NuGet (over 30 million downloads / 87 packages)
Apache-2.0 OR MIT