rusty_jpeg 0.1.0

Pure-Rust JPEG/MJPEG decoder + encoder, no C/FFI. Baseline and progressive DCT, planar YUV in/out, real quality and chroma-subsampling control.
Documentation

rusty_jpeg

Remade With Rust By Mata Network License: MIT OR Apache-2.0 AND IJG

Pure-Rust JPEG / MJPEG decoder + encoder. No C, no FFI. Baseline and progressive DCT, planar YUV in and out, with real quality and chroma-subsampling control.

This crate is a vendored merge of two upstream pure-Rust projects, carried forward in-tree as one codec:

Half Upstream Licence
decode jpeg-decoder 0.3.2 MIT OR Apache-2.0
encode jpeg-encoder 0.7.0 (MIT OR Apache-2.0) AND IJG

See NOTICE.md for attribution and the IJG obligations, and CHANGES.md for everything changed since vendoring.

This software is based in part on the work of the Independent JPEG Group.

Why merge them

Holding the two halves in one crate buys three things the separate crates could not:

  1. The encoder is gated against the decoder as a round-trip oracle — the standing correctness gate for every change, running in CI on real content rather than as a one-off bring-up check.
  2. Shared primitives — quantization tables, zig-zag order, and the feature-gated stage profiler are defined once.
  3. The encoder's SIMD is on by default. Upstream put its AVX2 FDCT and RGB→YCbCr kernels behind a non-default simd feature; consumers who took the default (as this workspace did) silently ran the scalar path.

Decode

use std::io::Cursor;

fn main() -> Result<(), rusty_jpeg::decode::Error> {
    let bytes = std::fs::read("in.jpg").expect("read input");

    let mut decoder = rusty_jpeg::Decoder::new(Cursor::new(bytes));
    let pixels = decoder.decode()?;
    let info = decoder.info().expect("populated by decode()");

    println!("{}x{}, {:?}", info.width, info.height, info.pixel_format);
    println!("{} bytes of pixel data", pixels.len());
    Ok(())
}

Encode

use rusty_jpeg::{ColorType, Encoder};

fn main() -> Result<(), rusty_jpeg::EncodingError> {
    // A 2x2 RGB image: red, green, blue, white.
    let pixels = [255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 255];

    let mut jpeg = Vec::new();
    let encoder = Encoder::new(&mut jpeg, 90); // quality 0-100
    encoder.encode(&pixels, 2, 2, ColorType::Rgb)?;

    std::fs::write("out.jpg", jpeg).expect("write output");
    Ok(())
}

Chroma subsampling (SamplingFactor) and quantization table selection (QuantizationTableType) are set on the Encoder before encode.

Features

Feature Default Effect
std yes Standard library.
simd yes Encoder AVX2 FDCT + colour conversion.
rayon yes Decoder work-stealing threading.
platform_independent no Decoder: drop arch-specific code, forbid(unsafe_code).
benchmark no Expose internal kernels for A/B oracle tests.
profile no Feature-gated stage profiler; zero-cost when off.

Part of Remade With Rust

This crate is the standalone JPEG engine of remade_ffmpeg_rs — a ground-up, permissively-licensed Rust rebuild of FFmpeg: a drop-in ffmpeg/ffprobe CLI on pure-Rust codecs, with no copyleft. Also check out our sister project FFAI — media for an AI-first world — and the rest of github.com/remade-with-rust, including the sibling codec crates rusty_h264, rusty_vp9, rusty_mp3, rusty_aac, rusty-opus, rusty_vorbis, and the rusty-av1-toolkit forks.

Licence

(MIT OR Apache-2.0) AND IJG — the IJG clause attaches to the forward-DCT files inherited from the encoder. See NOTICE.md.