Delphi: GR32 在不清除其内容的情况下将带有 alpha 的 PNG 绘制到 TBitmap32 上

Delphi: GR32 draw a PNG with alpha onto a TBitmap32 without clearing its content

在经历了其他几个相关问题后,我无法为此提供工作代码,所以请保留 "duplicate question" 标签。

给定一个具有每像素 alpha 通道或单色透明度的 PNG 图像,我需要代码将其绘制到已经包含图像的 TBitmap32 上(一些绘图在 PNG 部分之前进行)。所以假设我的 TBitmap32 是 200x200,我在上面画了一些图,然后我想在其当前内容之上插入一个较小的透明 PNG 图像,根据 PNG 的 alpha 通道数据或单色 alpha 透明。

Uses pngimage, GR32;

procedure TForm1.Button1Click(Sender: TObject);
Var b: TBitmap;
    b32: TBitmap32;
    p: TPngImage;
begin
  b   := TBitmap.Create;
  b32 := TBitmap32.Create;
  p   := TPngImage.Create;

  // 50x50 PNG
  p.LoadFromFile('z:\test2.png');

  b.Width    := 200;
  b.Height   := 200;
  b32.Width  := 200;
  b32.Height := 200;
  // some drawing happens on the b32~

  // insert code here to draw the png onto the b32, on top of
  // what's already drawn, and at specific coordinates i.e 10,10


  /////////////////////////////

  b32.DrawTo(b.Canvas.Handle,0,0);
  Canvas.Draw(0,0,b);

  p.Free;
  b32.Free;
  b.Free;
end;

原始 PNG:

目前的结果:

有两种处理透明 PNG 文件的方法:

  1. 将它们加载到中间的 TBitmap32 位图中,然后操作这些 TBitmap32 位图。
  2. 如您所指出的,直接在目标 Canvas 上使用 TPngImage.Draw(在 Vcl.Imaging.pngimage 中使用 Delphi XE2 及更高版本实现)。

就透明度而言,第二种方法更可取,因为您可能会发现将 PNG 加载到 TBitmap32 的代码可能无法正常工作。以下是最常使用的错误代码的两个示例:

(1) 来自 http://graphics32.org/wiki/FAQ/ImageFormatRelated 的“LoadPNGintoBitmap32” - 它应用了两次透明度,因此 alpha 值不是 0 或 255 的图像看起来与在其他软件中不同(在具有玻璃效果的半透明图像上最明显)。此代码将首先将 alpha 应用于 RGB,然后设置 alpha,因此当您感到疼痛时,将再次应用 alpha。您可以在此处找到有关此问题的更多信息:Delphi, GR32 + PngObject: converting to Bitmap32 doesn't work as expected .除此之外,它不能正确地将调色板图像的透明度转换为 TBitmap32 的 alpha 层,例如,所有白色像素都变得透明。

(2) 来自 gr32ex 库的“LoadBitmap32FromPNG”:https://code.google.com/archive/p/gr32ex/ - 与 (1) 相同算法的实现略有不同,并且具有与 (1) 相同的问题。

如果您仍然喜欢使用 TBitmap32,请执行以下步骤:

  1. 确保您的代码正确地将 PNG 转换为 TBitmap32。
  2. 不要使用带透明图像的TBitmap32直接在HDC、Canvas或TBitmap上绘制。使用 dmBlend 和 DrawTo 或 BlockTransfer() 在另一个 TBitmap32 上绘制。例如,要在 TBitmap 上透明绘制,创建一个中间缓存 TBitmap32:
    1. 将图片从TBitmap复制到缓存TBitmap32;
    2. 使用 DrawTo 或 BlockTransfer() 将透明图像应用到缓存 TBitmap32,避免使用 Canvas 或 HDC 混合两个图像,因为它们会丢失 alpha 层信息;
    3. 将图像从缓存 TBitmap32 复制回您的 TBitmap。