0

I use Delphi 10.3.3 VCL.

I want to load a PNG image, convert to TBitmap (in order to make some modifications), then save it as PNG.

I use this code, but it loses transparency. Transparent background becomes black.

var
  InputPNG: TPngImage;
  OutputPNG: TPngImage;
  BMP: TBitmap;
begin
  InputPNG  := TPngImage.Create;
  OutputPNG := TPngImage.Create;
  BMP := TBitmap.Create;

  InputPNG.LoadFromFile('C:\input.png');
  BMP.Assign(InputPNG);

  OutputPNG.Assign(BMP);
  OutputPNG.SaveToFile('C:\output.png');

  InputPNG.Free;
  OutputPNG.Free;
  BMP.Free;
end;

How can I modify the code and preserve PNG transparency? Any solutions with free components such as Skia4Delphi are welcome.

Shaun Roselt
  • 1,650
  • 5
  • 18
  • 44
Xel Naga
  • 826
  • 11
  • 28
  • PngComponents (available via GetIt or on https://github.com/UweRaabe/PngComponents) provides a method ConvertToPNG in unit PngFunctions. – Uwe Raabe May 17 '23 at 12:13
  • 1
    Might find a solution here: https://stackoverflow.com/questions/21384491/png-to-bmp-conversion-maintaining-transparency – Sherlock70 May 17 '23 at 12:13

3 Answers3

3

Use a TWICImage to save to file. This will preserve the alpha-channel:

procedure SaveToPng(aBmp: TBitmap; const Filename: string);
var
  wic: TWICImage;
begin
  Assert(aBmp.PixelFormat=pf32bit);
  wic := TWICImage.Create;
  try
    aBmp.AlphaFormat := afDefined;
    wic.Assign(aBmp);
    wic.ImageFormat := wifPng;
    wic.SaveToFile(Filename);
  finally
    wic.Free;
  end;
end;

Be aware that whenever you use VCL.Graphics to assign a png to a bmp, the bitmap will have Alphaformat = afDefined, which means the RGB-channel is multiplied by alpha. If you now modify your bitmap's alphachannel this can lead to unexpected results. I would always set bmp.Alphaformat:=afIgnored before doing any modifications.

Renate Schaaf
  • 295
  • 1
  • 3
  • 9
  • +1 For the often underestimated TWICImage. I loved it back when I did VCL, but sadly, there is no such beast for platform independent programming. – Sherlock70 May 23 '23 at 08:30
2

Try to add this lines before assign the PNG image.

  BMP.PixelFormat := pf32bit; // not sure if this is necessary
  BMP.Transparent := True;
  BMP.Assign(iPNG);
Garada
  • 66
  • 2
0

Use the following code:

InputPNG.AssignTo(BMP);
dwrbudr
  • 607
  • 4
  • 8
  • 1
    `BMP.Assign(InputPNG);` and `InputPNG.AssignTo(BMP);` do the exact same thing, as `TBitmap.Assign(Source)` ends up calling `Source.AssignTo(Self)` for any `Source` that is not a `TBitmap`. – Remy Lebeau May 17 '23 at 18:31