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



Affichage du Bitmap
Comme nous ne savons pas d'où provient le bitmap et sous quelle type de résolution il à été créé alors nous devons lui assuré une parfaite compatibilité avec le contrôle fenêtré où il sera dessiner. Pour cela nous allons le dessiner sur un DC, qui sera juste créer en mémoire, mais qui sera aussi compatible avec le contrôle fenêtré où nous voulons le dessiner. Ensuite nous copierons le contenu du DC temporaire vers le DC où nous voulons dessiner le Bitmap. Voici le code associé à mon explication qui semble très abstraite...
Function DessinerSur( PlancheADessin :HDC;
                      DestLargeur,
                      DestHauteur :Integer ) :Boolean;
Var
   hBMP :HBITMAP;
   MemoireDC :HDC;

Begin
      If GetObjectType( PlancheADessin ) = 0 Then
          Exit;

      hBMP := CreateCompatibleBitmap( PlancheADessin,
                                     BmpINFO.biWidth, BmpINFO.biHeight );
      If hBMP = NULL Then
          Exit;

      MemoireDC := CreateCompatibleDC( PlancheADessin );
      If MemoireDC = NULL Then
          Exit;

      If SetDIBits( MemoireDC, hBMP, 0, BmpINFO.biHeight,
                   pTabPixels, pBmpINFO^, DIB_RGB_COLORS ) <= 0 Then
         Exit;

      SelectObject( MemoireDC , hBMP );

      If StretchBlt( PlancheADessin,
                     0, 0, DestLargeur, DestHauteur,
                     MemoireDC,
                     0, 0, BmpINFO.biWidth, BmpINFO.biHeight,
                     SRCCOPY ) <> False Then
         Result := True ;

      DeleteObject( hBMP );
      DeleteDC( MemoireDC );

     End;
End;

hBMP :HBITMAP;
Handle sur un Bitmap. Genre de pointeur sur un Bitmap.
MemoireDC :HDC;
Contexte Graphique(DC). C'est par l'entremise de cette variable que nous allons créer un DC en mémoire seulement.
If GetObjectType( PlancheADessin )...;
Vérification du type de contexte graphique(DC) passé en paramètre.
hBMP := CreateCompatibleBitmap( PlancheADessin, BitMapTemp.Width, BitMapTemp.Height );
Création d'un Bitmap compatible avec le DC où nous voulons l'afficher. Supposons que nous voudrions dessiner notre Bitmap sur un DC qui ne supporte que deux couleur (Monocrome) alors le Bitmap compatible serait créer de manière à ce qu'il suporte le mode monocrome. Pas trop compliqué n'est-ce pas ?
MemoireDC := CreateCompatibleDC( PlancheADessin );
Création d'un DC compatible aussi avec notre DC où nous voulons dessiner notre Bitmap.
SetDIBits( MemoireDC, hBMP, ..., DIB_RGB_COLORS );
Cette fonction dessine le contenu d'un tableau de pixel sur un DC. Voici la description de cette fonction :

SetDIBits( hdc                    :HDC;         // DC de destination 
           hbmp                   :HBITMAP;     // Handle du Bitmap
           uStartScan,                          // Première ligne à lire dans le tableau de Pixels 
           cScanLines             :Cardinal;    // Dernière ligne à lire dans le tableau de Pixels 
           lpvBits                :Pointer;     // Pointer sur le tableau de pixels 
           Const lpbmi            :BITMAPINFO;  // Pointeur sur la Structure d'info TBitMapInfo 
           fuColorUse             :Cardinal     // Type de gestion de pixel RGB ou Indexé 
) :Integer;  
										 
