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 文件的方法:
- 将它们加载到中间的 TBitmap32 位图中,然后操作这些 TBitmap32 位图。
- 如您所指出的,直接在目标 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,请执行以下步骤:
- 确保您的代码正确地将 PNG 转换为 TBitmap32。
- 不要使用带透明图像的TBitmap32直接在HDC、Canvas或TBitmap上绘制。使用 dmBlend 和 DrawTo 或 BlockTransfer() 在另一个 TBitmap32 上绘制。例如,要在 TBitmap 上透明绘制,创建一个中间缓存 TBitmap32:
- 将图片从TBitmap复制到缓存TBitmap32;
- 使用 DrawTo 或 BlockTransfer() 将透明图像应用到缓存 TBitmap32,避免使用 Canvas 或 HDC 混合两个图像,因为它们会丢失 alpha 层信息;
- 将图像从缓存 TBitmap32 复制回您的 TBitmap。
在经历了其他几个相关问题后,我无法为此提供工作代码,所以请保留 "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 文件的方法:
- 将它们加载到中间的 TBitmap32 位图中,然后操作这些 TBitmap32 位图。
- 如您所指出的,直接在目标 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,请执行以下步骤:
- 确保您的代码正确地将 PNG 转换为 TBitmap32。
- 不要使用带透明图像的TBitmap32直接在HDC、Canvas或TBitmap上绘制。使用 dmBlend 和 DrawTo 或 BlockTransfer() 在另一个 TBitmap32 上绘制。例如,要在 TBitmap 上透明绘制,创建一个中间缓存 TBitmap32:
- 将图片从TBitmap复制到缓存TBitmap32;
- 使用 DrawTo 或 BlockTransfer() 将透明图像应用到缓存 TBitmap32,避免使用 Canvas 或 HDC 混合两个图像,因为它们会丢失 alpha 层信息;
- 将图像从缓存 TBitmap32 复制回您的 TBitmap。