Approfondimenti

BMP spiegato: il formato immagine più semplice di Windows

koboshiCo-founder
·12 min di lettura
BMP spiegato: il formato immagine più semplice di Windows
Riepilogo

BMP fa parte di Windows dal 1990. Memorizza pixel grezzi con header minimi, nessuna compressione e nessun canale alpha. Questo articolo ripercorre il formato dai 14 byte del BITMAPFILEHEADER ai contesti in cui compare ancora, come i sistemi embedded e l'imaging medico.

Se apri un file BMP in un editor esadecimale, i primi quattordici byte si presentano così:

42 4D 46 00 00 00 00 00 00 00 36 00 00 00

È l'intero BITMAPFILEHEADER. 42 4D è la signature "BM" in ASCII. I quattro byte successivi indicano la dimensione del file — 46 00 00 00 in little-endian corrisponde a 70. I quattro byte seguenti sono riservati e valgono sempre zero. Gli ultimi quattro byte sono l'offset ai dati pixel — 36 00 00 00 vale 54, quindi l'array dei pixel inizia al byte 54.

Nessun marker di compressione. Nessun profilo colore. Nessun canale alpha. Solo una signature, una dimensione e un offset. BMP è, come suggerisce il nome stesso, una mappa diretta di bit.

Cos'è BMP in realtà

BMP sta per Bitmap, o più formalmente Device Independent Bitmap (DIB). Microsoft lo introdusse con Windows 3.0 nel 1990 per memorizzare immagini raster senza legarle a uno specifico dispositivo di visualizzazione. Prima del DIB, Windows usava i Device Dependent Bitmaps (DDB), il cui formato pixel dipendeva dalla scheda grafica installata. Un DDB salvato su una macchina poteva essere illeggibile su un'altra.

BMP risolveva il problema conservando metadati sufficienti perché qualsiasi decoder potesse ricostruire l'immagine: larghezza, altezza, profondità di bit, tavolozza, tipo di compressione e l'array pixel grezzo. Il sistema operativo legge l'header, alloca un buffer e copia i pixel in memoria. Per le immagini a 24 bit non compresse, i dati pixel sono in genere triplette RGB scritte dal basso verso l'alto, riga per riga, riempite fino a un confine di quattro byte.

Questa semplicità rese BMP il formato immagine predefinito di Windows per oltre un decennio. Paintbrush, il motore degli sfondi di Windows, gli scanner di prima generazione e innumerevoli tool interni leggevano BMP nativamente.

La struttura del file

Un file BMP è composto da quattro parti, disposte in sequenza:

