1

I have a little problem with PNG format. To read and display PNG files I use GraphicEx library by Mike Lischke (got it there). All was good before I decided to draw PNG file with transparent background.
I use this code to load and draw PNG on form's canvas:

procedure TForm1.aButton1Click(Sender: TObject);
var
  PNGGraph: GraphicEx.TPNGGraphic;
begin
  PNGGraph := GraphicEx.TPNGGraphic.Create;

  PNGGraph.PixelFormat := pf32bit; - added code line

  PNGGraph.LoadFromFile('demo.png');
  Form1.Canvas.Draw(10, 10, PNGGraph);
  PNGGraph.Free;
end;

What I get you can see on a picture below:
png without premultiplied alpha

After hours searching in Internet, I found that I should multiple alpha channel. I get some code from here (Mike Sutton's answer): Fade in an alpha-blended PNG form in Delphi

procedure PreMultiplyBitmap(Bitmap: TBitmap);
var
  Row, Col: integer;
  p: PRGBQuad;
  PreMult: array[byte, byte] of byte;
begin
  // precalculate all possible values of a*b
  for Row := 0 to 255 do
    for Col := Row to 255 do
    begin
      PreMult[Row, Col] := Row*Col div 255;
      if (Row <> Col) then
        PreMult[Col, Row] := PreMult[Row, Col]; // a*b = b*a
    end;

  for Row := 0 to Bitmap.Height-1 do
  begin
    Col := Bitmap.Width;
    p := Bitmap.ScanLine[Row];
    while (Col > 0) do
    begin
      p.rgbBlue := PreMult[p.rgbReserved, p.rgbBlue];
      p.rgbGreen := PreMult[p.rgbReserved, p.rgbGreen];
      p.rgbRed := PreMult[p.rgbReserved, p.rgbRed];
      inc(p);
      dec(Col);
    end;
  end;
end;

Using this code I got a little odd result:
enter image description here

The picture above has black background and in the same time looks almost as an original image.

On a picture below you can see an original PNGimage:
enter image description here

So, my question is: how to draw PNG file correctly with transparency and without black background?

I looked into GraphicEx's units, but can't get enough info about my question. Can't believe that such serious graphic library as GraphicEx is not able to draw PNG files without any troubles.

P.S.
Bitmap property Transparent doesn't work properly - black background still on a picture.

Thanks to everyone who can give me advice!

EDIT
When I set PixelFormat = pf32bit, it makes bitmap 'broken' visually.
Picture below demonstrates this effect:
Artifacts on a bitmap

Community
  • 1
  • 1
Josef Švejk
  • 1,047
  • 2
  • 12
  • 23
  • maybe [this](http://stackoverflow.com/questions/32266312/transparent-png-to-tbitmap32) may help – fantaghirocco Jul 29 '16 at 15:00
  • @fantaghirocco, thank you for link, but that was not helpful. Graphics32 too large for me. GraphicEx seems more elegant. So I still looking for answer on my question. – Josef Švejk Jul 29 '16 at 15:15
  • 1
    Delphi supports PNG out of the box. Why fight with third party libraries unless you need some extra functionality? – David Heffernan Jul 29 '16 at 15:51
  • Does the target bitmap have the 32bit RGBA format? – Mike Lischke Jul 30 '16 at 10:19
  • @David Heffernan, unfortunately, I use Delphi 2005 and I have no abilities to update it. I think GraphicEx is more cheapest way to have a PNG support in this condition. – Josef Švejk Jul 30 '16 at 16:32
  • @Mike Lischke, if you meant did I set PixelFormat to pf32bit, I did it. But it causes strange artifacts on a bitmap. So the problem is still there. – Josef Švejk Jul 30 '16 at 16:36
  • You could use pngimage or whatever the library is called – David Heffernan Jul 30 '16 at 17:11
  • @David Heffernan, perhaps I will use another libary to get PNG support in applications. But I want to find an answer for my question. It could be helpful for those who stuck with the same trouble as mine. – Josef Švejk Jul 30 '16 at 17:43

1 Answers1

2

The problem is that Mike's PNG graphic doesn't support drawing transparency.

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
    g: TGraphic;
begin
    g := TPNGGraphic.Create;
    g.LoadFromFile('D:\Temp\FolderOpen_48x48_72.png');
    PaintBox1.Canvas.Draw(0, 0, g);
end;

Comes out without the alpha channel being taken into account:

enter image description here

TPNGObject

For Delphi 2005 use can use Gustavo Daud's pngdelphi library (It is the class that was later absorbed into Delphi). It fully supported drawing with alpha blending:

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
    g: TGraphic;
begin
//  g := TPNGGraphic.Create;
    g := TPNGObject.Create;
    g.LoadFromFile('D:\Temp\FolderOpen_48x48_72.png');
    PaintBox1.Canvas.Draw(0, 0, g);
end;

It draws correctly:

enter image description here

Windows Imaging Component

I don't know when Borland added Windows Imaging Component (WIC) to Delphi. But in Delphi 5 i translated the headers myself, and created a TGraphic that uses WIC to perform all the work: TWicGraphic:

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
    g: TGraphic;
begin
//  g := TPNGGraphic.Create;
//  g := TPNGObject.Create;
    g := TWicGraphic.Create;
    g.LoadFromFile('D:\Temp\FolderOpen_48x48_72.png');
    PaintBox1.Canvas.Draw(0, 0, g);
end;

It also paints correctly:

enter image description here

GDI+

There's also GDI+. I also don't know when Borland added support for GDI+ to Delphi. But in Delphi 5 i translated GDI+ myself and created a TGraphic that uses GDI+ for all the work, TGDIPlusGraphic:

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
    g: TGraphic;
begin
//  g := TPNGGraphic.Create;
//  g := TPNGObject.Create;
//  g := TWicGraphic.Create;
    g := TGDIPlusGraphic.Create;
    g.LoadFromFile('D:\Temp\FolderOpen_48x48_72.png');
    PaintBox1.Canvas.Draw(0, 0, g);
end;

it also draws correctly:

enter image description here


But to answer your question: You cannot. Not without re-writing Mike's TPNGGraphic to support the alpha channel.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 1
    thank you very much for your contribution! Few days ago I have got PngImage unit and use it to load and display *.png files. Your answer is well illustrated. Suppose it will helpful for others who will come with the same question as mine) – Josef Švejk Aug 25 '16 at 14:11