如何在TBitmap上透明地绘制TBitmap32?

时间:2014-01-30 17:28:07

标签: delphi graphics32

我正在尝试绘制源图像(GR32 TBitmap32),其中包含普通(TBitmap)图像上的一些完全透明且部分透明的像素,同时保留源图像中的透明度。

我用这个:

BMP32.DrawTo(BMP.Canvas.Handle, 0, 0);

但图像不是透明绘制的。


代码:
一切都非常基本:我有一个背景位图(Bkg),我在应用程序启动时加载一个图像。 然后在程序中应用我从磁盘加载第二个图像(具有透明度的图像),然后在背景上绘制它。

var Bkg: TBitmap;

procedure TfrmPhoto.FormCreate(Sender: TObject);
begin
 Bkg:= LoadGraphEx(GetAppDir+ 'bkg.bmp'); { Load bitmap from file }
 {
 Bkg.Transparent:= TRUE;
 Bkg.PixelFormat:= pf32bit;
 Bkg.TransparentColor:= clPink;
 }
end;


procedure TfrmPhoto.Apply2;
VAR
   Loader: TBitmap;
   BMP32: tbitmap32;
begin
 BMP32:= TBitmap32.Create;
 TRY

  Loader:= TBitmap.Create;
  TRY
   Loader.LoadFromFile('c:\Transparent.BMP');
   BMP32.Assign(Loader);
  FINALLY
   FreeAndNil(Loader);
  END;

  { Mix images }
  BMP32.DrawTo(Bkg.Canvas.Handle, 0, 0);    <----- The problem is here

  imgPreview.Picture.Assign(Bkg);    { This is a TImage where I see the result }
 FINALLY
  FreeAndNil(BMP32);
 END;
end;

3 个答案:

答案 0 :(得分:4)

它与TransparentBlt()一起工作(但有两个缺点)。

  1. 我对TransparentBlt处理半透明像素(旋转图像的边缘)的方式不满意。将src图像合并到背景中后,边缘看起来很糟糕。

  2. 为了使用TransparentBlt,我必须将源图像中的颜色(clPink)定义为透明。这意味着如果源图像中有一些粉红色,结果将显得非常讨厌(它将被视为透明)。让我们为非粉红色的图像祈祷!

  3. 如果您找到一种方法将图像直接从Bitmap32传输到背景中(同时保留透明度),请发布,我会接受您的回答!

    我在这里看到的解决方案(仍然是黑客)是处理TBitmap32中的所有内容,然后将最终结果“导出”为TBitmap。我明天会试试。


    更新:
    解决方案:

    这是如何在保持透明度的同时合并两个TBitmap32图像:

     Dst.CombineMode:= cmBlend;
     Dst.DrawMode:= dmBlend;
     Src.Draw(0, 0, Dst);  
    

    Dst和Src是TBitmap32图像。它不适用于TBitmap。

答案 1 :(得分:3)

正如您自己已经建议的那样,我建议完全在TBitmap32域中执行混合操作!其原因在于它在混合方面提供了更多选择,并且在可用的情况下使用MMX / SSE / SSE2(在现代机器上总是如此)。与让GDI执行混合相比,通常可以获得显着的性能提升。

特别是这不是一个好主意,因为GDI通常不使用任何SIMD操作码(MMX / SSE)。

这还取决于每个部分的变化程度。例如,通常背景是静态的,并且仅需要在变化时(例如,在VCL样式或UI主题变化上)转移到TBitmpa32中。随着每次传输(GR32-TBitmap等),可能发生冲突转换(DIB-DDB),这使得整个混合成为O(n 2)操作。因此,您最好将(通过隐式转换)传输到TBitmap32一次,然后完全在GR32域中执行混合。

相反,如果TBitmap32相当静态并且TBitmap(或背景)发生了很大变化,那么最好不要单独留下GR32并将TBitmap32复制到TBitmap并执行与GDI的混合。尽管GDI混合略慢,但您可以避免使用额外的副本。否则,你的瓶颈可能就是内存吞吐量,而处理速度永远不会达到极限。

答案 2 :(得分:0)

TBitmap32的dmBlend DrawMode打开透明度,但它仅在两个TBitmap32位图之间起作用。不要将TBitmap32与透明图像一起直接在HDC,Canvas或TBitmap上绘制。使用dmBlend和DrawTo或BlockTransfer()在另一个TBitmap32上绘制。例如,要在TBitmap上透明地绘制,请创建中间缓存TBitmap32:

  1. 将图像从TBitmap复制到缓存TBitmap32;
  2. 使用DrawTo或BlockTransfer()将透明图像应用于缓存TBitmap32,避免使用Canvas或HDC混合两个图像,因为它们会丢失alpha图层信息;
  3. 将图像从缓存TBitmap32复制回TBitmap。