How to check if the PNG image loaded into FMX.TBitmap has an alpha channel?

2.2k Views Asked by At

I'm loading PNG images into FMX.Type.TBitmap in Delphi-XE2 Update3 FireMonkey HD application. How do I check if loaded PNG image has an alpha channel or not?

Currently if I load an image with an alpha channel it has alpha info in Bitmap.Scanline[Y]^[X] in a form of $AABBGGRR. However if I load PNG image without alpha the said record has only $00BBGGRR entries (AA = 0), just like an image with clear alpha. Hence the problem - how to determine if it is RGBA image with the alpha fully transparent or it is a RGB image (in this case I will process it to make the alpha fully opaque). Note: Checking through all pixels is not an option.

FMX TBitmap has no PixelFormat property, nor I could find HasAlpha flag.

2

There are 2 best solutions below

2
On BEST ANSWER

You're probably not going to like this.

All bitmaps in FMX are 32-bit, and they are loaded and saved using code from the OS, which is all 32-bit.

So, the real answer is that all bitmaps have an alpha channel.

But, what you really want to know is whether the bitmap uses the alpha channel, and the only way to tell this would be to iterate over every pixel and see if any have an alpha channel which is <> 255.

I would recommmend something like the following (untested):

function TBitmap.IsAlpha(Bitmap: TBitmap): Boolean;
var
  I, j: Integer;
  Bits: PAlphaColorRecArray;
begin
  Bits := PAlphaColorRecArray(StartLine);
  for j := 0 to Height - 1 do
    for I := 0 to Width - 1 do
    begin
      if Bits[I + (j * Width)].A <> 255 then
      begin
        Result := True;
        EXIT;
      end;
    end;
  Result := False;
end;
0
On

Following function checks if a PNG file has a transparency channel. This is easy, since the main PNG header has a fixed length and the data information block IHDR must be the first occurring block.

function PngHasAlphaLayer(f: String): Boolean;
var
  fs: TFileStream;
  colorType: Byte;
begin
  fs := TFileStream.Create(f, fmOpenRead);
  fs.Position := 25;
  fs.Read(colorType, 1);
  fs.Free;
  Result := colorType and (1 shl 2) <> 0;
end;

So it is stored in the 26th byte (or 0x19 as hex), in the 3rd bit.

However, this function does not check for a valid file structure for simplicity reasons. So it should be used after the PNG image has been loaded to TBitmap and then its boolean value for transparency support could be stored e. g. in the Tag property of TImage (or wherever you want).