Spécification format BMP

Transcription

Spécification format BMP
LES FICHIERS BITMAP BMP
Introduction
BMP est un format de description d'images point à point développé par Microsoft dont l'effort
a porté sur l'amélioration de la gestion des images, par trop liée aux cartes graphiques de
Windows 2. De fait, BMP est devenu un format tout à fait valable, du même acabit que TIFF
ou TGA. En outre, le succès dont bénéficie Windows depuis la version 3.1 en a fait un ténor
quasi incontournable de ce domaine, d'autant qu'il permet de modéliser virtuellement tous les
types d'images point à point, compressées ou non. Même les milieux professionnels de
l'image y ont trouvé une alternative de choix, car il s'avère aisé de transcoder un fichier BMP
24 ou 32 bits en un fichier TGA, et vice et versa.
N'oublions pas non plus que BMP entre dans la catégorie des formats de fichiers reconnus par
le presse-papiers de Windows, et devient ainsi un outil de choix pour les échanges
d'informations dynamiques entre applications Windows.
L'en-tête d'un fichier BMP
L'en-tête d'un fichier BMP se décompose en deux parties, l'une regroupant les informations
concernant le fichier proprement dit, la seconde, quant à elle, synthétisant les divers
paramètres régissant le codage de l'image. Les attributs inclus dans un fichier BMP sont à
l'évidence très complets. Seuls manquent à l'appel un descriptif géométrique de l'image et un
indicateur de sens de stockage des octets (Intel ou Motorola).
Si l'on reprend les notations du kit de développement Windows, la structure C permettant
d'interpréter un en-tête BMP peut prendre la forme suivante. La redéfinition des types word
et dword est ici réalisée aux fins de lisibilité, nombre de programmeurs C sur microordinateur préférant des déclarations du type int ou long. Quoi qu'il en soit, cette
adaptation mineure ne concerne qu'un éventuel confort d'utilisation.
#define
#define
word
dword
unsigned int
unsigned long
typedef struct
{
word
bfType
dword bfSize
word
bfReserved1
word
bfReserved2
dword bfOffBits
} FILEHEADER ;
;
;
;
;
;
typedef struct
{
dword biSize
dword biWidth
dword biHeight
word
biPlanes
word
biBitCount
dword biCompression
dword biSizeImage
dword biXPelsPerMeter
dword biYPelsPerMeter
dword biClrUsed
dword biClrImportant
} INFOHEADER ;
;
;
;
;
;
;
;
;
;
;
;
typedef struct
{
FILEHEADER
INFOHEADER
} Entete_BMP ;
Fileheader ;
Infoheader ;
Dans toute la suite de ce chapitre, nous utiliserons une structure X de type Entete_BMP
déclarée selon la méthode habituelle du C :
Entete BMP X ;
Signification des champs
•
X.Fileheader.bfType : Stocke le type de fichier. En l'occurrence, une constante, BM, est définie par
Microsoft au sein du kit de développement Windows. La valeur de BM est fixée à 19 778. La présence
de cette valeur est cruciale, car les applications commencent par tester bfType afin de savoir si le
fichier est conforme BMP. Dans le cas contraire, l'importation est rejetée. La valeur un tant soit peu
cryptique de bffype autorise ainsi la reconnaissance automatique du format de fichier, sans grand risque
de confusion.
•
X.Fileheader.bfSize : Contient la taille du fichier en octet. Le fait d'utiliser un entier long induit la
possibilité de décrire des images en haute définition, quelle que soit la profondeur de couleur choisie
(de 1 à 32 bits). En outre, la connaissance directe de cette information dispense l'application de faire
appel à un service du système d'exploitation.
•
X.Fileheader.bfReservedl : Toujours à 0 pour les bitmaps.
•
X.Fileheader.bfReserved2 : Toujours à 0 pour les bitmaps.
•
X.Fileheader.bfOffBits : Contient l'index vers le début des données constituant l'image, par rapport à
la fin du Fileheader. Certes, cette information est redondante, puisqu'il est possible de la calculer en
fonction des autres valeurs présentes dans l'en-tête. Mais elle permet d'éviter toute ambiguïté à ce sujet,
notamment si un logiciel ne gérait pas correctement l'ensemble des spécifications BMP.
•
X.Infoheader.biSize : Contient la taille du bloc information (Infoheader) en octets. La raison d'être de
cet indicateur réside dans un souci de différenciation entre les formats de fichiers bitmap de Windows 3,
de OS/2 1.1 et de OS/2 2.0. La valeur à stocker dans le cas qui nous intéresse est de 40.
•
X.Infoheader.biWidth : Largeur de l'image en nombre de points. L'utilisation d'un entier long permet
d'envisager des bitmaps d'une taille virtuellement illimitée.
•
X.Infoheader.biHeight : Nombre de lignes constituant l'image bitmap.
•
X.Infoheader.biPlanes : Nombre de plans selon lesquels l'image est organisée. Les deux exemples
suivants expliquent le rôle de biPlanes.
Prenons le cas d'une image couleurs 24 bits. Chaque point est défini par trois octets désignant
l'intensité des composantes bleues, vertes et rouges. Il est raisonnablement possible d'envisager
deux moyens de stockage de ces informations :
-
-
les trois composantes sont écrites les unes à la suite des autres. Ceci revient à une
organisation en un seul plan, pixel par pixel. La méthode est généralement mise en
œuvre par des applications exploitant des cartes graphiques 24 ou 32 bits dont la
configuration mémoire adopte le même schéma. En ce cas, on n'a affaire qu'à un seul
plan, et X.Infoheader.biPlanes prend la valeur 1.
toutes les composantes bleues sont écrites, suivies par les composantes vertes et enfin
les rouges. L'image est alors décrite par une succession de trois plans de 1 octet.
X.Infoheader.biPlanes prend ici la valeur 3.
Dernière illustration du phénomène, une copie d'écran VGA 16 couleurs peut être considérée
comme la superposition de quatre plans de 1 bit: R, G, B et 1 (intensité). Une telle "hardcopy",
bien adaptée à la sauvegarde et au chargement rapides, entraînera une valeur de 4 dans
X.Infoheader.biPlanes.
CONSEIL : Une image couleurs 24 ou 32 bits est souvent décrite sous la forme d'un seul plan
de 24 ou 32 bits. La décomposition en 3 ou 4 plans peut s'avérer très efficiente si l'image est
fréquemment utilisée pour des sorties. A titre d'exemple, un programme de présentation
destinée à être éditée sous forme de diapositive sera généré plus rapidement par l'imageur, si
son fond bitmap est stocké en trois ou quatre plans. En effet, et sous réserve d'une bonne
optimisation de l'application, l'extraction de chaque composante n'exige pas la lecture de tous
les octets définissant un pixel. Pour une image haute définition, le gain ainsi obtenu peut
atteindre 30 à 40 %, en raison de la diminution du nombre des accès disques par 3 ou 4.
•
X.Infobeader.biBitCount : Nombre de bits nécessaires au codage d'un point de chaque plan. Celui-ci
dépend du type d'organisation des données images. Si seul un plan est défini (X.Infoheader.biPlanes=I),
l'en-tête d'une image couleurs 24 bits contiendra la valeur 24 dans cette rubrique. S'il existe trois plans,
la valeur devient 24/3=8.
•
X.Infoheader.biCompression : Indique si l'image est compressée. Une valeur 0 indique une image non
compressée. 1 ou 2 spécifie une méthode de compression du type RLC.
•
X.Infoheader.biSizeImage : Taille en octets des données images proprement dites. Cette information
est surtout utile en cas d'images compressées. L'application est alors capable de vérifier si le fichier
décompressé correspond bien à l'image initiale, du moins en termes de dimensions. Ce champ est inutile
pour un fichier non compressé, et peut être mis à 0. Toutefois, le renseignement de cette rubrique ne
s'apparentant pas à l'érection de la Grande Muraille de Chine, il est conseillé ne pas s'en dispenser.
•
X.Infoheader.biXPeIsPerMeter : Résolution horizontale en pixels par mètre. Cette rubrique est
facultative. Mais elle a le mérite de quantifier l'aspect de ratio de l'image si besoin est, par comparaison
avec la valeur X.Infoheader.biYPelsPerMeter. Par ailleurs, un logiciel d'application peut éventuellement
invoquer des algorithmes de traitement spéciaux en fonction de la définition précise de l'image. Une
image numérisée via un scanner 300 dpi se verra affublée de la valeur 11 811 dans cette rubrique (300
points/pouce = 11 811 points/mètre). Le renseignement de cette rubrique n'est pas obligatoire, mais il
reste conseillé, à moins d'opérer constamment avec des images dont l'aspect de ratio est connu et
constant.
•
X.Infoheader.biYPeIsPerMeter : Résolution verticale en pixels par mètre.
•
X.Infoheader.biCIrUsed : Nombre de couleurs utilisées. Si 0, toutes les couleurs sont utilisées. Ce
champ est fondamental pour une image munie d'un index de couleurs, à l'instar des images 256 couleurs
codées sur 8 bits. Il permet éventuellement de limiter le nombre d'entrées dans la table d'index de
couleurs (LUT). Aussi une image ne contenant que 35 couleurs différentes aura-t-elle cette valeur fixée
à 35, et l'on obtiendra un gain en compacité de 256-35=221 entrées de LUT. Dans le cas d'images
couleurs 24 bits, cette rubrique ne présente quasiment pas d'intérêt et doit être positionnée à 0, taille
réelle de la LUT. Le codage précis de ce champ est parfois susceptible d'optimiser le fonctionnement
d'une application qui serait à même d'importer simultanément plusieurs images couleurs 8 bits. Elle
peut ainsi facilement optimiser la palette matérielle de l'adaptateur graphique employé.
•
X.Infoheader.biCIrImportant : Nombre de couleurs importantes. Si 0, toutes les couleurs sont
importantes. Cette rubrique a été conçue afin d'assister une application pour générer des sorties sur un
périphérique dont le nombre de couleurs adressables est inférieur au nombre de couleurs présentes dans
l'image. Il n'y a pas grand risque à laisser cette valeur à 0, car les applications prennent généralement
très bien en charge ce genre de difficultés.
Le fichier image
Quoiqu'il n'y ait pas de limitation quant au nombre de bits nécessaires au codage d'un pixel,
les valeurs les plus classiques sont de 1, 4, 8, 24 et 32 bits. Les deux dernières options sont
aptes à représenter des images au rendu quasi photographique (16,7 millions de teintes).
L'ordre de rangement des octets descripteurs est important, puisque l'en-tête ne dispose
d'aucune rubrique réservée à cet effet. Aussi convient-il de se conformer scrupuleusement aux
spécifications de Microsoft. L'ordre de rangement retenu est similaire à celui du format TGA,
à savoir: BLEU, VERT, ROUGE.
Il est ainsi possible de se définir une structure C du type :
typedef struct
{
unsigned char B ;
unsigned char G ;
unsigned char R ;
} Color_24 ;
équivalente à la structure RGBTRIPLE définie dans le kit de développement Windows 3.0.
Trois autres points sont à prendre en considération, sous peine d'erreurs à l'affichage ou à la
conversion des fichiers BMP :
-
-
La taille en octets d'une ligne de balayage doit être un multiple de 4.
L'origine du bitmap est toujours le coin inférieur gauche. Il est dommage que
Microsoft n'ait pas rendu possible le paramétrage de cette information dans l'en-tête,
empêchant ainsi certaines applications d'effectuer une optimisation des traitements.
La table des index de couleur (LUT) est définie par des structures 32 bits, et non 24
bits comme il est d'usage dans les autres formats.
Remarques :
La LUT est un tableau de structure du type
typedef struct
{
unsigned
unsigned
unsigned
unsigned
} Color_32;
char
char
char
char
B;
G;
R;
O;
dont le nombre d'entrées est spécifié par la rubrique X.Infoheader.biCIrUsed. Rappelons que
si sa valeur est 0, toutes les couleurs sont utilisées. La taille de la LUT sera alors fonction de
la valeur de X.Infoheader.biBitCount :
VALEUR
1
4
8
24
TAILLE LUT
2
16
256
0
On notera le hiatus existant entre la définition des entrées de la LUT en 32 bits, et le codage
maximal 24 bits préconisé par Microsoft pour les données de l'image. En réalité, il est tout à
fait envisageable d'utiliser BMP pour le stockage 32 bits ; malheureusement, l'absence de
spécifications de la part de Microsoft risque d'induire des incompatibilités entre différentes
applications.
Compression
Si la valeur de X.Infoheader.biCompression est différente de 0, les données du fichier sont
compressées. A l'heure actuelle, Microsoft n'a défini que deux méthodes possibles qui
s'apparentent à un codage de type RLC, pour des points définis par 4 bits
(X.Infoheader.biCompression =1) et 8 bits (X.Infoheader.biCompression = 2).
Une fois encore, la cohérence du format BMP n'est pas totalement assurée car cette
compression ne s'applique pas à des images 24 bits, ou du moins avec une efficacité plus que
douteuse. Par rapport à un codage RLC simple, l'adaptation Microsoft apporte quelques
améliorations mineures, au prix il est vrai d'une interprétation plus Complexe.
Analysons les différents cas pour une compression 8 bits.
octet 1
04
00
00
00
00
2
OE
00
01
02
04
3
5
.
4
7
.
décompression
OE OE OE OE
commentaires
fin de ligne
fin de l'image
déplacement x+5, y+7
4 points non compressés
Si le premier octet est à 0, il s'agit d'une commande dont la signification est fonction de la
valeur de l'octet suivant (voir ci-dessus). Pour une valeur supérieure à 3 et inférieure ou égale
à 255 (FF en notation hexadécimale), les n valeurs suivantes représentent un paquet de
données non compressées.
Le cas 00 02, décrivant un déplacement relatif du curseur (toujours positif) par rapport à sa
position actuelle, n'est guère utile dans le cadre d'une image stockée dans un fichier disque.
En pratique, il permet d'ignorer purement et simplement une portion rectangulaire d'image,
particularité utile durant l'exploitation de Windows 3.0. Par ce biais, ce dernier économise en
effet l'espace mémoire nécessaire à la sauvegarde de portions d'images. Enfin, seules des
zones rectangulaires de 256 x 256 points maximum, et dont l'origine inférieure gauche
coïncide avec la position courante du curseur, peuvent être décrites.
L'analyse précédente porte sur le codage de type 2 concernant les images bits (256 couleurs).
Le principe général reste applicable pour le type 1, conçu afin de gérer des points de 4 bits (16
couleurs). Les compteurs associés à chaque paquet se rapportent alors à des demi-octets, et
non plus à des octets comme précédemment. Par exemple :
05 08 00 06 FE A3 23 00 02 07 03 se décompressera sous la forme
08080
5 demi-octets. Le demi-octet de poids fort est tracé en premier.
FEA323
6 demi-octets non compressés.
Déplacement du curseur de 7 pixels à droite, et de 3 pixels vers le haut.
Bien entendu, chaque valeur obtenue après décompression correspond à une entrée dans la
table d'index des couleurs (LUT).
ATTENTION :
Le format BMP a été créé en environnement PC. L'ordre de stockage des octets dans le fichier
se conforme donc aux conventions Intel, soit octet de poids faible suivi par octet de poids fort.
L'exploitation d'un fichier BMP sur une plate-forme matérielle différente, notamment
Motorola/Macintosh, doit tenir compte de ce fait. Seule la lecture des informations de l'en-tête
est concernée. Il faut alors inverser le sens des octets pour les informations de type INTEGER
(2 octets) ou plus larges.