SelectObject( MemoireDC , hBMP );
Liasons des deux objet créés. Donc on selectionne le Bitmap(hBMP) dans le DC en mémoire.
StretchBlt( PlancheADessin,...
Cette fonction sert à dessiner un Bitmap sur un DC passé en paramètre. Si le Bitmap à dessiner est plus large que sa destination alors cette fonction le rétréssira en revanche s'il est trop petit cette fonction l'agrandira. Description de cette fonction :
StretchBlt( hdcDest      :HDC;       // DC de destination
            nXOriginDest :Integer;   // Coordonnée X Haut-Gauche de destination
            nYOriginDest :Integer;   // Coordonnée Y Haut-Gauche de destination
            nWidthDest   :Integer;   // Largeur de la destination
            nHeighDest   :Integer;   // Hauteur de la destination
            hdcSrc       :HDC;       // DC de la source
            nXOriginSrc  :Integer;   // Coordonnée X Haut-Gauche de l'origine 
            nYOriginSrc  :Integer;   // Coordonnée Y Haut-Gauche de l'origine
            nWidthSrc    :Integer;   // Largeur de l'origine
            nHeightSrc   :Integer;   // Hauteur de l'origine
            dwRop        :DWORD;     // Type de traitement
): Boolean;			
DeleteObject( hBMP );
Très important quand nous avons fini d'utiliser un objet il faut libérer la mémoire prise par celui-ci.
DeleteDC( MemoireDC );
Encore plus important quand on à plus besion d'un DC il faut absolument le détruire si on ne veut pas avoir de surprises avec Windows.

Manipulation des pixels d'un Bitmap en mémoire
La manipulation des pixels en mémoire est n'est pas extremmement difficile mais il y a tout de fois quelque chose qui la rend difficile et c'est le résultat que l'on désire avoir. Vu que la manipulation se fait en mémoire alors je n'ai pas besion de vous dire que celle-ci se fera par l'entremise de pointer sur des Octets, DWord, TRGBTriple ou TRGBQuad et tout cela dépendemment du nombre de bits/Pixel du Bitmap. Le manière d'accéder au tableau de pixel en mémoire se fera à l'aide de transtypage et de déplacements d'octets en octets ou autres selon le cas(bpp). Voici un bout de code qui vous donnera sûrement d'autres idées :
Procedure InverserCouleur;
Var
   LongeurDuneLigne :Integer;    {Longeur d'une ligne de pixel en octets}
   Parcours         :Integer;    {Ligne parcourue (Partant du bas du bitmap)}
   X                :Integer;    {Parcourir chaque octet d'une ligne de pixels}

   PointeurTemp     :Pointer;    {Pointeur temporaire sur les pixels du Bitmap}
   CouleurIndex     :Integer;    {Incrémenteur pour parcourir la palette}
begin
     Case BmpINFO.biBitCount Of

     1, 4, 8 :
         Begin
              For CouleurIndex := 0 To PalNbCouleurs - 1 Do
              Begin
                   PointeurTemp := Pointer( Integer(PtrDebutPal) + CouleurIndex * SizeOf(TRGBQuad));
                   TRGBQuad(PointeurTemp^).rgbRed    := Not TRGBQuad(PointeurTemp^).rgbRed;
                   TRGBQuad(PointeurTemp^).rgbGreen  := Not TRGBQuad(PointeurTemp^).rgbGreen;
                   TRGBQuad(PointeurTemp^).rgbBlue   := Not TRGBQuad(PointeurTemp^).rgbBlue;
              End;
         End;


		 
          16 :
         Begin
              LongeurDuneLigne := ((( BmpINFO.biWidth * BmpINFO.biBitCount ) + 31) And -31) Shr 3;
              Parcours     := 0;

              While Parcours < LongeurDuneLigne * (BmpINFO.biHeight - 1) Do
              Begin
                   For X := 0 To LongeurDuneLigne - 1 Do
                   Begin
                        PointeurTemp := Pointer(Integer(pTabPixels) + Parcours + X );
                        Byte( PointeurTemp^ ) := Not Byte( PointeurTemp^ );
                   End;
                   Inc(Parcours, LongeurDuneLigne );
              End;
         End;


		 
          24 :
         Begin
              For X := 0 To (BmpINFO.biHeight * BmpINFO.biWidth) Do
              Begin
                   PointeurTemp := Pointer( Integer(pTabPixels) + X * SizeOf(TRGBTriple) );

                   TRGBTriple( PointeurTemp^ ).rgbtBlue  := Not TRGBTriple( PointeurTemp^ ).rgbtBlue;
                   TRGBTriple( PointeurTemp^ ).rgbtGreen := Not TRGBTriple( PointeurTemp^ ).rgbtGreen;
                   TRGBTriple( PointeurTemp^ ).rgbtRed   := Not TRGBTriple( PointeurTemp^ ).rgbtRed;
              End;
         End;

		 
          32 :
         Begin
              For X := 0 To (BmpINFO.biHeight * BmpINFO.biWidth) Do
              Begin
                   PointeurTemp := Pointer( Integer(pTabPixels) + X * SizeOf(TRGBQuad));

                   TRGBQuad( PointeurTemp^ ).rgbBlue  := Not TRGBQuad( PointeurTemp^ ).rgbBlue;
                   TRGBQuad( PointeurTemp^ ).rgbGreen := Not TRGBQuad( PointeurTemp^ ).rgbGreen;
                   TRGBQuad( PointeurTemp^ ).rgbRed   := Not TRGBQuad( PointeurTemp^ ).rgbRed;
              End;
         End;

     End;
end;
Alors pour le cas des bitmap possèdant un Table de couleur(Palette), nous ne pouvons pas inverser la couleur du pixel directement mais les couleur de sa Palette. Et pour les autre bitmap n'ayant pas de Palette de couleur on peut se permettre de spécifier la couleur contraire pour chaque pixels. Remarquer le travail splandide du transtypage de valeur, quand nous avons besion que de récupérer un Byte alors on le précise devant le pointer :BYTE( Adresse... ).

Une autre chose, il est très important de calculer le nombre d'octet par ligne pour un Bitmap moins de 8bpp.

Prenons par exemple un bitmap 4 bits par pixel qui aurait 15 pixel en largeur. Quand nous récupèrerions une ligne, il faudrait récupérer 8octets. Pourtant 7 octets + 4 bits aurait suffit ? Mais comme on ne peut pas vraiment récupérer 7 octets + 4 bits alors il faut TOUT récupérer. Ensuite il sera important de ne pas prendre le dernier 4 bits du 8ième octets comme étant une couleur car il ne sert à rien. Pour une ceux qui sont visuel :-), une ligne du bitmap est représentée dans l'image ci-dessus et le carré qui contient un signe d'intérogation représente le dernier 4 bits du dernier octets.

Petit trucs :
Byte  
Utile pour travailler sur des bitmap ayant 1, 4, 8 bpp.
Dword  
Gérer des bitmaps ayant 16bpp, parce qu'un pixel à besion de deux octets alors on récupère deux octets DWORD = 2 octets.
TRGBTRIPLE
Utile sur les 24bpp, 3 octets pour 1 pixels.
TRGBQUAD
Utile sur les 32bpp, 4 octets pour 1 pixels et dont un qui sert complètement à rien.


Le cadeaux :
Voici un petit programme démonstrateur qui à pour but de démontrer l'utilisation des Bitmaps. Par la même occasion j'ai conçu une class TFichierBitmap qui contient tout le nécessaire pour débuter avec les Bitmaps. Bien sur je n'ai pas le temps de vous l'expliquer en tutoriel mais elle est fortement commentée. Et surtout s'il y a des questions, ne vous gênez pas...

  • Chargement d'un bitmap.
  • Afficher la palette du bitmap.
  • Renverser l'image (Horizontal ou vertical).
  • Ajustement des couleurs Rouge, Vert et bleu selon un pourcentage.
  • Griser une image (GrayScale).
  • Inverser toutes les couleurs d'un bitmap.
  • Récupérer les informations en rapport avec le Bitmap.
  • Possibilité de charger ou enregistrer la palette du Bitmap.
  • Conversion
    1bpp à 24bpp
    4bpp à 24bpp
    8bpp à 24bpp
    16bpp à 24bpp
    32pp à 24bpp

    1bpp à 32bpp avec valeur Alpha
    4bpp à 32bpp avec valeur Alpha
    8bpp à 32bpp avec valeur Alpha
    16bpp à 32bpp avec valeur Alpha
    24pp à 32bpp avec valeur Alpha
  • Eregistrement sous le format courant.
Programme relié
Le code source de ma CLASS TBitmapFichier vous ai totalement livré gratuitement. Mais ce que vous y trouverai n'est pas tout expliqué dans ce tutoriel. Si vous avez suivi le tutoriel jusqu'ici vous devriez être en mesure d'utiliser cette Class très facilement.
  Source = > Programme démo + Source de la class TFichierBitmap
  source = > Seulement la class TFichierBitmap