我正在尝试绘制源图像(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;
答案 0 :(得分:4)
它与TransparentBlt()一起工作(但有两个缺点)。
我对TransparentBlt处理半透明像素(旋转图像的边缘)的方式不满意。将src图像合并到背景中后,边缘看起来很糟糕。
为了使用TransparentBlt,我必须将源图像中的颜色(clPink)定义为透明。这意味着如果源图像中有一些粉红色,结果将显得非常讨厌(它将被视为透明)。让我们为非粉红色的图像祈祷!
如果您找到一种方法将图像直接从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: