2013-10-22 82 views
5

我试图在运行时创建并绘制一个32位位图,然后将其添加到ImageList。位图具有透明度(alpha通道)。我可以创建位图并在Canvas上绘制,没有任何问题,并且它在任何其他画布上都具有透明度。将32位位图添加到ImageList

问题是,当我将它添加到ImageList时,图像似乎失去了使用位图的Canvas属性所做的图形。

这里是我开始的位图:

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'); 

如果我画这个位图到任何控制的画布,它吸引normaly,从图像列表,圆角矩形和文本的图像,用透明背景(任何地方都没有被绘的东西是透明的;会保留已经存在的背景)。这意味着Form1.Canvas.Draw(0, 0, Bitmap);将在Form1上绘制位图,如果有其他图像,它将保留为背景。

但是,如果我将这个位图添加到图像列表中,会出现一个奇怪的问题。 ImageList中有它的颜色质量汇总设置为cd32bit,然后我打电话:

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

现在,如果我尝试从图像列表绘制图像用:

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

将要显示的唯一的事情是从ImageList中的位图中绘制的图像,圆角矩形和Canvas中绘制的文本消失。

我错过了什么?

回答

5

这可以通过创建其alpha通道设置为0的附加位图(Intrans)来完成。
Intrans用于ImageList.Add图像原始位图作为Mask。
这个例子应该反映你的。

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; 

一个较短的版本将是

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

干得好。我忘记了面具。我总是将图标添加到图像列表中,现在我记得当我制作图标时,指定蒙版是非常重要的。 –

+0

太棒了。我一直在寻找一个解决这个问题的答案,并且找不到任何答案。您的解决方案完美地工作。最后需要注意的是,示例中的“BitmapImageList”必须将其ColorDepth设置为cd24Bit。非常感谢你。 – Marcio