KULT Underground

una della più "antiche" e-zine italiane – attiva dal 1994

Sbirciamo dentro i file BITMAP

6 min read

Sbirciamo dentro i file bitmap

Questo articolo risulterà forse un tantino legnoso, essendo rivolto principalmente a chi ha la necessità di scrivere applicazioni Windows o
OS/2 che manipolano e modificano file bitmap, insomma a programmatori abbastanza smaliziati e che hanno un po’ di familiarità con il linguaggio
C. Il formato bitmap infatti è il formato grafico standard di questi due sistemi. Una conoscenza di base del linguaggio C è raccomandata in quanto la struttura interna dei file bitmap verrà spiegata attraverso le convenzioni per la definizione delle strutture dati di questo linguaggio.
I files bitmap di Windows e di OS/2 sono memorizzati in un formato DIB
(device Indipendent Bitmap) che permette a Windows e a OS/2 di visualizzare l’immagine su ogni tipo di dispositivo di visualizzazione
(video, stampante, ecc…). Il termine device indipendent significa che il bitmap specifica il colore dei pixel in una forma indipendente dal metodo usato dal dispositivo di visualizazione per rappresentare i colori.
L’estensione di default dei file DIB di Windows e di OS/2 è .BMP

Ogni file bitmap contiene un bitmap-file header, un bitmap-information header, una color table ed un array dei byte che definiscono i punti del bitmap. I file bitmap quindi hanno la seguente struttura:

BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
RGBQUAD aColors[];
BYTE aBitmapBits[];

Il bitmap-file header contiene informazioni sul tipo, la dimensione in byte ed il layout del file bitmap. Questo header è definito come una struttura BITMAPFILEHEADER.
typedef struct tagBITMAPFILEHEADER{

unsigned int bfType;

double word bfSize;

unsigned int bfReserved1;

unsigned int bfReserved2;

double word bfOffBits;

} BITMAPFILEHEADER;

Il membro bfType Specifica il tipo di file. Perchè un file bitmap venga riconosciuto come tale il suo valore deve sempre essere ‘BM’ (424Dh,
6677d). La double word bfSize Specifica la lunghezza del file in byte. I double int bfReserved1 e bfReserved2 sono riservati, devono essere 0. bfOffBits specifica l’offset (distanza in byte) tra la struttura
BITMAPFILEHEADER e l’area dati vera e propria nel file.

Il bitmap-information header, definito come una struttura
BITMAPINFOHEADER, specifica le dimensioni, il tipo di compressione ed il formato del colore di un bitmap. Ha la seguente struttura:
typedef struct tag BITMAPINFOHEADER{

double word biSize;

long int biWidth;

long int biHeight;

word biPlanes;

word biBitCount;

double word biCompression;

double word biSizeImage;

long int biXPelsPerMeter;

long int biYPelsPerMeter;

double word biClrUsed;

double word biClrImportant;

} BITMAPINFOHEADER;

La double word biSize indica il numero di byte necessari per la struttura
BITMAPINFOHEADER, mentre i long int biWidth e biHeight specificano la largezza e l’altezza in pixel del bitmap; biPlanes specifica il numero di piani per il device di destinazioni, il suo valore deve essere 1.
Il membro biBitCount della struttura BITMAPINFOHEADER determina il numero di bit che definiscono ogni pixel e il massimo numero di colori nel bitmap. Questo membro può assumere uno dei seguenti valori:

1    Il bitmap è monocromatico e la color table contiene due valori. Ogni bit nell’array del bitmap rappresenta un pixel. Se il bit è spento, il pixel viene visualizzato con il colore del primo valore nella color table.
Se il bit è acceso con il secondo.
4    Il bitmap ha al massimo 16 colori. Ogni pixel nell’array del bitmap è rappresentato da un indice di 4 bit alla color table. Ad esempio se il primo byte dell’array del bitmap ha valore 1Fh, il byte rappresenta due pixel. Il primo pixel ha il colore del secondo elemento della color table, mentre il secondo ha il colore del sedicesimo elemento della color table.
8    Il bitmap ha al massimo 256 colori. Ogni pixel nell’array del bitmap è rappresentato da un indice di 1 byte alla color table. Ad esempio se il primo byte dell’array del bitmap ha valore 1Fh, rappresenta un pixel. che ha il colore del trentaduesimo elemento della color table.
24    Il bitmap è TRUE COLOR. Ogni sequenza di tre byte nell’array del bitmap rappresenta l’intensità di rosso, verde e blu rispettivamente per ogni pixel.

