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

时间:2014-08-29 23:11:40

标签: delphi lazarus

问题

我正在尝试将TBitmap中的32x32磁贴复制到TPaintbox这是我的地图编辑器,但我似乎无法使透明度正常工作。

见下图:

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

enter image description here

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

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

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;

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;

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

无论如何,如何在不失去透明度的情况下将TBitmap的一部分复制/绘制到TPaintbox,或者在没有复制白色背景的情况下如何复制/绘制?{/ p>

更新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;

enter image description here

感谢。

1 个答案:

答案 0 :(得分:0)

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

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

  1. 将透明位图保留在TImageList中,并使用TImageList.Draw直接在目标画布上绘制(不要在中间位图上绘制,因为这里会丢失透明度)。要在设计时将图像添加到图像列表,请右键单击并选择“图像列表编辑器”。列表中的图像可以是位图,图标,PNG,GIF和JPEG图像:TImage支持的任何图像类型。 ImageLists也支持32位格式,因此alpha混合位图和PNG文件可以正常工作。您还可以在运行时加载图像。如果您的位图以非透明形式存储但是有透明颜色,则可以使用TImageList.AddMasked(位图:TBitmap; MaskColor:TColor)方法。您可以在第二个参数或clDefault中自行传递透明色,让图像列表采用左下角像素的颜色。
  2. 将图像保存在PNG文件或资源中,然后将它们加载到Vcl.Imaging.pngimage.TpngImage中,然后调用TpngImage.Draw直接在目标画布上绘制PNG。如上所述,不要在中间位图上绘画,因为这里会失去透明度。
  3. 使用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。