BMP: Windows Bitmap as Foundation of Raster Graphics
The BMP (Bitmap) format is Windows' native uncompressed raster image format—arguably the simplest image format ever standardized, with near-zero processing overhead. While modern use is limited (JPEG, PNG vastly superior), BMP remains important for: embedded systems with minimal computational resources, legacy medical/industrial imaging hardware, and as a pedagogical reference for understanding raw raster structure.
BMP File Structure: File Header and DIB Header
Every BMP file contains two headers:
File Header (14 bytes):
[Signature: 2 bytes ('BM' = 0x42 0x4D)]
[File Size: 4 bytes (little-endian)]
[Reserved: 4 bytes (0x00000000)]
[Offset: 4 bytes (byte offset to pixel data)]
DIB Header (variable size, typically 40 or 108 bytes): Most common: BITMAPINFOHEADER (40 bytes):
[Header Size: 4 bytes (40 for this variant)]
[Width: 4 bytes (signed, pixels)]
[Height: 4 bytes (signed, pixels; negative = top-down)]
[Color Planes: 2 bytes (always 1)]
[Bits Per Pixel: 2 bytes (1, 4, 8, 16, 24, 32)]
[Compression: 4 bytes (0=uncompressed, 1=RLE-8, 2=RLE-4)]
[Image Size: 4 bytes (in bytes; can be 0 for uncompressed)]
[Horizontal Resolution: 4 bytes (pixels per meter)]
[Vertical Resolution: 4 bytes (pixels per meter)]
[Colors Used: 4 bytes (0 = default for bit depth)]
[Important Colors: 4 bytes (0 = all colors)]
[Optional Color Table: variable (palette entries if bit depth ≤ 8)]
[Pixel Data: variable]
Example: Minimal 1×1 8-bit BMP:
File Header:
42 4D (BM signature)
3A 00 00 00 (file size = 58 bytes)
00 00 00 00 (reserved)
36 00 00 00 (offset to pixel data = 54 bytes after headers)
DIB Header (BITMAPINFOHEADER):
28 00 00 00 (header size = 40)
01 00 00 00 (width = 1 pixel)
01 00 00 00 (height = 1 pixel)
01 00 (planes = 1)
08 00 (bits per pixel = 8)
00 00 00 00 (compression = none)
00 00 00 00 (image size = calculated by decoder)
13 0B 00 00 (72 DPI horizontal = 2835 pixels/meter)
13 0B 00 00 (72 DPI vertical)
00 00 00 00 (colors used = default for 8-bit)
00 00 00 00 (important colors = all)
Color Palette (8-bit: 256 entries × 4 bytes each = 1024 bytes):
[R, G, B, Reserved] for each color...
Pixel Data (1 pixel, 8-bit indexed):
00 (pixel value = color table index 0)
Color Depths and Encoding: 1-Bit to 32-Bit
| Depth | Type | Colors | Packing | File Size Example (1 MP) |
|---|---|---|---|---|
| 1-bit | Bilevel | 2 (B&W) | 8 px/byte | ~125 KB |
| 4-bit | Indexed palette | 16 | 2 px/byte | ~250 KB |
| 8-bit | Indexed palette | 256 | 1 px/byte | ~1 MB |
| 16-bit | RGB555 or RGB565 | 32K or 64K | 2 bytes/pixel (packed) | ~2 MB |
| 24-bit | True color RGB | 16.7M | 3 bytes/pixel (B, G, R order) | ~3 MB |
| 32-bit | RGBA (with alpha) | 16.7M + transparency | 4 bytes/pixel | ~4 MB |
Pixel encoding note: BMP stores pixels in bottom-up order (left-to-right, bottom row first) unless height is negative.
Color Palette: Indexed Color for 1-, 4-, 8-Bit Images
For palettized depths (1-, 4-, 8-bit), BMP includes a color table immediately after the header:
8-bit: 256 entries × 4 bytes (R, G, B, Reserved) = 1024 bytes
4-bit: 16 entries × 4 bytes = 64 bytes
1-bit: 2 entries × 4 bytes = 8 bytes
Each pixel value is an index into this table. Example:
- Pixel value
42in 8-bit image → color table[42] = (255, 128, 0) = orange - Pixel value
5in 4-bit image → color table[5] = (0, 0, 255) = blue
RLE Compression: Run-Length Encoding
BMP supports optional RLE (Run-Length Encoding) for 4- and 8-bit images:
Compressed: [Escape (0x00), Count (1 byte), Value (1 byte), ...]
Uncompressed: [0x00, 0x00] (end of line marker)
RLE is effective for synthetic images (diagrams, scans) with large color blocks; ineffective for photographic content.
Example 8-bit RLE (10 consecutive red pixels):
0A FF (10 copies of color index 255 = red)
BMP Variants: BITMAPCOREHEADER, BITMAPV4HEADER, BITMAPV5HEADER
- BITMAPCOREHEADER (12 bytes): Oldest variant; width/height stored as 2-byte integers (max 65K)
- BITMAPINFOHEADER (40 bytes): Standard; width/height as 4-byte signed (supports negative height for top-down)
- BITMAPV4HEADER (108 bytes): Adds color space (sRGB, Adobe RGB, custom ICC profile) and alpha mask
- BITMAPV5HEADER (124 bytes): Adds rendering intent and HDR metadata (rarely used)
BMP Limitations and Modern Alternatives
BMP weaknesses:
- No compression (by default): 1 MB image → 3–4 MB BMP file (vs. 50–200 KB JPEG)
- Bottom-up scanlines: Non-standard; complicates streaming decoders
- Poor color management: DIB headers have no native ICC profile support (BITMAPV4/V5 partially address this)
- Limited metadata: No EXIF, IPTC, or XMP support
- No interlacing: Cannot display progressive scans while downloading
Modern replacements:
- PNG: Lossless compression, transparency, ICC profiles, interlacing, superior compression
- JPEG: Lossy compression, excellent for photographs, 10–50× smaller than uncompressed BMP
- WebP: Modern compression (lossless and lossy), smaller than PNG/JPEG, good browser support
Processing BMP: Python, C Libraries, ImageMagick
Python (PIL/Pillow):
from PIL import Image
# Load BMP
img = Image.open('photo.bmp')
print(f"Size: {img.size}, Mode: {img.mode}") # Mode: 'RGB', 'RGBA', 'L', 'P', etc.
# Convert to PNG (compress)
img.save('photo.png') # ~90% size reduction typical
# Convert palette to RGB
if img.mode == 'P':
img = img.convert('RGB')
img.save('converted.bmp')
ImageMagick:
# BMP → PNG (compress)
convert photo.bmp photo.png
# BMP → JPEG (lossy, smaller)
convert photo.bmp -quality 85 photo.jpg
# Batch convert directory
mogrify -format png *.bmp
C library (libbmp via FFI):
#include <stdio.h>
// Platform-specific BMP read/write (minimal API, deprecated in favor of libpng/libjpeg)
Comparison: BMP vs PNG, JPEG, TIFF, WebP
| Aspect | BMP | PNG | JPEG | TIFF | WebP |
|---|---|---|---|---|---|
| Compression | None (or RLE) | Lossless (Deflate) | Lossy (DCT) | Optional (LZW, JPEG, none) | Lossless/lossy |
| File size | Largest (~1 MB per MP) | Small (~200 KB per MP) | Very small (~50 KB per MP) | Medium (300 KB–1 MB) | Small (~100 KB per MP) |
| Transparency | 32-bit alpha | Yes (8-bit alpha) | No | Yes (via clipping) | Yes (8-bit alpha) |
| Metadata | Minimal (DPI only) | Chunks (EXIF via chunk) | Markers (EXIF, IPTC) | Extensive (IFD tags) | Minimal |
| Color management | DIB color space (BITMAPV4+) | ICC profile (chunk) | Limited markers | Extensive ICC | Yes (VP8 CICP) |
| Interlacing | No | Yes (Adam7) | No (baseline progressive) | No (pyramidal TIFF) | Yes (VP8 preview) |
| Browser support | Universal | Universal | Universal | Poor (requires plugin) | Good (modern) |
| Archival rating | Poor (uncompressed) | Excellent | Fair (lossy artifacts) | Excellent | Unknown |
When to Choose BMP
- Embedded systems: Minimal CPU overhead; decodable in firmware
- Legacy hardware: Medical imaging, industrial control systems still expect BMP
- Pedagogical purposes: Learning raster structure; simplest image format
- Avoid BMP if: Internet delivery (use PNG/JPEG/WebP), compression needed, metadata required, modern software (prefers PNG)
BMP is deprecated for nearly all modern use cases but remains a fundamental reference for understanding raw raster encoding—pixel-perfect but inefficient.