IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)


Format du fichier Bitmap :
Maintenant parlons un peu plus en détail des différentes structures qui nous permettrons de stocker le Bitmap lui-même. Chaque structure possède une forme et elle est responsable de récupérer certaines informations relatives au Bitmap mais pour cela il est nécessaire de poursuivre un Ordre précis pour la récupération des données. Tout d'abord nous parlerons seulement des structures qui seront utilisées dans ce tutoriel. La première :
TBITMAPFILEHEADER = Packed Record 
    bfType      :Word; 
    bfSize      :DWORD; 
    bfReserved1 :Word; 
    bfReserved2 :Word; 
    bfOffBits   :DWORD; 
End; 
TBITMAPFILEHEADER
bfType
Spécifie le type de Bitmap, sa Signature. cette valeur doit contenir 'BM' ou sous format DWord ($424D).
Ce qui équivaut aussi à Chr( $42 ) + Chr($4D );
bfSize
Grosseur total du fichier.
bfReserved1
Réservé.
bfReserved2
Réservé
bfOffBits
Spécifie en Octet(Byte) la distance dans le fichier entre cette structure et le commencement des pixels, donc ceux qui forme l'image contenu dans le Bitmap.


Voici trois autres structures qui nous serons utile, Trois car elles se rappel une à une.
TBITMAPINFO = Packed Record
    bmiHeader :TBitmapInfoHeader;
    bmiColors :Array[0..0] of TRGBQuad;
End;

TRGBQUAD = Packed Record
    rgbBlue     : Byte;
    rgbGreen    : Byte;
    rgbRed      : Byte;
    rgbReserved : Byte;
End;

TBITMAPINFOHEADER = Packed Record
    biSize          : DWORD;
    biWidth         : Longint;
    biHeight        : Longint;
    biPlanes        : Word;
    biBitCount      : Word;
    biCompression   : DWORD;
    biSizeImage     : DWORD;
    biXPelsPerMeter : Longint;
    biYPelsPerMeter : Longint;
    biClrUsed       : DWORD;
    biClrImportant  : DWORD;
End;
TBITMAPINFO
bmiHeader
Ce membre pointe vers la structure :TBITMAPINFOHEADER
bmiColors
Ce membre est un tableau vide représentant la palette de couleur du Bitmap. La Palette contient biClrUsed couleurs. Si l'on veut la parcourir alors il faut se servir de la structure TRGBQuad pour stocker chacune des couleurs (Quad = 4 Octets).


TBITMAPINFOHEADER
biSize
Spécifie la dimension de cette structure en Octet.
biWidth
Largeur de l'image.
biHeight
Hauteur de l'image.
biPlanes
Nombre de plans doit être '0001'.
biBitCount
Nombre de Bits par Pixel.
biCompression
Compression s'il en existe une. Si cette valeur est BI_RGB, c'est que le Bitmap n'est pas compressé. BI_RLE8 signifie qu'il est compressé (RLE) 8 bits par pixel et BI_RLE4 qu'il est compressé (RLE) 4 bits par pixel.
biSizeImage
Spécifie la taille de l'image en octet. Pour bien récupérer cette valeur le bitmap ne doit pas être compressé donc biCompression <> BI_RGB.
biXPelsPerMeter
Résolution Horizontale en pixels par mètre
biYPelsPerMeter
Résolution Verticale en pixels par mètre
biClrUsed
Spécifie le nombre de couleur dans la table qui sont présentement utilisées par le Bitmap. Ce cette valeur est égale à 0, c'est que le Bitmap utilise le maximum des couleurs présentes dans sa table.
biClrImportant
Spécifie le nombre de couleur requise pour afficher le bitmap.


Je ne l'ai pas mentionné encore mais pour ceux qui ne serais pas au courant, Packet Record n'est pas tout à fait pareil à Record. Cela indique au compilateur qu'il doit compresser le stockage des données au format de la structure, même au prix d'un ralentissement de l'accès à un composant d'une variable de ce type.

Bon et maintenant je vous affiche un petit dessin très explicatif du format d'un fichier Bitmap. L'auteur est Microsoft, on le devine bien bien que ce n'est pas moi parce que ça dépasse pas de chaque côté.. :-)
Récupération des informations à l'intérieur du BitMap :
Premièrement je vous présente un petit bout de code qui m'aidera très bien à vous expliquer :
Procedure RecupererInfo( Chemin :String;
                         Var FileSize, Largeur, Hauteur, BitsPerPixel,
                         NbCouleur :Integer );
Const
     FICHEADER  = SizeOf( TBITMAPFILEHEADER );
     BITMAPINFO = SizeOf( TBITMAPINFOHEADER );
	
Var
   FichierTemp :File;
   InfoFichier :TBITMAPFILEHEADER;
   InfoImage   :TBITMAPINFOHEADER;
   
Begin
     AssignFile( FichierTemp, Chemin );
     Reset( FichierTemp, 1 );

     BlockRead( FichierTemp, InfoFichier, FICHEADER );
     BlockRead( FichierTemp, InfoImage,   BITMAPINFO );

     CloseFile( FichierTemp );

     FileSize    := InfoFichier.bfSize;
     Largeur     := InfoImage.biWidth;
     Hauteur     := InfoImage.biHeight;
     BitsPerPixel:= InfoImage.biBitCount;
     NbCouleur   := InfoImage.biClrUsed;
End;
Les deux constantes en haut contiennent la grosseur en Octet des deux structures principales d'un Bitmap.
Si vous connaissez un peut le fonctionnement de la lecture d'un fichier alors vous comprendrez vite que l'on ouvre le fichier et on positionne le curseur au début. Ensuite on récupère les informations dans la première structure et ensuite la deuxième. C'est ici que le mot réservé Packed Record est important, car on compresse les informations lues dans le format que la structure demande...
Par la suite on ferme le fichier et il nous restes plus qu'a renvoyer les informations récupérées par l'entremise des paramètres de la procédure.


