A minimal JPEG decoder implementation written in Rust for educational purposes. The goal is to make the code readable and serve as a learning resource for understanding JPEG compression algorithms, rather than focusing on performance optimization.
Input: Baseline DCT JPEG images in JFIF format (.jpg/.jpeg)
Output: Decoded bitmap images (.bmp)
The decoder implements the full JPEG decoding pipeline:
JFIF File Format Parsing: SOI, APP0, COM, DQT, SOF0 (Baseline DCT), DHT, SOS, and EOI markers
Decoding Pipeline:
- Huffman Decoding - Constructs Huffman trees and decodes DC/AC coefficients with run-length encoding (RLE)
- Inverse Quantization - Dequantizes DCT coefficients using quantization tables
- Inverse Discrete Cosine Transform (IDCT) - Converts frequency domain back to spatial domain
- Color Space Conversion - YCbCr to RGB transformation
- Image Reconstruction - Assembles 8×8 MCU blocks into the final image
This implementation supports:
- Baseline DCT JPEG images only (no progressive JPEG)
- 4:4:4 chroma subsampling (no subsampling)
- 3-component YCbCr color images and 1-component grayscale images
As this is a learning-focused implementation, there are many low-hanging fruit optimizations that could significantly improve performance:
- Integer-based IDCT: Replace floating-point calculations with fixed-point integer arithmetic
- Separable 1D transforms: Use two 1D IDCT passes (rows then columns) instead of a 2D transform, reducing complexity from O(n⁴) to O(n³)
- Precomputed cosine tables: Cache cosine calculations instead of computing them for each coefficient
- SIMD vectorization: Leverage CPU vector instructions for parallel computation
- RST marker support: Implement restart marker (RST) handling to enable parallel decoding of image segments
- Multi-threaded block processing: Process multiple MCU blocks concurrently
- Chroma subsampling support: Implement 4:2:2 and 4:2:0 subsampling with upsampling
- Progressive JPEG: Add support for progressive DCT encoding
- Memory optimization: Reduce memory allocations and improve cache locality
This implementation was developed with the help of the following excellent resources:
# Build the project
cargo build --release
# Run the decoder (default image: images/lenna.jpg)
cargo run --releaseThe decoded output will be saved as a BMP file in the same directory as the input JPEG.
src/
├── main.rs # Entry point
├── jpeg_parser.rs # Main decoder logic and JFIF parsing
├── huffman_tree.rs # Huffman tree construction and decoding
├── bit_reader.rs # Bit-level reading utilities
└── constants.rs # JFIF markers and zigzag ordering
bmp- For saving decoded imagesbyteorder- For reading big-endian data from JPEG filesanyhow- For error handling