为什么我在调用BitBlt或CopyRect时会失去透明度?

5 delphi lazarus

问题

我正在尝试将32x32磁贴从a复制TBitmapTPaintbox我的地图编辑器中,但我似乎无法使透明度正常工作.

见下图:

注意:出于演示和测试的目的,我在TPaintbox下面放置了一个TImage,这有助于查看透明度是否有效.

在此输入图像描述

如您所见,常规瓷砖绘制正确,但应该是透明的瓷砖是用白色背景绘制的.

我现在正在使用适当的类来管理我的地图和图块,下面是我尝试绘制的两种方法:

CopyRect:

procedure TMap.DrawTile(Tileset: TBitmap; MapX, MapY, TileX, TileY: Integer;
  MapCanvas: TCanvas);
begin
  if TileIsFree(MapX, MapY) then
  begin
    MapCanvas.CopyRect(
      Rect(MapX, MapY, MapX + fTileWidth, MapY + fTileHeight),
      Tileset.Canvas,
      Rect(TileX, TileY, TileX + fTileWidth, TileY + fTileHeight));
  end;
end;
Run Code Online (Sandbox Code Playgroud)

的BitBlt

procedure TMap.DrawTile(Tileset: TBitmap; MapX, MapY, TileX, TileY: Integer;
  MapCanvas: TCanvas);
begin
  if TileIsFree(MapX, MapY) then
  begin
    BitBlt(
      MapCanvas.Handle,
      MapX,
      MapY,
      fTileWidth,
      fTileHeight,
      Tileset.Canvas.Handle,
      TileX,
      TileY,
      SRCCOPY);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

我已经尝试为tileset使用位图和png图像格式(屏幕截图上的左图).位图和png之间的唯一区别是,CopyRect当它是png时,很难绘制甚至几个图块,但BitBlt设法绘制没有任何明显的缺点.

无论如何,如何TBitmapTPaintbox不丢失透明度的情况下复制/绘制部分a ,或者在我的情况下不复制白色背景?

更新1

继下面的一些评论后,我尝试调用该AlphaBlend函数,但这仍然会产生不良结果(请注意透明区域周围的蓝色):

procedure TMap.DrawTile(Tileset: Graphics.TBitmap; MapX, MapY, TileX, TileY: Integer;
  MapCanvas: TCanvas);
var
  BlendFn: TBlendFunction;
begin
  if TileIsFree(MapX, MapY) then
  begin
    BlendFn.BlendOp := AC_SRC_OVER;
    BlendFn.BlendFlags := 0;
    BlendFn.SourceConstantAlpha := 255;
    BlendFn.AlphaFormat := AC_SRC_ALPHA;

    AlphaBlend(
      MapCanvas.Handle,
      MapX,
      MapY,
      fTileWidth,
      fTileHeight,
      Tileset.Canvas.Handle,
      TileX,
      TileY,
      fTileWidth,
      fTileHeight,
      BlendFn);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

谢谢.

Max*_*tin 0

有 3 种流行的方法来处理透明位图,前两种使用标准 Delphi 工具,第三种需要第三方库:

\n\n

如果您使用两种标准方法之一,请不要使用 BitBlt 或 CopyRect。使用透明图像容器的 Draw 方法在目标画布上绘图。

\n\n
    \n
  1. 将透明位图保存在 TImageList 中,并使用 TImageList.Draw 直接在目标画布上绘制(不要在中间位图上绘制,因为您将在此处失去透明度)。要在设计时将图像添加到图像列表,请右键单击并选择图像列表编辑器。列表中的图像可以是位图、图标、PNG、GIF 和 JPEG 图像:TImage 支持的任何图像类型。ImageLists 还支持 32 位格式,因此 alpha 混合位图和 PNG 文件可以正常工作。您还可以在运行时加载图像。如果您的位图以非透明形式存储但有透明颜色,则可以使用 TImageList.AddMasked(Bitmap: TBitmap; MaskColor: TColor) 方法。您可以在第二个参数中自行传递透明颜色,也可以使用 clDefault 来让图像列表采用左下像素的颜色。
  2. \n
  3. 将图像保存在 PNG 文件或资源中,并将它们加载到 Vcl.Imaging.pngimage.TpngImage 中,然后调用 TpngImage.Draw 将 PNG 直接绘制在目标画布上。如上所述,不要在中间位图上绘制\xe2\x80\x99t,因为你会在这里失去透明度。
  4. \n
  5. 使用第三方库 GR32 中的 TBitmap32。在这种情况下,请勿使用具有透明图像的 TBitmap32 直接在 HDC、Canvas 或 TBitmap 上绘制。使用 dmBlend 和 DrawTo 或 BlockTransfer() 在另一个 TBitmap32 上绘图。例如,要在 TBitmap 上透明绘制,请创建一个中间缓存 TBitmap32: (1) 将图像从 TBitmap 复制到缓存 TBitmap32;(2) 使用 DrawTo 或 BlockTransfer() 将透明图像应用到缓存 TBitmap32,避免使用 Canvas 或 HDC 混合两个图像,因为它们会丢失 alpha 层信息;(3) 将图像从缓存 TBitmap32 复制回您的 TBitmap。
  6. \n
\n