La versione 3.0 di Windows e le successive (anche Windows’95) supportano i formati RLE (Run Length Encoded) per la compressione dei file bitmap che usano 4 o 8 bit per pixel.
Quando il membro biCompression della struttura BITMAPINFOHEADER è settato al valore della costante BIRLE8 (cioè 1) il bitmap è compresso usando il format RLE per le immagini a 256 colori. Questo formato usa due modi: encoded e absolute. Entrambi i modi possono essere utilizzati in qualsiasi punto di un file bitmap.
Un’unità di informazione in encoded mode consiste di due byte. Il primo byte indica il numero di pixel consecutivi che devono essere disegnati usando il colore indicato dal secondo. Il primo byte della coppia viene posto a 0 per indicare una escape che può denotare la fine di una linea, la fine del bitmap o un salto. L’interpretazione dell’escape viene fatta in base al secondo byte che assume valori 00h (fine di una linea), 01h
(fine del bitmap) e 02h (salto: i due byte successivi contengono i valori che indicano l’offest orizzontale e verticale del prossimo pixel dalla posizione corrente). L’absolute mode è segnalato dal primo byte della coppia settato a 0 e dal secondo che assume un valore compreso tra 03h e
FFh. Il secondo byte rappresenta il numero di byte che seguono, ognuno dei quali contiene l’indice del colore (cioè la posizione del colore nella color table) di un singolo pixel. Vediamo ora tutto questo più chiaramente in un esempio:
dati espansi:
04 04 04
06 06 06 06 06 06
45 56 67
78 78 muovi 5 a destra e 1 giu
78 78 fine linea
1E 1E 1E 1E 1E 1E 1E 1E 1E
dati compressi:
03 04 encoded mode
05 06 encoded mode
00 03 45 56 67 00 absolute mode
02 78 encoded mode
00 02 05 01 encoded mode
02 78 encoded mode
00 00 encoded mode
09 1E encoded mode
00 01 encoded mode

Quando il membro biCompression della struttura BITMAPINFOHEADER è settato al valore della costante BIRLE4 (cioè 2) il bitmap è compresso usando il format RLE per le immagini a 16 colori Anche questo formato usa due modi: encoded e absolute. Anche nell’encoded mode a 16 colori un’unità di informazione consiste di due byte. Il secondo byte contiene gli indici di due colori, uno nel nibble alto e l’altro nel nibble basso.
Il primo pixel viene disegnato con il colore specificato dall’indice nel nibble alto, il secondo con il colore specificato dall’indice nel nibble basso, il terzo con il colore specificato dall’indice nel nibble alto e così via fino a quando non è stato disegnato il pixel indicato nel primo byte. Il primo byte della coppia viene posto a 0 per indicare una escape che pu¢ denotare la fine di una linea, la fine del bitmap o un salto.
L’interpretazione dell’escape viene fatta in base al secondo byte che assume valori tra 00h e e 02h. Questi valori hanno lo stesso significato dei loro cugini nei file bitmap a 8 bit per pixel.
Nell’absolute mode, il primo byte è zero, il secondo contiene il numero dei colori che seguono ed i byte successivi gli indici dei colori nei loro nibble alti e bassi, un colore per ogni pixel. Ora vediamo un esempio di bitmap RLE a 4 bit per pixel
dati espansi:
0 4 0
0 6 0 6 0
4 5 5 6 6 7
7 8 7 8 muovi 5 a destra e 1 giu
7 8 7 8 fine linea
1 E 1 E 1 E 1 E 1 fine del bitmap RLE
dati compressi:
03 04 encoded mode
05 06 encoded mode
00 06 45 56 67 00 absolute mode
04 78 encoded mode
00 02 05 01 encoded mode
04 78 encoded mode
00 00 encoded mode
09 1E encoded mode
00 01 encoded mode

Torniamo ai membri della struttura BITMAPINFOHEADER. biSizeImage specifica, in byte, la misura di un’immagine. Questo membro è posto a 0 se abbiamo a che fare con un bitmap in format BIRGB. I membri biXPelsPerMeter e biYPelsPerMeter specificano la risoluzione orizzontale e verticale (in pixel per metro) del device di destinazione.
Un’applicazione pu¢ usare questo valore per selezionare, da un gruppo di risorse, il bitmap che meglio risponde alle caratteristiche del device di visualizzazione corrente. biClrUsed specifica il numero di colori della color table che vengono effettivamente utilizzati nel bitmap. Se il suo valore è zero, il bitmap usa il massimo numero di colori, corrispondente al valore di biBitCount. Il membro biClrImportant specifica il numero di colori che sono considerati importanti per la visualizzazione del bitmap.
Se il valore è zero, tutti i colori sono importanti.

La color table, definita come un array di strutture RGBQUAD, contiene tanti elementi quanti sono i colori del bitmap. La struttura RGBQUAD è cos¡ definita:
typedef struct tagRGBQUAD {

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed;

BYTE rgbReserved

} RGBQUAD

La color table non è presente nei file bitmap true-color (quelli con 16 milioni di colori) perchè ogni pixel è rappresentato da un valore RGB
(Red-Green-Blue) di 24 bit nell’array di byte (l’area dei dati vera e propria). I colori dovrebbero apparire in ordine di importanza nella color table: questo aiuta i display-driver a visualizzare un bitmap su device che non possono mostrare tanti colori quanti sono presenti nel bitmap.

Andrea Poggi

Commenta