4
votes

I have a png that i would like to load in a TBitmap32.

After I load the bitmap I call:

Bitmap.DrawMode   := dmTransparent;
Bitmap.OuterColor := Bitmap.PixelS[0,0];

But then all white pixels are transparent. How can i do that just for the transparent part of the png image? Here is my image with the alpha transparency around the edge of the image indicated in the standard way.

enter image description here

And this is the actual image:

enter image description here

2
Why are you setting DrawMode and OuterColor? It sounds like you got what you asked for. In other words, surely TBitmap32 will respect the alpha transparency of your image.David Heffernan

2 Answers

6
votes

It seems that TBitmap32 may lose alpha information while loading a PNG image.

You may consider to use the GR32PNG library of which a documentation excerpt follows:

. . .
since reading and writing utilizes an intermediate TBitmap object, unnecessary additional memory is required to store the bitmap data. Also by converting data to and from the TBitmap format additional information might get lost or handled wrong.
. . .
To handle PNG files natively by Graphics32 the thirdparty library GR32 PNG Library can be used. This library use the native PNG format as intermediate storage. By assigning a TBitmap32 object the data is encoded/decoded to/from PNG on the fly. Using this library it is also possible to access additional information, which is stored in the PNG file.

Graphics32 project page


The code usage example of the unit can be changed as below to suit your needs:

var
  AlphaChannelUsed: Boolean;
begin
  LoadBitmap32FromPNG(Bitmap, <your path to the PNG image>, AlphaChannelUsed);

  if AlphaChannelUsed then
    Bitmap.DrawMode := dmBlend
  else
    Bitmap.DrawMode := dmOpaque;
end;

Where Bitmap is a TBitmap32 object.


The resulting image loaded in a form within a TImage32 component:

enter image description here

3
votes

The problem may be that the PNG has incorrectly converted to TBitmap32, losing the transparency information in transit. It is a common case with paletted PNG images. Otherwise, you would not had to use „Bitmap.DrawMode := dmTransparent” and the „OuterColor”. If the transparencry information from PNG would have correctly transferred to TBitmpa32, DrawMode := dmBlend would have worked, without the need to set the OuterColor.

What matters most is how did you load a PNG into the TBitmap32. The TPngImage from Vcl.Imaging.pngimage unit (implemented in Delphi XE2 and later) can draw transparently on bitmaps, preserving what was on that bitmaps, combining colors using the PNG alpha layer, etc, but it doesn’t allow to easily convert various formats of PNG transparency (including paletted) into the alpha component of each pixel of TBitmap32. Once TPngImage have drawn an image, you get the combined RGB for each pixel, but the alpha component is not transferred to the target bitmap.

There are helper routines available that try to load a PNG into a TBitmap32 with transparency, but they have drawbacks:

(1) “LoadPNGintoBitmap32” from http://graphics32.org/wiki/FAQ/ImageFormatRelated - it applies the transparency twice, so the images with alpha values other than 0 or 255 will look differently than in other software (most noticeable on translucent images with glass effects). This code will first apply alpha to RGB and then sets alpha as a separate layer, so when you paint, alpha will be applied again. You can find more information on this issue here: Delphi, GR32 + PngObject: converting to Bitmap32 doesn't work as expected . Besides that, it doesn't convert correctly transparency from paletted images into the alpha layer of TBitmap32. They manually set alpha transparency for the pixels of a certain color of the output bitmap (rendered to RGB) rather doing that before rendering to RGB, so the actual transparency is lost as on your sample image when all white pixels are transparent.

(2) “LoadBitmap32FromPNG” from gr32ex library: https://code.google.com/archive/p/gr32ex/ - a slightly different implementation of the same algorithm as (1), and has the same issues as (1).

So, the solutions are:

  1. Do not use TBitmap32; use Vcl.Imaging.pngimage.TPngImage do draw directly on target bitmap (screen, etc.) – this is the most compatible way that deals correctly with various PNG formats.
  2. Use a helper routing to transfer transparency information from Vcl.Imaging.pngimage.TPngImage to TBitmap32.
  3. Use the GR32 PNG library https://sourceforge.net/projects/gr32pnglibrary/

Since you now have all the information on this issue, you may choose the right solution for you.