Voici une autre manière plus complex de récupérer chaque informations relatives au Bitmap :
Procedure LireBitmap( Chemin :String );
Var
   BmpFichier     :File;              {Fichier Bitmap}
   BmpINFOFichier :TBITMAPFILEHEADER; {Structure #1}
   BmpINFO        :TBITMAPINFOHEADER; {Structure #2}

   GrosseurPal    :Cardinal;          {Grosseur de la palette}
   PtrDebutPal    :Pointer;           {Pointeur sur le début de la palette}

   DimBitmapInfo  :Cardinal;          {Grosseur de la structure TBITMAPINFO}
   pBmpINFO       :PBITMAPINFO;       {Pointeur sur une structure TBITMAPINFO}

   pTabPixels     :PByte;             {Pointeur sur une région de pixels en mémoire}

Begin
     {Vérification de l'existance du fichier}
     If Not FileExists( Chemin ) Then
        Exit;
        

     {Ouverture du fichier}
     AssignFile( BmpFichier, Chemin );
     Reset( BmpFichier, 1);


     {Lecture de l'entête TBITMAPFILEHEADER.
      Vérifier si c'est bien un bitmap "BM".}
     BlockRead( BmpFichier, BmpINFOFichier, SizeOf(BmpINFOFichier) );
     If BmpINFOFichier.bfType <> ( Ord('M') Shl 8 + Ord('B') ) Then
        Exit;

		
     {Lecture de l'entête TBITMAPINFO.
     Vérifier si la dimension/version de l'entête est correct.}
     BlockRead( BmpFichier, BmpINFO, SizeOf(BmpINFO) );
     If BmpINFO.biSize <> SizeOf(BmpINFO) Then
        Exit;

		
     {Déterminer le nombre de couleur dans la palette}
     If BmpINFO.biClrUsed = 0 Then
        PalNbCouleurs := 1 Shl BmpINFO.biBitCount
     Else
         PalNbCouleurs := BmpINFO.biClrUsed;

		 
     {Déterminer la grosseur de la palette}
     If BmpINFO.biBitCount < 16 Then
          GrosseurPal := PalNbCouleurs * SizeOf( TRGBQUAD )
     Else
         GrosseurPal := 256 * SizeOf( TRGBQUAD );

         
     {Déterminer la dimension de la table de couleur ainsi 
      que la structure BITMAPINFOHEADER pour enfin connaître 
      la vraie dimension de la structure
	  
          TBITMAPINFO + La table de couleur (TRGBQUAD)
     }
      DimBitmapInfo := Sizeof( TBITMAPINFOHEADER ) + GrosseurPal;

	  
     {Déterminer où débute le tableau de pixel dans le fichier bitmap.
      On aurait pu aussi utiliser cette ligne qui calcul l'"offset" déplacement
      entre la structure TBITMAPINFO et la fin du fichier, dont ce qui nous
      donnes les donnés pixel. Ne pas oublier que TBITMAPINFO contient aussi
      un tableau de couleur pour la palette (Si existante)

         DimTableauPixel := BmpINFOFichier.bfSize - BmpINFOFichier.bfOffBits;
     }
      DimTableauPixels := BmpINFO.biHeight * 
              ((((BmpINFO.biWidth * BmpINFO.biBitCount ) + 31) And -31) Shr 3);


     {Allocation de mémoire pour récupérer la structure : "TBITMAPINFO"
          BITMAPINFOHEADER + Table de couleur (TRGBQUAD)}
      GetMem( pBmpINFO, DimBitmapInfo );

	  
     {Copier la structure BITMAPINFOHEADER à l'intérieur de TBITMAPINFO}
      CopyMemory( pBmpINFO, @BmpInfo, SizeOf(TBITMAPINFOHEADER) );

	  
     {Ajouter la palette(TRGBQUAD) à la structure TBITMAPINFO et
	     par la même occasion récupérer un pointeur sur la palette}
      PtrDebutPal := Pointer( Cardinal(pBmpINFO) + SizeOf(TBITMAPINFOHEADER) );
      BlockRead( BmpFichier, TBITMAPINFO( PtrDebutPal^ ), GrosseurPal );

	  
     {Allouer de la mémoire pour récupérer les pixels du Bitmap}
      GetMem( pTabPixels, DimTableauPixels );

	  
     {Positionner le curseur de lecture du fichier, sur le début du
      tableau de pixels}
      Seek( BmpFichier, BmpINFOFichier.bfOffBits );


     {Récupérer le tableau de pixels en mémoire}
      BlockRead( BmpFichier, pTabPixels^, DimTableauPixels );

	  
     {Fermeture du fichier}
      CloseFile( BmpFichier );
End;
Ouff! Ça fait pas mal de code tout ça...
J'utilise les pointeurs et la mémoire directement que pour des raisons de rapidité. L'utilisation de variables statiques telque des tableaux Ex :MaPalette = Array[0..256] Of TRGBQuad, ralenti de beaucoup le l'accès aux pixels ou la palette. Pour des traitements rapide et efficaces il n'y a pas mieux que les pointeurs et la mémoire allouée dynamiquement !

Si vous êtes à l'aise avec les pointeurs et la lecture des fichiers alors je ne crois pas que vous ayez des problèmes mais pour ceux qui ont de la difficulté alors dites le moi et je verrai ce que je peux faire pou vous aider, peut-être un tutoriel sur le sujet :-)