@takalawang/jpeg-decoder
v1.1.5
Published
A complete JPEG decoder implementation in TypeScript
Maintainers
Readme
@takalawang/jpeg-decoder
A complete JPEG decoder implementation in TypeScript with support for both baseline and progressive JPEG formats. Convert JPEG images to PNG, BMP, PPM, or raw RGBA data.
Installation
Local Installation
npm install @takalawang/jpeg-decoderOr with pnpm:
pnpm add @takalawang/jpeg-decoderGlobal Installation
For command-line usage, you can install globally:
npm install -g @takalawang/jpeg-decoderOr with pnpm:
pnpm add -g @takalawang/jpeg-decoderThis will make the jpeg-decode command available system-wide.
Usage
Programmatic API
import { JPEGDecoder } from '@takalawang/jpeg-decoder';
import { readFileSync } from 'fs';
// Read JPEG file
const data = readFileSync('image.jpg');
// Create decoder instance
const decoder = new JPEGDecoder(new Uint8Array(data));
// Decode image
const result = decoder.decode();
console.log(`Width: ${result.width}`);
console.log(`Height: ${result.height}`);
console.log(`Data: RGBA format, ${result.data.length} bytes`);
// Access pixel data (RGBA format)
const pixel = {
r: result.data[0],
g: result.data[1],
b: result.data[2],
a: result.data[3],
};Simple API
import { decodeJPEG, decodeAndConvert } from '@takalawang/jpeg-decoder';
import { readFileSync, writeFileSync } from 'fs';
// Decode to raw RGBA
const data = readFileSync('image.jpg');
const decoded = decodeJPEG(new Uint8Array(data));
// Decode and convert to PNG
const pngData = await decodeAndConvert(new Uint8Array(data), 'png');
writeFileSync('output.png', pngData);
// Decode and convert to BMP
const bmpData = await decodeAndConvert(new Uint8Array(data), 'bmp');
writeFileSync('output.bmp', bmpData);
// Decode and convert to PPM
const ppmData = await decodeAndConvert(new Uint8Array(data), 'ppm');
writeFileSync('output.ppm', ppmData);CLI Usage
After installation, you can use the jpeg-decode command:
# Decode JPEG and save as PNG (auto-detected from .png extension)
jpeg-decode decode input.jpg -o output.png
# Decode JPEG and save as BMP (auto-detected from .bmp extension)
jpeg-decode decode input.jpg -o output.bmp
# Convert to specific format (overrides auto-detection)
jpeg-decode decode input.jpg -o output.raw --format raw
jpeg-decode decode input.jpg -o output.ppm --format ppm
# Display image information only
jpeg-decode decode input.jpg -i
# Get detailed info about JPEG
jpeg-decode info input.jpg
# Works with both baseline and progressive JPEGs
jpeg-decode decode progressive.jpg -o output.pngAPI Reference
JPEGDecoder
Main decoder class for JPEG images.
Constructor
new JPEGDecoder(data: Uint8Array)data: JPEG file data as Uint8Array
Methods
decode(): DecodedImage
Decodes the JPEG image and returns the decoded data.
Returns:
interface DecodedImage {
width: number; // Image width in pixels
height: number; // Image height in pixels
data: Uint8Array; // RGBA pixel data (4 bytes per pixel)
}decodeJPEG()
Convenience function for quick decoding.
function decodeJPEG(data: Uint8Array): DecodedImage;decodeAndConvert()
Decode JPEG and convert to specific format.
async function decodeAndConvert(
jpegData: Uint8Array,
format: 'png' | 'bmp' | 'ppm' | 'raw'
): Promise<Buffer>;getEncoder()
Get encoder for specific format.
import { getEncoder } from '@takalawang/jpeg-decoder';
const encoder = getEncoder('png');
const pngBuffer = await encoder.encode(rgbaData, width, height);Output Formats
- PNG: Portable Network Graphics with zlib compression
- BMP: Windows Bitmap (32-bit RGBA)
- PPM: Portable Pixmap (P6 binary format, RGB only)
- RAW: Uncompressed RGBA data
Supported JPEG Features
✅ Supported
- Baseline DCT (SOF0) - Sequential JPEG
- Extended sequential DCT (SOF1) - Extended sequential JPEG
- Progressive DCT (SOF2) - Progressive JPEG with spectral selection and successive approximation
- Huffman coding - Standard entropy coding
- YCbCr color space - Standard JPEG color space
- CMYK color space - Adobe CMYK format (4-component)
- YCCK color space - YCbCr with K channel (Adobe format)
- Grayscale images - Single component images
- Multiple quantization tables - Up to 4 quantization tables
- Multiple Huffman tables - Separate DC/AC tables per component
- Chroma subsampling - 4:4:4, 4:2:2, 4:2:0 formats
❌ Not Supported
- Lossless JPEG (SOF3) - Predictive lossless encoding
- Hierarchical JPEG (SOF5-SOF7) - Multi-resolution pyramid encoding
- Arithmetic coding - Alternative entropy coding (rarely used due to patents)
How It Works
Progressive JPEG Decoding
Progressive JPEGs decode in multiple scans, gradually refining image quality:
- Spectral Selection: DC coefficients first, then AC coefficients in bands
- Successive Approximation: High-order bits first, then refinement bits
- Coefficient Accumulation: Multiple scans build up the final DCT coefficients
Output Format
The decoder outputs raw pixel data in RGBA format:
- 4 bytes per pixel (Red, Green, Blue, Alpha)
- Alpha channel is always 255 (fully opaque)
- Row-major order (left to right, top to bottom)
Technical Details
Decoding Pipeline
Baseline JPEG (SOF0)
- Marker Parsing: Identifies and processes JPEG markers (SOI, SOF, DHT, DQT, SOS, etc.)
- Huffman Decoding: Decodes compressed coefficients using Huffman tables
- Dequantization: Applies quantization tables to coefficients
- IDCT: Inverse Discrete Cosine Transform using efficient AAN algorithm
- Color Conversion: YCbCr to RGB conversion with inline optimization
- Rendering: Direct component-to-image rendering (no intermediate upsampling buffers)
Progressive JPEG (SOF2)
- Parse Progressive Scans: Reads multiple SOS markers with scan parameters
- Spectral Selection: Processes DC (0) or AC (1-63) coefficient ranges
- Successive Approximation: Accumulates bits across refinement scans
- Coefficient Assembly: Builds complete DCT blocks from multiple passes (including efficient EOB run handling)
- IDCT & Color Space: Same as baseline after coefficient reconstruction
Color Space Conversion
The decoder automatically detects and handles multiple color spaces:
- YCbCr → RGB: Standard JPEG color space using ITU-R BT.601 conversion
- CMYK → RGB: Adobe CMYK format (inverted values) with proper K channel handling
- YCCK → RGB: YCbCr with separate K channel, converted via CMY intermediate
- Grayscale: Single component copied to R, G, B channels
Color space detection uses the Adobe APP14 marker when present, or infers from component count.
Image Format Encoders
- PNG: Creates IHDR, IDAT (zlib-compressed), IEND chunks with CRC32 validation
- BMP: Windows DIB format with bottom-up row ordering and BITMAPINFOHEADER
- PPM: Simple NetPBM binary format (P6 magic number)
- RAW: Direct RGBA buffer output
Performance
The decoder is optimized for speed and memory efficiency:
- AAN Algorithm: Uses the Arai, Agui, and Nakajima algorithm for IDCT, reducing multiplications per block from ~1024 (naive) to < 100.
- Memory Optimization: Eliminates intermediate upsampling buffers, reducing memory usage during rendering.
- Inline Scaling: Calculates pixel coordinates on-the-fly for faster processing.
Decode time for 512×512 images: ~30-50ms on modern hardware.
Development
Setup
# Install dependencies
pnpm install
# Build project
pnpm build
# Run tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Lint code
pnpm lint
# Format code
pnpm formatProject Structure
src/
├── index.ts # Main exports
├── cli.ts # CLI interface
├── decoder.ts # Main decoder class
├── types.ts # TypeScript interfaces
├── bit-reader.ts # Bit-level reading utilities
├── huffman.ts # Huffman decoding
├── aan.ts # IDCT implementation (AAN algorithm)
├── encoders.ts # Image format encoders
└── __tests__/ # Test filesTesting
The project includes comprehensive tests using Vitest:
# Run all tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Test with specific file
jpeg-decode decode lena.jpg -iLicense
MIT License - see LICENSE file for details.