BITMAPFILEHEADER   (14 byte)
BITMAPINFOHEADER   (40 byte per la versione classica)
Color Table        (opzionale, per le modalità colore indicizzate)
Pixel Data         (l'immagine vera e propria)

BITMAPFILEHEADER (14 byte)

Bytes 0-1:   Signature    "BM" (0x42 0x4D)
Bytes 2-5:   FileSize     (uint32, little-endian)
Bytes 6-9:   Reserved     (sempre 0)
Bytes 10-13: Offset       (uint32, offset ai dati pixel dall'inizio del file)

La signature non è sempre "BM". Windows supporta anche "BA", "CI", "CP", "IC" e "PT" per varianti cursore e icona, ma in pratica ogni BMP che aprirai inizia con "BM".

BITMAPINFOHEADER (40 byte, tipo BITMAPINFOHEADER)

Bytes 0-3:   HeaderSize        (40)
Bytes 4-7:   Width             (int32, pixel)
Bytes 8-11:  Height            (int32, pixel; negativo significa top-down)
Bytes 12-13: Planes            (1)
Bytes 14-15: BitCount          (1, 4, 8, 16, 24 o 32)
Bytes 16-19: Compression       (0 = nessuna, 1 = RLE8, 2 = RLE4, 3 = bitfields)
Bytes 20-23: ImageSize         (0 se non compresso)
Bytes 24-27: XpixelsPerMeter   (risoluzione fisica)
Bytes 28-31: YpixelsPerMeter   (risoluzione fisica)
Bytes 32-35: ColorsUsed        (0 significa 2^BitCount)
Bytes 36-39: ColorsImportant   (0 significa tutti)

Le versioni successive di Windows aggiunsero header più grandi — 52, 56, 108 e 124 byte — per supportare maschere alpha, spazi colore e profili ICC. La versione da 40 byte è però quella che si incontra più spesso.

L'altezza indica la direzione

Se il campo altezza è positivo, l'immagine è memorizzata dal basso verso l'alto. La riga 0 nel file corrisponde alla riga inferiore dell'immagine. Se il campo altezza è negativo, l'immagine è memorizzata dall'alto verso il basso. È una delle peculiarità poco evidenti di BMP — la maggior parte degli altri formati usa l'ordine top-down per default.

La tavolozza dei colori

Per profondità di bit di 1, 4 o 8, BMP usa una tavolozza indicizzata. Ogni voce della tavolozza occupa quattro byte: blu, verde, rosso e un byte alpha riservato che viene quasi sempre ignorato. Un BMP a 256 colori ha una tavolozza di 1.024 byte subito dopo l'header. I dati pixel che seguono non sono colori — sono indici in quella tabella.

Il padding dei dati pixel

Ogni scanline deve essere un multiplo di quattro byte. Un'immagine a 24 bit larga 5 pixel richiede 15 byte per riga, che si arrotondano a 16. Quei byte di padding extra sono spazio sprecato, un altro piccolo motivo per cui BMP è inefficiente.

Ecco un esempio completo per un BMP 2 × 2 a 24 bit non compresso:

Offset 0x00: 42 4D 46 00 00 00 00 00 00 00 36 00 00 00  -- BITMAPFILEHEADER
Offset 0x0E: 28 00 00 00 02 00 00 00 02 00 00 00 01 00 18 00  -- BITMAPINFOHEADER
Offset 0x22: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
Offset 0x32: 00 00 00 00 00 00 00 00
Offset 0x36: FF 00 00 00 FF 00 00 00 FF  -- riga inferiore: rosso, verde, blu (con padding)
Offset 0x3F: 00 FF FF 00 FF FF 00 00 00  -- riga superiore: ciano, magenta, giallo (con padding)

Il panorama dei formati nel 1990

BMP non apparve nel vuoto. Entro il 1990, diversi formati immagine competevano già per attenzione:

FormatoCompressioneProfondità coloreTrasparenzaRischio brevettiUso tipico
GIFLZWMax 256 colori1 bitSì (LZW)Grafica web
JPEGDCT + Huffman24 bitNessunaQuasi noFotografie
TIFFMultipla opzionaleFino a 48 bitOpzionaleStampa, scansione
PCXRLEFino a 24 bitNessunaNoGiochi DOS, clip art
PICTRLEFino a 32 bitNoMac OS classico
BMPNessuna o RLEFino a 32 bitNessunaNoSfondi Windows, icone

GIF era già il default sul web, ma il brevetto LZW rendeva rischioso l'uso commerciale. JPEG era nato per le fotografie e scartava dati con compressione lossy. TIFF era potente ma sovraingegnerizzato — scrivere un reader TIFF universale era un progetto a sé. PCX stava scomparendo insieme al DOS.

Il punto di forza di BMP era la semplicità. Non era più piccolo, più veloce o più capace degli altri. Era semplicemente il formato che Windows capiva senza librerie aggiuntive.

Perché BMP funzionava

BMP aveva vantaggi concreti nel suo contesto:

Zero complessità di decodifica. Un BMP a 24 bit non compresso può essere renderizzato leggendo un header a dimensione fissa e copiando i pixel direttamente in un framebuffer. Nessuna tabella Huffman, nessuna macchina a stati DEFLATE, nessun passaggio progressivo. Questo lo rendeva ideale per sistemi embedded con CPU limitata.

Nessun vincolo di brevetto. A differenza del LZW di GIF, la compressione BMP era assente oppure RLE, entrambe libere da brevetti. Questo contava per gli tool open source e il software commerciale che voleva evitare la licenza GIF di Unisys.

Integrazione diretta con Windows. Le API Win32 offrivano LoadBitmap, BitBlt e StretchBlt costruiti attorno alle sezioni DIB. Uno sviluppatore poteva caricare un BMP in memoria e blittarlo sullo schermo in poche righe di C.

Layout di memoria prevedibile. Poiché i pixel BMP non compressi corrispondono direttamente alla memoria video, i motori di gioco e i tool grafici usarono BMP come formato di interscambio texture negli anni '90. Potevi mappare il file in memoria e trattare l'offset pixel come un buffer grezzo.

Dove BMP mostra i limiti

I punti di forza di BMP erano anche i suoi punti deboli. Il formato non riuscì a evolversi insieme al resto dell'industria.

Nessuna compressione efficace. I BMP non compressi sono enormi. Un'immagine 1920 × 1080 a 24 bit occupa 5,93 MB. La stessa immagine come JPEG qualità 90 è circa 300-500 KB. Man mano che velocità internet e costi di archiviazione diventavano vincoli, BMP divenne problematico.

La compressione RLE è debole. BMP supporta la run-length encoding RLE8 e RLE4, ma RLE aiuta solo le immagini con grandi aree uniformi. Fotografie e gradienti si comprimono male. I BMP codificati RLE sono rari nella pratica.

Nessuna trasparenza reale. Il BMP standard non ha canale alpha. La variante a 32 bit include un byte alpha, ma molti tool lo ignorano o lo trattano come riservato. Per la grafica web e gli sprite di gioco, questo rese BMP inutile rispetto a PNG.

Nessuna animazione, nessun metadato, nessun color management. BMP memorizza pixel e poco altro. Nessun EXIF, nessun supporto profilo ICC nell'header originale, nessun frame di animazione. Man mano che i flussi di lavoro diventavano più sofisticati, BMP rimase primitivo.

Memorizzazione dal basso verso l'alto. L'ordine di righe dal basso verso l'alto di default confonde i decoder e spreca cicli per la conversione. È un dettaglio che aggiunge attrito senza alcun beneficio.

I formati che hanno sostituito BMP

Le limitazioni di BMP hanno plasmato direttamente ciò che venne dopo.

PNG (1996) risolse il problema della trasparenza e della compressione. Offriva compressione lossless, alpha a 8 bit e una specifica più semplice di TIFF. PNG sostituì BMP quasi ovunque sul web e nelle applicazioni multipiattaforma.

JPEG (1992) risolse il problema delle fotografie. La sua compressione lossy basata su DCT rendeva le fotografie 10-20 volte più piccole del BMP non compresso. Per qualsiasi immagine a toni continui, JPEG divenne il default.

WebP (2010) aggiunse modalità lossy e lossless, animazione e alpha in un unico container. Un WebP lossless è tipicamente il 20-30% più piccolo di PNG, che a sua volta batte BMP di un margine enorme.

HEIC/HEIF (2013) portò la compressione HEVC sulle immagini fisse. Raggiunge dimensioni inferiori al JPEG con qualità migliore, supporta alpha e depth map, ed è ora il default sui dispositivi Apple. Quando un iPhone salva una foto, di solito è HEIC.

Ognuno di questi formati esiste perché BMP smise di essere sufficiente per uno specifico caso d'uso.

Dove BMP viene ancora usato

BMP non è scomparso. È stato semplicemente spinto in nicchie dove la sua semplicità vale più della sua inefficienza.

Interno di Windows. La schermata di avvio di Windows, finestre di dialogo legacy e alcune risorse di sistema usano ancora BMP. Le API Win32 GDI si aspettano dati DIB, e riscrivere quei percorsi di codice non vale il tempo di Microsoft.

Sistemi embedded e microcontrollori. Un piccolo LCD su Arduino o STM32 non ha RAM o CPU per decodificare PNG. Un BMP a 16 bit non compresso può essere copiato direttamente nel framebuffer con quasi nessun codice.

Imaging medico e scientifico. Alcuni viewer DICOM legacy e apparecchiature di laboratorio esportano BMP perché ogni sistema lo apre. La semplicità del formato riduce il rischio di interoperabilità, il che conta in ambienti regolamentati.

Reverse engineering e didattica. BMP è ancora uno dei migliori formati per insegnare la struttura dei file immagine. Gli header sono piccoli, il layout dei pixel è evidente e puoi costruire un decoder funzionante in un pomeriggio.

Legacy nello sviluppo di giochi. I motori di gioco e i tool texture più dati usavano BMP come formato intermedio. Alcune community di modding lavorano ancora con asset BMP perché i tool erano costruiti attorno a esso.

Riconoscere BMP dalla signature

Non fidarti dell'estensione .bmp. Leggi i primi due byte.

TypeScript

async function isBmp(file: File): Promise<boolean> {
  const buffer = await file.slice(0, 2).arrayBuffer()
  const bytes = new Uint8Array(buffer)
  return bytes.length === 2 && bytes[0] === 0x42 && bytes[1] === 0x4d
}

Python

def is_bmp(path: str) -> bool:
    with open(path, "rb") as f:
        return f.read(2) == b"BM"

Go

func isBmp(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	buf := make([]byte, 2)
	if _, err := f.Read(buf); err != nil {
		return false
	}
	return bytes.Equal(buf, []byte("BM"))
}

PHP

function isBmp(string $path): bool {
    $header = file_get_contents($path, false, null, 0, 2);
    return $header === "BM";
}

ImageMagick CLI

magick identify -verbose image.bmp | grep "Format:"
# Format: BMP (Microsoft Windows bitmap image)

O semplicemente:

file image.bmp
# image.bmp: PC bitmap, Windows 3.x format, 1920 x 1080 x 24

Il futuro di BMP

BMP è un formato concluso. La specifica principale non è cambiata in modo significativo dall'era di Windows 95. Questo è contemporaneamente un limite e una garanzia: un BMP scritto nel 1995 si apre ancora correttamente oggi.

Il formato non acquisirà nuove funzionalità. Non avrà una compressione migliore, una gestione alpha corretta o supporto per l'animazione. Nessuno investe in BMP perché nessuno ha bisogno di un BMP migliore. PNG, WebP, AVIF e HEIC hanno già vinto in ogni contesto in cui conta l'efficienza.

Ma BMP continuerà a essere usato nei luoghi in cui è già presente: interno di Windows, display embedded, apparecchiature mediche legacy e aule scolastiche. Non è elegante né efficiente, ma è difficile da eliminare perché troppi sistemi sanno ancora leggerlo.

Se ti ritrovi con file BMP legacy che devi usare su dispositivi moderni, la scelta più pratica è convertirli. Per le foto, convertire in JPEG o HEIC riduce lo spazio occupato. Per la grafica con trasparenza, PNG o WebP sono la destinazione giusta. E quando devi collegarti all'ecosistema Apple, convertire HEIC in un formato universalmente leggibile è il primo passo.

Il nostro convertitore HEIC in JPG gira interamente nel browser: il file non lascia mai il tuo dispositivo. Per un output lossless con trasparenza, usa HEIC in PNG. Per dimensioni ottimizzate per il web, HEIC in WebP ti offre file più piccoli con un ampio supporto browser.

BMP ha insegnato al settore una lezione utile: un formato non deve essere il migliore per essere ovunque. Deve solo essere abbastanza semplice perché tutti lo implementino, e abbastanza radicato perché nessuno osi rimuoverlo.

Altri post del blog da leggere