Why am I losing transparency when calling BitBlt or CopyRect?

Problem

I am trying to copy 32x32 tiles from TBitmap to TPaintbox , which is my map editor, but I cannot get transparency to work correctly.

See image below:

Note. For demonstration and testing, I placed TImage under TPaintbox, which will help see if transparency works.

enter image description here

As you can see, the correct tiles are drawn correctly, but the tiles, which should be transparent, are painted on a white background.

Now I use the appropriate classes to manage my maps and fragments, and below, in two ways that I tried to draw:

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; 

Bitlt

 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; 

I tried to use raster and png image formats for a set of tiles (left image in the screenshot). The only difference between bitmap and png is that CopyRect tries to draw even a few fragments when it is png, but BitBlt manages to draw without any obvious flaws.

Anyway, how to copy / draw a part of TBitmap on TPaintbox without losing transparency or in my case without copying a white background?

Update 1

Following the comments below, I tried calling the AlphaBlend function, but this still leaves unwanted results (note the blue colors around the transparent areas):

 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

Thanks.

+5
source share
1 answer

There are 3 popular ways to work with transparent bitmaps, the first two use standard Delphi tools, and the third requires a third-party library:

If you use one of the two standard methods, do not use BitBlt or CopyRect. Use the Draw method for a transparent image holder to draw on the destination canvas.

  • Save your transparent bitmaps in a TImageList and use TImageList.Draw to paint directly on the destination canvas (do not paint on intermediate bitmaps as you will lose transparency here). To add images to the image list at design time, right-click and select Image List Editor. The images in the list can be bitmaps, icons, PNG, GIF and JPEG images: any type of image supported by TImage. ImageLists also support the 32-bit format, so alpha-mixed bitmaps and PNG files work correctly. You can also upload images at runtime. If your bitmaps are stored in an opaque form but have a transparent color, you can use the TImageList.AddMasked method (Bitmap: TBitmap; MaskColor: TColor). You can either pass the transparent color to yourself in the second parameter, or in clDefault to allow the image to draw the bottom left pixel color.
  • Save images in PNG files or resources and upload them to Vcl.Imaging.pngimage.TpngImage, and then call TpngImage.Draw to draw your PNG directly on the destination canvas. As above, do not draw on intermediate bitmaps, as you will lose transparency here.
  • Use TBitmap32 from GR32, a third-party library. In this case, do not use TBitmap32 with transparent images for drawing directly on HDC, Canvas or TBitmap. Use dmBlend and DrawTo or BlockTransfer () to draw on another TBitmap32. For example, to draw transparently on TBitmap, create an intermediate TBitmap32 cache: (1) Copy the image from TBitmap to the TBitmap32 cache; (2) Apply a transparent image to the TBitmap32 cache using DrawTo or BlockTransfer (), avoid using Canvas or HDC to mix two images, as they lose alpha layer information; (3) Copy the image from the TBitmap32 cache to your TBitmap.
0
source

Source: https://habr.com/ru/post/1201454/


All Articles