简体   繁体   English

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

[英]How to draw a TBitmap32 transparently on a TBitmap?

I am trying to draw a source image (GR32 TBitmap32) that contains some fully transparent and also partially transparent pixels on a normal (TBitmap) image while preserving the transparency in the source image. 我正在尝试绘制一个源图像(GR32 TBitmap32),该图像在正常(TBitmap)图像上包含一些完全透明和部分透明的像素,同时保留了源图像的透明度。

I use this: 我用这个:

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

but the image is not drawn transparently. 但是图像不是透明绘制的。


Code: 码:
Everything is pretty basic: I have a background bitmap (Bkg) in which I load, at application start up, an image. 一切都非常基本:我有一个背景位图(Bkg),在应用程序启动时在其中加载图像。 Then in procedure Apply I load a second image from disk (the one with transparency) and I draw the it over the background. 然后在“应用”过程中,从磁盘加载第二张图像(具有透明度的图像),然后将其绘制在背景上。

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;

It worked (but with 2 disadvantages) with TransparentBlt(). 它与TransparentBlt()一起工作(但有两个缺点)。

  1. I am not happy with the way TransparentBlt handles the semitransparent pixels (the edge of the rotate image). 我对TransparentBlt处理半透明像素(旋转图像的边缘)的方式不满意。 After merging the src image into the background the edges look bad. 将src图像合并到背景中后,边缘看起来不好。

  2. In order to use TransparentBlt, I had to define a color (clPink) in the source image as transparent. 为了使用TransparentBlt,我必须在源图像中将颜色(clPink)定义为透明。 This means that if the source image has some pink in it, the result will look really nasty (it will be treated as transparent). 这意味着,如果源图像中有一些粉红色,结果将看起来非常讨厌(将被视为透明)。 Let's pray for non-pink images! 让我们为非粉红色的图片祈祷!

If you find a way to transfer the image (while preserving transparency) directly from Bitmap32 into the background please post and I will accept your answer! 如果您找到一种将图像(同时保持透明性)直接从Bitmap32转移到背景中的方法,请发表,我会接受您的回答!

A solution (still a hack) I see here is to process everything in a TBitmap32 and then 'export' the final result as TBitmap. 我在这里看到的一个解决方案(仍然是hack)是处理TBitmap32中的所有内容,然后将最终结果“导出”为TBitmap。 I will try this tomorrow. 我明天试试。


Update: 更新:
Solution: 解:

This is how to merge two TBitmap32 images while preserving transparency: 这是在保留透明度的同时合并两个TBitmap32图像的方法:

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

Dst and Src are TBitmap32 images. Dst和Src是TBitmap32图像。 It doesn't work with TBitmap. 它不适用于TBitmap。

As already suggested by yourself, I would recommend performing blending operations entirely in the TBitmap32 domain! 正如您已经建议的那样,我建议您完全在TBitmap32域中执行混合操作! The reason for this is the fact that it offers more choices in regards of blending and it uses MMX/SSE/SSE2 where available (on modern machines always the case). 这样做的原因是,它在混合方面提供了更多选择,并且在可用的情况下使用MMX / SSE / SSE2(在现代机器上始终如此)。 With this one can typically get a notable performance boost in contrast to letting GDI perform the blending. 与让GDI执行混合相比,使用此方法通常可以显着提高性能。

In particular this is not a good idea as GDI typically does not make use of any SIMD opcodes (MMX/SSE). 特别地,这不是一个好主意,因为GDI通常不使用任何SIMD操作码(MMX / SSE)。

It also depends on how much each part changes. 它还取决于每个部分的变化量。 For example, typically the background is rather static and need to be transfered into a TBitmpa32 only occassionally on changes (eg on VCL style or UI theme changes). 例如,通常背景是相当静态的,仅在偶尔发生更改时(例如,在VCL样式或UI主题更改时)才需要转移到TBitmpa32中。 With each transfer (GR32 <-> TBitmap and alike) an implict conversion (DIB <-> DDB) might happen, which makes the entire blending an O(n²) operation. 每次传输(GR32 <-> TBitmap等)时,可能会发生隐式转换(DIB <-> DDB),这会使整个混合过程成为O(n²)操作。 So you'd better transfer (with an implicit conversion) to TBitmap32 just once and then perform the blending entirely in the GR32 domain. 因此,您最好一次(通过隐式转换)转移到TBitmap32,然后在GR32域中完全执行混合。

On the contrary, if the TBitmap32 is rather static and the TBitmap (or background) changes a lot, it might probably be better to leave GR32 alone and copy the TBitmap32 to TBitmap and perform the blending with GDI. 相反,如果TBitmap32是静态的并且TBitmap(或背景)发生了很大变化,则最好不使用GR32,而是将TBitmap32复制到TBitmap并与GDI进行混合。 Despite the fact that the GDI blending is slightly slower, you avoid the additional copy. 尽管GDI混合的速度稍慢,但是您还是避免了额外的复制。 Otherwise your bottleneck will likely be the memory throughput, while processing speed never can touch the limits. 否则,您的瓶颈可能是内存吞吐量,而处理速度永远无法超越极限。

It is dmBlend DrawMode of TBitmap32 to turn on the transparency, but it only works between two TBitmap32 bitmaps. 打开透明度是TBitmap32的dmBlend DrawMode,但它仅在两个TBitmap32位图之间起作用。 Do not use TBitmap32 with transparent images to draw directly on HDC, Canvas or TBitmap. 请勿将TBitmap32与透明图像一起使用,以直接在HDC,Canvas或TBitmap上绘制。 Use dmBlend and DrawTo or BlockTransfer() to draw on another TBitmap32. 使用dmBlend和DrawTo或BlockTransfer()在另一个TBitmap32上绘制。 For example, to draw transparently on a TBitmap, create an intermediary cache TBitmap32: 例如,要在TBitmap上透明地绘制,请创建一个中间缓存TBitmap32:

  1. Copy the image from TBitmap to the cache TBitmap32; 将图像从TBitmap复制到缓存TBitmap32;
  2. Apply your transparent image to the cache TBitmap32 using DrawTo or BlockTransfer(), avoid using Canvas or HDC to mix two images because they lose alpha layer information; 使用DrawTo或BlockTransfer()将透明图像应用于缓存TBitmap32,避免使用Canvas或HDC混合两个图像,因为它们会丢失alpha层信息;
  3. Copy the image back from the cache TBitmap32 to your TBitmap. 将图像从缓存TBitmap32复制回您的TBitmap。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM