Formatul grafic BMP

Ioan Iacob

În ultimii ani formatul BMP a devenit un standard important ca urmare a faptului că este utilizat atât sub OS/2 cât si sub Windows. Pentru multi dintre noi, acest format este destul de străin având în vedere că îl cunoastem mai mult după nume si nu neapărat după structură. De fapt după cum e lesne de înteles, ne găsim în fata unui adevărat folclor - există o serie de specificatii de formate grafice care utilizează acelasi nume. Sub sistemul de operare OS/2 ca dealtfel si sub Windows, fisierele de format BMP se folosesc pentru a stoca imagini, icon-uri, cursoare, pointeri si poate lista nu este completă. În continuare ne vom focaliza atentia asupra formatului BMP pentru imagine.

Există două versiuni ale formatului BMP sub Windows si două sub OS/2. Putem să le considerăm ca fiind de fapt versiunea veche si versiunea nouă pentru fiecare din cele două platforme. Cele două versiuni vechi sunt identice, lucru explicabil ca urmare a originii comune a lui OS/2 si Windows. Versiunile asa-zise noi ale formatului BMP sunt diferite. Aceasta înseamnă că o aplicatie care vrea să lucreze în cazul oricărei instante valide de BMP trebuie să ia în considerare trei variante diferite de format.

Din punct de vedere al programatorului, programul trebuie să fie pregătit să interpreteze corect oricare din cele trei versiuni de format BMP iar logica handler-ului de erori trebuie să se ocupe de cel putin trei situatii distincte: un fisier imagine BMP valid, un fisier BMP valid dar care contine altceva decât o imagine, un fisier invalid de format nestiut. În acest articol voi încerca să examinez formatul imagine BMP si să prezint câteva informatii legate de modul de codificare si decodificare a datelor.

Structura BMP

Formatul BMP este de uzantă generală astfel încât permite stocarea, într-un fisier pe disc, a unei imagini de orice dimensiune. Informatiile despre culoare pot să varieze de la 1 bit la 24 de biti. De asemena este suportată codificarea RLE (run length encoding) sub Windows sau comprimarea folosind algoritmul Huffman sub OS/2. Până acum nu am întâlnit nici un fisier având extensia BMP care să folosească una din aceste tehnici de compresie. În ceea ce priveste modul de stocare, imaginea este înregistrată linie cu linie pornind de jos în sus. Acest lucru nu prezintă nici o problemă atunci când este necesară afisarea imaginii pe monitor folosind API-ul Windows sau OS/2 (Presentation Manager). Problema reală apare în cazul în care trebuie să ne preocupăm direct de datele stocate în fisier, respectiv atunci când trebuie să facem conversia de format sau trebuie să listăm imaginea respectivă la imprimantă.

