JPEG: Joint Photographic Experts Group Standard for Lossy Image Compression
JPEG (Joint Photographic Experts Group) is the de facto standard for lossy compression of photographic images. Standardized in 1992, JPEG achieves ~10:1 compression ratios with imperceptible quality loss at moderate quality settings (Q=75–85). JPEG is universally supported—100% of browsers, cameras, and mobile devices natively support it.
JPEG File Structure: SOI, EOI, Markers
JPEG files are built on marker-based segments:
FF D8 (SOI — Start of Image)
FF E0 00 10 4A 46 49 46 00 (JFIF APP0 marker — defines JPEG variant)
[JFIF identifier and version]
FF DB … (DQT — Quantization Table)
FF C0 … (SOF0 — Start of Frame, baseline DCT)
FF C4 … (DHT — Huffman Table)
FF DA … (SOS — Start of Scan)
[compressed image data]
FF D9 (EOI — End of Image)
Key markers:
| Marker | Name | Purpose |
|---|---|---|
| FFD8 | SOI | Marks beginning of file |
| FFE0–FFE1 | APP0–APP1 | Application-specific data (JFIF, EXIF) |
| FFDB | DQT | Defines quantization tables (quality factor) |
| FFC0–FFC3 | SOF0–SOF3 | Start of Frame (specifies MCU dimensions, components) |
| FFC4 | DHT | Huffman table definition |
| FFDA | SOS | Start of Scan—signals compression data begins |
| FFD9 | EOI | End of Image |
JFIF Header: Aspect Ratio & Color Space
FF E0 (APP0 marker)
00 10 (segment length = 16 bytes)
4A 46 49 46 00 ('JFIF' identifier + null terminator)
01 00 (version 1.0)
00 (units: 0 = no units, 1 = DPI, 2 = DPCM)
00 48 (X density = 72 DPI)
00 48 (Y density = 72 DPI)
00 00 (thumbnail X/Y = none)
Sets aspect ratio and DPI metadata.
Image Encoding: MCU, DCT, Quantization
JPEG divides image into Minimum Coded Units (MCU)—typically 16×16 pixels (2×2 blocks of 8×8):
Step 1: Color Space Conversion (RGB → YCbCr)
Y = 0.299*R + 0.587*G + 0.114*B (luminance — perceived brightness)
Cb = -0.169*R - 0.331*G + 0.5*B (blue chrominance offset)
Cr = 0.5*R - 0.419*G - 0.081*B (red chrominance offset)
Separates luminance (1x data) from chrominance (2x2 subsampled to 0.25x → 4:2:0 sampling).
Step 2: 8×8 DCT (Discrete Cosine Transform)
DCT transforms 8×8 block of pixel values into frequency coefficients.
Result: [DC coefficient] [low-freq coefficients] [high-freq coefficients]
Concentrates energy in low frequencies—high frequencies are imperceptible to human vision.
Step 3: Quantization (Quality Factor)
Quantized Coefficient = round( DCT Coefficient / Quantization Value )
Quantization values increase for high frequencies (discard imperceptible details).
Example:
Quality = 75 (default): Quantization value 16 for high freq
Quality = 95 (high): Quantization value 1 for high freq
Quality = 10 (low): Quantization value 80 for high freq
Step 4: Huffman Entropy Coding
Variable-length codes: frequent symbols → shorter codes, rare symbols → longer codes
DC coefficient: -1000 → 5 bits
AC coefficients: 0 (runs) → 3–8 bits
Chroma Subsampling: 4:2:0, 4:2:2, 4:4:4
Human vision is less sensitive to color (chrominance) than brightness (luminance). JPEG exploits this:
| Sampling | Y:Cb:Cr | Size reduction | Quality loss | Use Case |
|---|---|---|---|---|
| 4:4:4 | 1:1:1 | None (24 bits/pixel) | Minimal | High-quality (Q≥85) |
| 4:2:2 | 1:0.5:0.5 | 33% | Very slight | Typical (Q=75–85) |
| 4:2:0 | 1:0.25:0.25 | 50% | Slight | Default (Q≤75) |
| 4:1:1 | 1:0.25:0.125 | 62.5% | Noticeable | Extreme compression |
Example (4:2:0 chroma subsampling):
Luminance (Y): 16×16 grid (256 values)
Chrominance (Cb): 8×8 grid (64 values)
Chrominance (Cr): 8×8 grid (64 values)
Total: 384 values (vs. 768 uncompressed)
File size: ~50% of uncompressed
Baseline vs. Progressive JPEG
Baseline JPEG:
SOS marker
[complete MCU data top-to-bottom, left-to-right]
EOI marker
Decoder renders scanlines as data arrives—interlacing not supported.
Progressive JPEG:
SOS marker (scan 1: DC coefficients + low AC)
[partial MCU data]
SOS marker (scan 2: higher AC)
[more detailed data]
[subsequent scans with increasing detail]
EOI marker
First scan shows rough preview, subsequent scans refine. Tradeoff: ~10% larger file but faster perceived load on slow networks.
EXIF & Metadata
EXIF (Exchangeable Image File Format):
FF E1 (APP1 marker)
[EXIF segment with camera metadata]
├── Model: Canon EOS 5D Mark IV
├── Focal Length: 50mm
├── Aperture: f/2.8
├── ISO: 3200
├── Flash: Yes
└── Timestamp: 2024-04-26 12:00:00 UTC
Preserves camera settings, GPS location, copyright info.
Comparison: JPEG vs. Competitors
| Metric | JPEG (Q=75) | PNG | WebP | HEIC |
|---|---|---|---|---|
| File size (photo) | 100 KB | 300 KB | 60 KB | 55 KB |
| File size (graphic) | 200 KB | 50 KB | 40 KB | 35 KB |
| Compression ratio | 12:1 | 3:1 | 20:1 | 22:1 |
| Transparency | ❌ | ✅ | ✅ | ❌ |
| Progressive | ✅ | ❌ | ❌ | ❌ |
| Browser support | 100% | 100% | 97% | 25% |
| EXIF metadata | ✅ | ⚠️ (limited) | ❌ | ✅ |
| Editing reversible | ❌ (re-save loses quality) | ✅ | ✅ | ❌ |
JPEG remains dominant for cameras and web photos. For web optimization, use WebP. For quality archives, use PNG or TIFF.
Practical JPEG Optimization
Quality settings:
- Q=95: Visually lossless (archive)
- Q=85: High quality (print, professional)
- Q=75: Good quality (default web)
- Q=60: Medium quality (thumbnails)
- Q=40: Low quality (placeholders)
FFmpeg (baseline JPEG, Q=85):
ffmpeg -i input.jpg -q:v 5 output.jpg
ImageMagick (progressive JPEG):
convert input.jpg -interlace Plane -quality 85 output-progressive.jpg
Python (Pillow):
from PIL import Image
img = Image.open('input.jpg')
img.save('output.jpg', 'JPEG', quality=85, optimize=True)
JPEG's combination of high compression, universal support, and decades of optimization make it the gold standard for photographic images worldwide.
Related conversions
Most teams that read this guide convert images in one of these directions: