2013-10-22 14 views
5

Sto provando a creare e dipingere in runtime un bitmap a 32 bit e quindi aggiungerlo a una ImageList. La bitmap ha trasparenza (canale alfa). Posso creare la bitmap e disegnare su di essa Canvas senza problemi, e disegna normalmente con trasparenza su qualsiasi altra tela.Aggiunta di bitmap a 32 bit a ImageList

Il problema è quando lo aggiungo a una ImageList, l'immagine sembra perdere i disegni realizzati con la proprietà Canvas della bitmap.

Ecco come avvio il Bitmap:

Bitmap := TBitmap.Create; 
Bitmap.PixelFormat := pf32bit; 
Bitmap.Transparent := True; 
Bitmap.AlphaFormat := afDefined; 
SetBkMode(Bitmap.Canvas.Handle, TRANSPARENT); 
Bitmap.SetSize(100, 42); 

// now I can draw, let's say, an icon from an imagelist 
ImageList.Draw(Bitmap.Canvas, 5, 5, 0, dsTransparent, itImage); 

// and some other stuff 
Bitmap.Canvas.RoundRect(0, 0, 99, 41, 5, 5); 
Bitmap.Canvas.TextOut(50, 5, 'Test string'); 

Se io disegnare questo Bitmap a qualsiasi tela di controllo, trae normalmente, con l'immagine della imagelist, il rettangolo arrotondato e il testo, con sfondo trasparente (Ovunque che nulla è stato dipinto sarà trasparente, manterrà lo sfondo che era già lì). Significa che Form1.Canvas.Draw(0, 0, Bitmap); disegna la bitmap su Form1 e se ci sono altre immagini lì, verrà mantenuta come sfondo.

MA, se aggiungo questa bitmap a un elenco immagini, si verifica uno strano problema. L'ImageList ha il ColorDepth impostato su cd32bit, e poi io chiamo:

BitmapImageList.Width := Bitmap.Width; 
BitmapImageList.Hieght := Bitmap.Height; 
BitmapImageList.Add(Bitmap, nil); 

Ora, se provo a disegnare quella immagine da ImageList con:

BitmapImageList.Draw(Form1.Canvas, 0, 0, 0); 

L'unica cosa che verrà visualizzata è la l'immagine disegnata in Bitmap da ImageList, il rettangolo arrotondato e il testo disegnato nel Canvas scompare.

Cosa mi manca?

risposta

5

È possibile creare una bitmap aggiuntiva (Intrans) il cui chanel alfa è impostato su 0.
Intrans viene utilizzato per ImageList.Add come immagine della bitmap originale come Mask.
L'esempio dovrebbe riflettere il tuo.

type 
    pRGBQuadArray = ^TRGBQuadArray; 
    TRGBQuadArray = ARRAY [0 .. 0] OF TRGBQuad; 

Procedure GenIntransparentBitmap(bmp, Intrans: TBitmap); 
var 
    pscanLine32: pRGBQuadArray; 
    i, j: Integer; 
begin 
    Intrans.Assign(bmp); 
    for i := 0 to Intrans.Height - 1 do 
    begin 
    pscanLine32 := Intrans.Scanline[i]; 
    for j := 0 to Intrans.Width - 1 do 
    begin 
     pscanLine32[j].rgbReserved := 0; 
    end; 
    end; 
end; 

procedure TForm3.Button1Click(Sender: TObject); 
var 
    Bitmap, Intransp: TBitmap; 
begin 
    Bitmap := TBitmap.Create; 
    try 
    Bitmap.PixelFormat := pf32bit; 
    Bitmap.Transparent := true; 
    Bitmap.AlphaFormat := afIgnored; 
    SetBkMode(Bitmap.Canvas.Handle, BKMODE_LAST); 
    Bitmap.SetSize(100, 42); 

    ImageList1.Draw(Bitmap.Canvas, 5, 5, 0, dsTransparent, itImage); 

    Bitmap.Canvas.Brush.Style := bsClear; 
    Bitmap.Canvas.RoundRect(0, 0, 99, 41, 5, 5); 
    Bitmap.Canvas.TextOut(50, 5, 'Test string'); 

    BitmapImageList.Width := Bitmap.Width; 
    BitmapImageList.Height := Bitmap.Height; 

    // Create intransparent bitmap from transparent bitmap 
    Intransp := TBitmap.Create; 
    try 
     GenIntransparentBitmap(Bitmap, Intransp); 
     // add intransparent bitmap as image and transparent bitmap as mask 
     BitmapImageList.Add(Intransp, Bitmap); 
    finally 
     Intransp.Free; 
    end; 

    BitmapImageList.Draw(Canvas, 100, 100, 0); 
    finally 
    Bitmap.Free; 
    end; 
end; 

Una versione più breve sarebbe

Procedure GenIntransparentBitmap(bmp, Intrans: TBitmap); 
begin 
    Intrans.Assign(bmp); 
    Intrans.PixelFormat := pf24bit; 
end; 

procedure TForm3.Button1Click(Sender: TObject); 
var 
    Bitmap, Intransp: TBitmap; 
begin 
    Bitmap := TBitmap.Create; 
    try 
    Bitmap.PixelFormat := pf32bit; 

    SetBkMode(Bitmap.Canvas.Handle, TRANSPARENT); 
    Bitmap.SetSize(100, 42); 

    ImageList1.Draw(Bitmap.Canvas, 5, 5, 0, dsTransparent, itImage); 

    Bitmap.Canvas.Brush.Style := bsClear; 
    Bitmap.Canvas.RoundRect(0, 0, 99, 41, 5, 5); 
    Bitmap.Canvas.TextOut(50, 5, 'Test string'); 

    BitmapImageList.Width := Bitmap.Width; 
    BitmapImageList.Height := Bitmap.Height; 

    // Create intransparent bitmap from transparent bitmap 
    Intransp := TBitmap.Create; 
    try 
     GenIntransparentBitmap(Bitmap, Intransp); 
     // add intransparent bitmap as image and transparent bitmap as mask 
     BitmapImageList.Add(Intransp, Bitmap); 
    finally 
     Intransp.Free; 
    end; 

    BitmapImageList.Draw(Canvas, 100, 100, 0); 
    finally 
    Bitmap.Free; 
    end; 
end; 
+1

ben fatto. Mi ero dimenticato della maschera. Aggiungo sempre le icone agli elenchi di immagini e ora ricordo che quando creo le icone, è essenziale specificare una maschera. –

+0

Fantastico. Stavo cercando una risposta per quel modulo di problemi di età, e non riuscivo a trovarne. La tua soluzione funziona PERFETTAMENTE. Un'ultima cosa da notare è che "BitmapImageList" nell'esempio deve avere ColorDepth impostato su cd24Bit. Grazie mille. – Marcio