În fiecare din cele trei variante specificate, un fisier BMP contine, respectând ordinea aparitiei, următoarele părti (am dat denumirile în engleză preluate din Microsoft Windows Programmer's Reference pentru a nu exista dubii în interpretarea lor): file header, bitmap info header, optional paleta de culori si în final datele imaginii. Variantele formatului BMP apar distincte în domeniile bitmap info header si în cel al paletei de culori.

Sub Windows 3.1, formatul vechi rezervă pentru paletă 3 octeti x număr culori de unde si denumirea sectiunii fisierului - RGBTRIPLE. În noua versiune avem 4 octeti rezervati pentru o culoare - RGBQUAD. Ambele versiuni, sub platforma Windows, includ structurile BITMAPFILEHEADER, BITMAPINFOHEADER, descrise în continuare.

Intrările în tabela ce reprezintă paleta de culori, în cazul versiunii vechi, sunt constituite din trei octeti care indică componentele de rosu, verde si albastru. În cadrul versiunilor noi ale formatului BMP se adaugă un al patrulea octet si ca urmare, o intrare în cadrul paletei de culori se poate citi ca si un longinteger. În cazul în care ne referim la liniile ce reprezintă imaginea, pe lângă faptul că ele sunt înregistrate începând cu linia de jos, există un al doilea aspect care priveste faptul că aceste linii sunt umplute cu octeti pozitionati pe zero astfel încât să ocupe un număr par de cuvinte duble. Dându-se o imagine de lătime w (în pixeli) si de adâncime d, numărul octetilor de pe o linie este calculat folosind formula octeti/rând = ((w*d+31)/32)*4.

Componentele structurii BMP

În general vorbind, câmpurile nefolosite sau care nu sunt importante pot fi setate pe zero în toate situatiile. În cadrul enumerării următoare am respectat denumirile câmpurilor asa cum apar ele în documentatia originală. În primul rând voi prezenta câmpurile structurii pe care am denumit-o BITMAPFILEHEADER:

În cazul în care imaginile utilizează 4 sau 8 octeti pe pixel trebuie să avem o paletă de culori. Numărul valid de culori cuprinse în această paletă variază după cum urmează: 16 si respectiv 256 dar până la urmă ele pot fi mai mici dacă imaginea nu face uz de toate culorile posibile. În cazul în care se folosesc 24 de biti pe pixel avem de-a face cu o imagine full-color care nu mai necesită o paletă de culori.

Practic pentru a integra în acest articol si o lămurire privitoare la formatul grafic PCX (în cazul acelora ce doresc să scrie scurte programe) am procedat la prezentarea în continuare a cazului în care avem totusi de-a face cu o comprimare RLE. În fond, peste tot în manualele originale sau în alte cărti în care se dau informatii despre structura formatelor grafice dar nu se prezintă algoritmul folosit în scopul decodificării datelor stocate. Pentru ca să pot lucra mai usor mi-am creeat un fisier text (care poate fi completat cu un editor de texte) ce mimează informatiile cuprinse într-un fisier BMP necomprimat. Ca urmare si secventele de program vor trata fisierul de intrare ca fiind fisier text. Am ignorat toate informatiile descrise ca făcând parte din headere pentru că am considerat mai dificilă problema comprimării si nu neapărat citirea informatiilor amintite. De asemenea am mai recurs la o simplificare considerând că fisierul foloseste 8 biti pe pixel.

Compresia bitmap

Pixelii dintr-o imagine de tip bitmap sunt comprimati folosind o combinatie a trei moduri de lucru. În modul RLE (run length encoded) „unitatea de compresie" este de 2 octeti si reprezintă de la 1 la 255 de pixeli, toti de aceeasi culoare. În secventa 04 07, de exemplu, am spus că urmează patru pixeli având culoarea 07. În modul escape, primul octet este 0 iar următorii octeti semnifică una dintre următoarele trei posibilităti: 0 reprezintă sfârsitul unei linii de imagine, 1 reprezintă sfârsitul fisierului bitmap, 2 indică o comandă delta. O comandă delta mai este urmată de încă doi octeti care reprezintă deplasarea pe orizontală si pe verticală privind locul unde va apare următorul pixel, în raport cu pixelul curent. De exemplu, o comandă delta arată cam asa: 00 02 05 08. Interpretarea ei este că următorul pixel va fi afisat cu 8 pozitii mai jos si cu 5 pozitii spre dreapta fată de pozitia curentă. Cea de-a treia modalitate este referită prin absolute mode. Prin acest mod primul octet are valoarea zero iar următorul octet are o valoare de 3 sau mai mare reprezentând numărul de pixeli necomprimati care urmează. Un exemplu de folosire a modului absolut este 00 03 09 08 06 care interpretat în mod adecvat ne spune că urmează trei pixeli având valorile 09, 08 si 06. După cum se poate observa, în modul de lucru numit absolut trebuie să avem cel putin trei pixeli de valori diferite altfel (dacă avem doi pixeli de valori diferite) trebuie să folosim modul de lucru RLE. Considerând că valorile a doi pixeli adiacenti sunt 09 si 07 va trebui să scriem în fisierul de iesire secventa 01 09 01 07 (ceea ce înseamnă o valoare 09 si apoi o valoare 07). Din această descriere rezultă că fisierele ce urmează a fi comprimate si nu au secvente repetitive vor ajunge să crească în mărime.

Ca ultimă informatie voi mai spune că un fisier ce contine informatii despre un icon, sub Windows, se poate recunoaste prin faptul că are o lungime de 32 de biti, foloseste patru biti pe pixel si descrie un bloc de 32 x 32 pixeli.


(C) Copyright Computer Press Agora