AlphaBlend , TransparentColor & Co [Résolu]

Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 18:03 - Dernière réponse : Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention
- 30 janv. 2009 à 23:15
Bonjour , encore moi ;)

Voila, j'ai encore un problème :
Cirec m'a fait Découvert il y a quelque temps TransparentBlt
(http://www.delphifr.com/forum/sujet-COPYRECT_1257817.aspx)
qui me convenait extrêmement bien à l'époque...

Mais j'avais une envie : définir le niveau d'opacité d'un TBitmap ...

chose réussi grâce a AlphaBlend
(http://msdn.microsoft.com/en-us/library/aa452850.aspx)

Mais cette fonction à 1 petit problème :
Les Bitmaps 32 bits
(les vrais , genre png->bitmap 32 bits)
 fonctionnent très bien : Couleur de transparence et opacité OK

Le problème arrive quand on charge 1 Bitmap <>32 bits ...

Je vous montre ma facon de procéder pr charger le Bitmap  :
NB : fBlend fait référence à une strucrure BLENDFUNCTION
(http://msdn.microsoft.com/en-us/librar/aa452889.aspx)

procedure SetBitmap ( ABitmap : TBitmap ) ;
begin
  // si ce n'est pas un bitmap 32 bits, il le devient
  // sinon on le charge en tant que 32bits

  if ABitmap.PixelFormat<>pf32bit then
    ABitmap.PixelFormat := pf32bit
  else
    fBlend.AlphaFormat:=AC_SRC_ALPHA;

   fBitmap.Assign(ABitmap);
end;

-> le truc mauvais qui se passe quand on charge un Bitmap  24 bits ,
il est " transfo en 32 bit " donc AlphaBlend OK
(bien que ca marcherais quand meme vu que
fBlend.AlphaFormat: =AC_SRC_ALPHA n'est activé que si le Bitmap est déjà en 32 bits
Je suppose dans ce cas que c'est un " vrai " Bitmap 32 bits ... et fonctionne qd même vu que PixelFormat = pf32Bit, c'est juste que ca fait n'importe quoi ! Voir remark msdn BlendFunction  )

Bon ca Ok : la fonction AlphaBlend me change bien l'opacité de mon Bitmap
grace a

procedure SetOpaque(AOpaque : byte);
begin
  fBlend.SourceConstantAlpha:=AOpaque;
end;

Mais il ne prend plus en compte ma couleur de transparence, donc j'ai bien une image à opacité variable mais je reste avec ma couleur de transparence !

Que dois je faire ?
J'ai cherché mais ... voila je me retrouve ici !

J'ai bien une idée me je ne sais pas du tout ce qu'elle vaut :

Au moment de charger mon bitmap je fais 1 truc du genre

procedure SetBitmap ( ABitmap : TBitmap ) ;

begin

  // si ce n'est pas un bitmap 32 bits, il le devient et le Alpha

  // sinon on le charge en tant que 32bits


  if ABitmap.PixelFormat<>pf32bit then begin
     CheckTransparentColor ;

    ABitmap.PixelFormat : = pf32bit;


   end else

    fBlend.AlphaFormat:=AC_SRC_ALPHA;


   fBitmap.Assign(ABitmap);

end;

CheckTransparentColor
dans Cette procedure , je teste la valeur de tous les pixels et a chaque fois que la valeur d'un pixel
est egale à TransparentColor , je mets 0 au byte Alpha , comme ca , ce n'est pas affiché et j'ai ma " transparence " ...

Y'a t-il une autre solution ?

Merci

Avec 1 bitmap 32 bits , il n'y a pas de problème ...

PS : la source de Bacterius parle de Alpha mais je n'ai pas réussi à la telecharger , donc si la reponse est dedans déso !

PS2 : déso si double topic, mais ça ne semble pas être passé la premier fois , j'ai recharger la page mais rien n'y fait ...
      
Afficher la suite 

12 réponses

Répondre au sujet
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 30 janv. 2009 à 20:32
+3
Utile
et fBitmap c'est quoi ?

l'appel à AlphaBlend est ou ?

avant de pouvoir utiliser le canal alpha correctement il faut préparer les pixels en les pré-multipliant :

procedure PreMultiply(aBmp: TBitmap);
var PData       : PRGBQuad;
  I, BytesTotal : Integer;
begin
  BytesTotal := aBMP.Width * aBMP.Height;
  If aBmp.PixelFormat = pf32Bit then
  begin
    PData := aBMP.ScanLine[aBMP.Height-1];
    for I := 0 to BytesTotal - 1 do
    begin
      with PData^ do
      begin
      // préparation des pixels avant l'appel a AlphaBlend
      // http://msdn.microsoft.com/en-us/library/ms532306(VS.85).aspx
        RGBRed := (RGBRed * rgbReserved) div 255;
        RGBGreen := (RGBGreen * rgbReserved) div 255;
        RGBBlue := (RGBBlue * rgbReserved) div 255;
      end;
      Inc(PData);
    end;
  end;
end;

 
@+
Cirec

<hr siz="" />
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Cirec
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 20:54
+3
Utile
fBitmap est le Bitmap que je Dessine est en appelant AlphaBlend

Mon code est trop gros que pour être mis ici ...

AlphaBlend est appeler dans une methode Draw

Et comme d'Hab  Merci Cirec , Ca marche nickel :)
j'appelle ta fonction comme ca :

procedure PreMultiply(aBmp: TBitmap);
var PData       : PRGBQuad;
  I, BytesTotal : Integer;
begin
  BytesTotal := aBMP.Width * aBMP.Height;
  If aBmp.PixelFormat = pf32Bit then
  begin
    PData := aBMP.ScanLine[aBMP.Height-1];
    for I := 0 to BytesTotal - 1 do
    begin
      with PData^ do
      begin
      // préparation des pixels avant l'appel a AlphaBlend
      // http://msdn.microsoft.com/en-us/library/ms532306(VS.85).aspx
        RGBRed := (RGBRed * rgbReserved) div 255;
        RGBGreen := (RGBGreen * rgbReserved) div 255;
        RGBBlue := (RGBBlue * rgbReserved) div 255;
      end;
      Inc(PData);
    end;
  end;
end;

procedure SetBitmap(ABitmap : TBitmap);
var
  pPix : pRGBQuad;
  x : integer;
begin

  fBlend.AlphaFormat:=AC_SRC_ALPHA;

  if ABitmap.PixelFormat<>pf32bit then begin
    ABitmap.PixelFormat := pf32bit;

    pPix := ABitmap.ScanLine[ABitmap.Height - 1];
    for x:=0 to ABitmap.Width * ABitmap.Height - 1 do begin
      // si c'est la TransparentColor , alors Alpha = 0
      // sinon Alpha = 255 ...
      if RGB(pPix^.rgbRed,pPix^.rgbGreen,pPix^.rgbBlue) = DEFAULT_TRANSPARENT_COLOR then
        pPix^.rgbReserved:=0
      else
        pPix^.rgbReserved:=255;
      inc (pPix);
    end;
    PreMultiply(ABitmap);
  end;

  fBitmap.Assign(ABitmap);
end;

Et ca marche ... je sais pas prq d'ailleurs !

Merci
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Nicolas___
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 30 janv. 2009 à 22:33
+3
Utile
pour convertir un BMP24 en BMP32 j'utilise ceci :

Function Bmp24To32(Const aBitmap: TBitmap): Boolean;Overload; forward;
Function Bmp24To32(Const
aBitmap: TBitmap; Const TrsColor:
Cardinal): Boolean;Overload; forward;

{converti un BMP24 en 32 avec comme couleur
transparente
 la couleur du pixel se trouvant en haut à gauche du
BMP}
Function Bmp24To32(Const aBitmap: TBitmap): Boolean;
Var PData : PRGBQuad;
  I, BytesTotal : Integer;

  TrsColor: Cardinal;
Begin

  Result := False;
  If Not
Assigned(aBitmap) Then

    Exit;
  aBitmap.PixelFormat := pf32Bit;
  BytesTotal
:= aBitmap.Width * aBitmap.Height;
  TrsColor := aBitmap.Canvas.Pixels[0, 0];
  Try
    Result := True;
    PData :=
aBitmap.ScanLine[aBitmap.Height-1];
     For I : = 0To BytesTotal - 1Do
    Begin
      If Integer(PData^)
<> TrsColor Then

        PData^.rgbReserved := 255;

      Inc(PData);
     End ;
  Except
    Result : = False;
  End;
End;

{ converti un BMP24 en 32 avec "TrsColor" comme
couleur transparente }
Function
Bmp24To32(Const aBitmap: TBitmap;
Const TrsColor: Cardinal): Boolean;
Var PData : PRGBQuad;
  I, BytesTotal : Integer;

Begin
  Result := False;
   If Not Assigned(aBitmap) Then

    Exit;
  aBitmap.PixelFormat : = pf32Bit;
  BytesTotal
:= aBitmap.Width * aBitmap.Height;
  Try

    Result := True;
    PData :=
aBitmap.ScanLine[aBitmap.Height-1];
     For I : = 0To BytesTotal - 1Do
    Begin
      If Integer(PData^)
<> TrsColor Then

        PData^.rgbReserved := 255;

      Inc(PData);
     End ;
  Except
    Result : = False;
  End;
End;

et ça fonctionne parce que maintenant les pixels sont correctes grâce à la pré-multiplication

 
@+
Cirec

<hr siz="" />
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Cirec
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 18:06
0
Utile
Oups, j'ai oublié de demander la première fois

if  GetDeviceCaps(ACanvas.Handle,SHADEBLENDCAPS)= 0 then
    fSupportAlphaBlend := false
  else
    fSupportAlphaBlend := true;
Je ne pige pas pourquoi cette fonction me retourne toujours 0 puisque j'arrvie a faire du blending avec AlphaBlend ...
Commenter la réponse de Nicolas___
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 18:36
0
Utile
J'ai essayé l'astuce CheckTransparentColor , ca ne fonctionne pas ...
Commenter la réponse de Nicolas___
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 30 janv. 2009 à 19:11
0
Utile
Salut,

j'avoue que je comprend pas bien ton problème !!!

j'utilise aussi cette fonction et elle ne me pose pas de problème.
Comme tu n'en parles pas je précise qu'il faut "pré-multiplier" les pixels avant d'utiliser AlphaBlend pour un rendu correcte avec 32Bit.

et pour un 24Bit à afficher en 32Bit avec ajout d'alpha il faut plutôt faire l'inverse !!!
Quand on transforme un 24Bit en 32Bit tous les bits Alpha sont mis à Zéro par défaut
donc transparent !!!! ..... il faut donc mettre tous les autres pixels, qui n'ont pas la couleur transparente, à 255 (Opaque)

 
@+
Cirec

<hr siz="" />
Commenter la réponse de Cirec
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 19:31
0
Utile
"Quand on transforme un 24Bit en 32Bit tous les bits Alpha sont mis à Zéro par défaut
donc transparent !!!! ..... il faut donc mettre tous les autres pixels, qui n'ont pas la couleur transparente, à 255 (Opaque)"
Je me suis peut être mal exprimé mais c'est ce que j'ai fait ...

Ben mon problème est simple , ma couleur transparente ne l'est plus !
j'ai le même problème qu'avec CopyRect !
Commenter la réponse de Nicolas___
Cirec 4217 Messages postés vendredi 23 juillet 2004Date d'inscription 3 avril 2018 Dernière intervention - 30 janv. 2009 à 19:48
0
Utile
ben si tu fais ça et tu pré-multiplies les pixels
et si AlphaFormat := AC_SRC_ALPHA
alors ça devrait fonctionner !!!!!

 
@+
Cirec

<hr siz="" />
Commenter la réponse de Cirec
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 20:06
0
Utile
attends , je te montre ce que je fais :

procedure SetBitmap(ABitmap : TBitmap);
var
  pPix : pRGBQuad;
  x : integer;
begin

  fBlend.AlphaFormat:=AC_SRC_ALPHA;

  if ABitmap.PixelFormat<>pf32bit then begin
    ABitmap.PixelFormat := pf32bit;

    pPix := ABitmap.ScanLine[ABitmap.Height - 1];
    for x:=0 to ABitmap.Width * ABitmap.Height - 1 do begin
      // si c'est la TransparentColor , alors Alpha = 0
      // sinon Alpha = 255 ...
      if RGB(pPix^.rgbRed,pPix^.rgbGreen,pPix^.rgbBlue) = DEFAULT_TRANSPARENT_COLOR then
        pPix^.rgbReserved:=0;
      else
        pPix^.rgbReserved:=255;
      inc (pPix);
    end;
  end;

  fBitmap.Assign(ABitmap);
end;

Je ne pige pas l'histoire de pré-multiplies les pixels ...

Mais normalement Je mets bien la couche alpha a 0 (donc transparent) ou mes pixels sont = a la couleur de transparence ,non ?

et fBlend.SourceConstantAlpha = 255 par defaut (donc opaque )
Commenter la réponse de Nicolas___
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 20:10
0
Utile
y'a un ; en trop , fausse manip mais ca ne change rien !
Commenter la réponse de Nicolas___
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 23:13
0
Utile
Super , Merci beaucoup  Cirec
Commenter la réponse de Nicolas___
Nicolas___ 1039 Messages postés jeudi 2 novembre 2000Date d'inscription 24 avril 2013 Dernière intervention - 30 janv. 2009 à 23:15
0
Utile
Ca y est , la pièce est tombée , je viens de piger comment ça fonctionnait :)
Commenter la réponse de Nicolas___

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.