【问题标题】:How to draw a TBitmap32 transparently on a TBitmap?如何在 TBitmap 上透明地绘制 TBitmap32?
【发布时间】:2014-01-30 17:28:06
【问题描述】:

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

我用这个:

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;

【问题讨论】:

  • 申请SSCCE会不会太过分了?
  • 请编辑您的问题:添加您的 Delphi 版本的标签,并展示您如何为每像素 32 位库存 TBitmap 启用和设置透明模式
  • 添加了源代码。 LoadGraphEx 可以替换为 LoadFromFile('')。否则,项目应该是可编译的。
  • 感谢您的更新,+1
  • 在 GR32 中有一个例子,他们在背景上绘制了一个旋转的图像。但是,他们也使用 bitmap32 作为背景!他们不像我那样将位图与 bitmap32 结合起来。我不知道我应该如何(透明地)组合这两个图像。此外,我在他们的示例中找不到有关如何执行此操作的具体示例。

标签: delphi graphics32


【解决方案1】:

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

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

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

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

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


更新:
解决方案:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    这还取决于每个部分的变化量。例如,通常背景是相当静态的,只需要偶尔在更改时(例如 VCL 样式或 UI 主题更改)才需要将其转换为 TBitmpa32。每次传输(GR32 TBitmap 等)可能会发生隐式转换(DIB DDB),这使得整个混合成为 O(n²) 操作。所以你最好只传输一次(通过隐式转换)到 TBitmap32,然后完全在 GR32 域中执行混合。

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

    【讨论】:

      【解决方案3】:

      开启透明是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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-22
        相关资源
        最近更新 更多