-
Notifications
You must be signed in to change notification settings - Fork 1
Unified JPEG encoder API surface across mozjpeg-rs and zenjpeg #18
Description
Summary
Make it trivial to swap between mozjpeg-rs and zenjpeg by unifying the native API surface. Both crates should support a common set of builder methods and encode calls so users change only the use statement. zencodec traits should be implemented directly on the native types (feature-gated), not via adapter wrappers.
Target API (works with either crate)
use mozjpeg_rs::{Encoder, Subsampling}; // OR: use zenjpeg::{Encoder, Subsampling};
let jpeg = Encoder::new()
.quality(85)
.progressive(true)
.subsampling(Subsampling::S420)
.optimize_huffman(true)
.deringing(true)
.icc_profile(icc_bytes)
.exif_data(exif_bytes)
.encode_rgb(&pixels, width, height)?;
Encoder::max_compression().encode_rgb(&px, w, h)?;
Encoder::fastest().encode_gray(&gray, w, h)?;With zencodec feature, the native type IS the zencodec config — no adapter wrapper:
// Encoder directly implements zencodec::EncoderConfig when feature="zencodec"
fn encode_generic<C: zencodec::encode::EncoderConfig>(config: C, pixels: PixelSlice<'_>) -> Vec<u8> {
config.job().encoder().unwrap().encode(pixels).unwrap().into_vec()
}Three-way API comparison
| Aspect | mozjpeg (C wrapper) |
mozjpeg-rs (current) |
zenjpeg (current) |
Unified |
|---|---|---|---|---|
| Type name | Compress |
Encoder |
EncoderConfig |
Encoder |
| Constructor | new(ColorSpace) |
new(Preset) |
ycbcr(q, ss) |
new() + explicit ctors |
| Quality | set_quality(f32) |
.quality(u8) |
.quality(impl Into<Quality>) |
.quality(impl Into<Quality>) |
| Progressive | set_progressive_mode() |
.progressive(bool) |
.progressive(impl Into<…>) |
.progressive(impl Into<…>) |
| Subsampling | tuples | Subsampling::S420 |
ChromaSubsampling::Quarter |
Subsampling::S420 |
| Deringing | N/A | .overshoot_deringing(bool) |
.deringing(bool) |
.deringing(bool) |
| Force baseline | N/A | .force_baseline(bool) |
.force_baseline() |
.force_baseline() |
| ICC | post-start | .icc_profile(Vec<u8>) builder |
request().icc_profile(&[u8]) |
.icc_profile(Vec<u8>) builder |
| Encode | start+write+finish | .encode_rgb(&[u8], w, h) |
.encode_bytes(&[u8], w, h, layout) |
.encode_rgb(&[u8], w, h) |
| zencodec | N/A | Adapter wrapper | Adapter wrapper | Direct trait impl on native type |
Tossups resolved toward zenjpeg's design (more elegant signatures).
Changes needed in zenjpeg
Native API additions
Encodertype alias —pub type Encoder = EncoderConfig;+ root re-export fromlib.rsSubsamplingre-export —pub use crate::types::Subsampling;fromencoder/mod.rsandlib.rsDefaultimpl —EncoderConfig::default()→ycbcr(85, Quarter).progressive(true).optimize_huffman(true)new()—pub fn new() -> Self { Self::default() }- Preset constructors —
max_compression()andfastest()delegating toOptimizationPreset .subsampling(Subsampling)— builder method converting via existingFrom<Subsampling> for ChromaSubsamplingencode_rgb()/encode_gray()— thin wrappers aroundencode_bytes()withRgb8Srgb/Gray8Srgb.icc_profile(Vec<u8>)/.exif_data(Vec<u8>)— metadata fields onEncoderConfig, wired intorequest()and one-shot encode- Un-hide
optimize_huffman()if currently#[doc(hidden)]
zencodec: direct trait impl, remove wrapper
Replace JpegEncoderConfig adapter with impl zencodec::EncoderConfig for EncoderConfig directly (feature-gated). The generic_quality_input: Option<f32> field moves onto EncoderConfig. JpegEncodeJob and JpegEncoder remain as thin feature-gated types (they hold per-operation state). Add pub type JpegEncoderConfig = EncoderConfig; for backwards compat.
Corresponding changes in mozjpeg-rs
Will be tracked in imazen/mozjpeg-rs separately:
Encoder::new()no-arg (oldnew(Preset)→with_preset(Preset))- Rename
overshoot_deringing→deringing(deprecated alias) - Add no-arg
force_baseline() - zencodec:
impl EncoderConfig for Encoderdirectly, removeMozjpegEncoderConfigwrapper
Intentional differences (not unified)
| mozjpeg-rs | zenjpeg | |
|---|---|---|
| Quality scale | mozjpeg u8 | jpegli f32 (different tables) |
Subsampling::Gray |
Exists | Use encode_gray() |
| Error type | mozjpeg_rs::Error |
zenjpeg::Error |
| Extended features | C compat, smoothing | XYB, AQ, parallel, hybrid trellis, f32/16-bit input |