Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi, GR32 + PngObject: converting to Bitmap32 doesn't work as expected

I'm using GR32 for drawing multiple semi-transparent PNG images. So far I've been using the following method:

  png:= TPNGObject.Create;
  png.LoadFromFile(...);
  PaintBox321.Buffer.Canvas.Draw(120, 20, png);

however I wanted to switch to the method proposed on GR32 website (http://graphics32.org/wiki/FAQ/ImageFormatRelated) :

  tmp:= TBitmap32.Create;
  LoadPNGintoBitmap32(tmp, ..., foo);
  tmp.DrawMode:= dmBlend;
  PaintBox321.Buffer.Draw(Rect(20, 20, 20+ tmp.Width, 20+tmp.Height),
   tmp.ClipRect, tmp);

While the first method works perfectly fine, the second - which should give the same result - causes very strange problem with alpha channel, see the image (which also shows comparison to the same image "arranged" in Paint.NET - both background and icon were opened on the layers of the editor). The image depicts that the Bitmap32 is loaded or drawn inproperly. Any tips?

Problem with TBitmap32 alpha channel

-- added 22 Nov

I've found out that it is not about drawing, it's about loading PNG to BMP32. Saving back from BMP32 to PNG generates the incorrect, "whitened" (the one on the left) PNG image.

like image 436
migajek Avatar asked Nov 21 '11 14:11

migajek


1 Answers

The reason seems to be that the transparency is applied two times to the image when loaded with LoadPNGintoBitmap32, giving it a more transparent and greyish look (more on this later).

First the transparency:

This is code from the original LoadPNGintoBitmap32, the critical parts are marked with comments:

 PNGObject := TPngObject.Create;
 PNGObject.LoadFromStream(srcStream);

 destBitmap.Assign(PNGObject);  // <--- paint to destBitmap's canvas with transparency (!)
 destBitmap.ResetAlpha;         

 case PNGObject.TransparencyMode of  // <--- the following code sets the transparency again for the TBitmap32
 { ... }

The destBitmap.Assign internally does the same as you in your previous approach: it let's the PNG image paint itself to its canvas. This operation respects the alpha channel of the PNG. But this is not necessary, since the alpha channel is assigned to TBitmap32's pixels in a second step!

Now change the code as follows, critical parts are again marked with comments:

 PNGObject := TPngObject.Create;
 PNGObject.LoadFromStream(srcStream);

 PNGObject.RemoveTransparency;  // <--- paint PNG without any transparency...
 destBitmap.Assign(PNGObject);  // <--- ...here
 destBitmap.ResetAlpha;

 srcStream.Position:=0;
 PNGObject.LoadFromStream(srcStream); // <--- read the image again to get the alpha channel back

 case PNGObject.TransparencyMode of   // <--- this is ok now, the alpha channel now only exists in the TBitmap32
 { ... }

The above solution is inefficient because it reads the image twice. But it shows why your second approach produces a more transparent image.

And for the greyishness: There is one more problem in the original code: destBitmap.Assign first fills the background with clWhite32, then paints the image transparently onto it. And then LoadPNGintoBitmap32 comes and adds another layer of transparency on top of it.

like image 141
Heinrich Ulbricht Avatar answered Sep 28 '22 07:09

Heinrich Ulbricht