Recent

Author Topic: Artifacts when displaying transparent png in timage  (Read 1800 times)

Jonny

  • Full Member
  • ***
  • Posts: 111
Artifacts when displaying transparent png in timage
« on: February 04, 2025, 03:44:21 pm »
Lazarus 4.99 (rev main_4_99-920-g0d73603378) FPC 3.3.1 x86_64-linux-gtk2

When loading a transparent png file and displaying it in a timage on my form, it produces artifacts all over the image.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. uses
  4.   Interfaces, Classes, Forms, ExtCtrls, FPImage, FPReadPNG;
  5.  
  6. var
  7.   frmMain: TForm;
  8.   imgForm: TImage;
  9.   imgLogo: TFPMemoryImage;
  10.   imgReader: TFPReaderPNG;
  11.  
  12. begin
  13.   Application.Initialize;
  14.   Application.CreateForm(TForm,frmMain);
  15.   frmMain.Width := 600;
  16.   frmMain.Height := 600;
  17.   imgForm := TImage.Create(frmMain);
  18.   imgForm.Parent := frmMain;
  19.   imgForm.Proportional := True;
  20.   imgForm.Stretch := True;
  21.   imgForm.BoundsRect := frmMain.BoundsRect;
  22.   try
  23.     imgReader := TFPReaderPNG.Create;
  24.     imgLogo := TFPMemoryImage.Create(0,0);
  25.     imgLogo.LoadFromFile('test.png',imgReader);
  26.     imgForm.Transparent := True; // clean without but no transparency
  27.     imgForm.Picture.Assign(imgLogo);
  28.   finally
  29.     imgReader.Free;
  30.     imgLogo.Free;
  31.   end;
  32.   Application.Run;
  33. end.
  34.  

Should I be doing something to handle the transparency?
« Last Edit: February 04, 2025, 10:25:28 pm by Jonny »

wp

  • Hero Member
  • *****
  • Posts: 12622
Re: Artifacts when displaying transpartent png in timage
« Reply #1 on: February 04, 2025, 06:00:40 pm »
An unusual way to create an LCL application...

Normally, I do this:
  • In Lazarus, I create a new LCL project ("File" > "New" > "Project" > "Application")
  • Drop a TImage component on the newly created form
  • To reproduce the settings in your posted project, use the Object Inspector and set Form1.Width = 600, Form1.Height = 600,  Image1.Align = alClient, Image1.Stretch = true (I'd also set Image1.Proportional = true to keep the aspect ratio when the image size changes)
  • Click on the '...' next to Image1.Picture and load the image to be displayed
  • Voila - ready: You see the image in the form, correctly, no artefacts
When you do it your way, maybe some initialization is missing, I don't know and don't want to investigate, because I do not want to motivate you to create LCL applications this way.

The Transparent property is meant for old color-transparency of bitmaps: all pixels having the "TransparentColor" (color of the top/left - or bottom/left? - pixel of the image are not painted when Transparent is true. But you have true alpha-channel transparency in the png image, and the Transparent property is not needed, maybe even harmful.

To convince yourself that the image really is transparent, change the Color property of the form - this color will be visibile through the transparent parts of the loaded image. Or draw a gradient onto the form: Click on the '...' next to the OnPaint property of the form and add the following code to the newly created procedure Form1Paint:
Code: Pascal  [Select][+][-]
  1. procedure procedure TForm1.FormPaint(Sender: TObject);
  2. begin
  3.   Canvas.GradientFill(Rect(0, 0, Width, Height), clRed, clYellow, gdVertical);
  4. end;

I adding this modified project as a attachment.

Maybe I should also mention that a transparent picture loaded into a TImage is always transparent to the form, but not to the desktop!
« Last Edit: February 04, 2025, 06:03:59 pm by wp »

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transpartent png in timage
« Reply #2 on: February 04, 2025, 06:34:10 pm »
Quote from: wp
An unusual way to create an LCL application...

Apologies, I created a compact and minimal project to quickly identify the issue.

Quote from: wp
  • Click on the '...' next to Image1.Picture and load the image to be displayed

My source image will either be a TFPMemoryImage that I generate myself or an external png file supplied after the program is already compiled and running. I am afraid that I cannot preload the image using the method that you suggested,

Quote from: wp
When you do it your way, maybe some initialization is missing, I don't know and don't want to investigate, because I do not want to motivate you to create LCL applications this way.

Don't worry, I am not creating LCL methods that way. It was just to demonstrate the issue, taken from a much, much larger program, in the minimal amount of lines.

Your lfm contains:

Code: Pascal  [Select][+][-]
  1.   object Image1: TImage
  2.     Left = 0
  3.     Height = 600
  4.     Top = 0
  5.     Width = 600
  6.     Align = alClient
  7.     Picture.Data = {
  8.       175450...
  9.     }
  10.     Stretch = True
  11.   end
  12.  

I see no additional initialisations there (but I am interested in how the Picture.Data is created)..

Quote from: wp
To convince yourself that the image really is transparent

I am convinced, thanks, your explanations are always clear, especially with your examples.

Quote from: wp
Maybe I should also mention that a transparent picture loaded into a TImage is always transparent to the form, but not to the desktop!

I think that I kinda understand the distinction.

Looks like the issue is copying the TFPMemoryImage to the TImage. Is there an alternative method to using TImage.Picture.Assign(TFPMemoryImage) which I can try?

Thaddy

  • Hero Member
  • *****
  • Posts: 16580
  • Kallstadt seems a good place to evict Trump to.
Re: Artifacts when displaying transpartent png in timage
« Reply #3 on: February 04, 2025, 06:41:38 pm »
To me it just looks like an unfortunate choice of the transparancy pixel.
But I am sure they don't want the Trumps back...

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transpartent png in timage
« Reply #4 on: February 04, 2025, 06:54:09 pm »
My TFPMemoryImage has an alpha channel rather than using a pixel for transparency - not sure why alpha is not being respected.

Thaddy

  • Hero Member
  • *****
  • Posts: 16580
  • Kallstadt seems a good place to evict Trump to.
Re: Artifacts when displaying transpartent png in timage
« Reply #5 on: February 04, 2025, 06:58:54 pm »
Quote
My TFPMemoryImage has an alpha channel rather than using a pixel for transparency - not sure why alpha is not being respected.
As far as I know the alpha channel still relies on a pixel in the main color palate....
But I am sure they don't want the Trumps back...

wp

  • Hero Member
  • *****
  • Posts: 12622
Re: Artifacts when displaying transpartent png in timage
« Reply #6 on: February 04, 2025, 07:17:27 pm »
As I wrote, set the color of the form to, say, yellow, run your program with the line "imgForm.Transparent := true" commented out, and see the yellow background --> the image IS rendered transparently, and now - since Transparent is false - with transparency taken from the alpha-channel.
Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. uses
  4.   Interfaces, Classes,
  5.   Graphics,    // <--- must be added for having "clYellow"
  6.   Forms, ExtCtrls, FPImage, FPReadPNG;
  7.  
  8. var
  9.   frmMain: TForm;
  10.   imgForm: TImage;
  11.   imgLogo: TFPMemoryImage;
  12.   imgReader: TFPReaderPNG;
  13.  
  14. begin
  15.   Application.Initialize;
  16.   Application.CreateForm(TForm,frmMain);
  17.   frmMain.Width := 600;
  18.   frmMain.Height := 600;
  19.   frmMain.Color := clYellow;
  20.   imgForm := TImage.Create(frmMain);
  21.   imgForm.Parent := frmMain;
  22.   imgForm.Proportional := True;
  23.   imgForm.Stretch := True;
  24.   imgForm.BoundsRect := frmMain.BoundsRect;
  25.   try
  26.     imgReader := TFPReaderPNG.Create;
  27.     imgLogo := TFPMemoryImage.Create(0,0);
  28.     imgLogo.LoadFromFile('test.png',imgReader);
  29.     //imgForm.Transparent := True;
  30.     imgForm.Picture.Assign(imgLogo);
  31.   finally
  32.     imgReader.Free;
  33.     imgLogo.Free;
  34.   end;
  35.   Application.Run;
  36. end.

Since your application is an LCL application (you are using TImage!) you can load the png file by the simpler LCL procedures in the Graphics unit:
Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. uses
  4.   Interfaces, Classes, Graphics,
  5.   Forms, ExtCtrls;
  6.  
  7. var
  8.   frmMain: TForm;
  9.   imgForm: TImage;
  10.  
  11. begin
  12.   Application.Initialize;
  13.   Application.CreateForm(TForm,frmMain);
  14.   frmMain.Width := 600;
  15.   frmMain.Height := 600;
  16.   frmMain.Color := clYellow;
  17.   imgForm := TImage.Create(frmMain);
  18.   imgForm.Parent := frmMain;
  19.   imgForm.Proportional := True;
  20.   imgForm.Stretch := True;
  21.   imgForm.BoundsRect := frmMain.BoundsRect;
  22.   imgForm.Picture.LoadFromFile('test.png');
  23.   Application.Run;
  24. end.

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transpartent png in timage
« Reply #7 on: February 04, 2025, 07:35:22 pm »
Quote from: wp
As I wrote, set the color of the form to, say, yellow, run your program with the line "imgForm.Transparent := true" commented out, and see the yellow background --> the image IS rendered transparently, and now - since Transparent is false - with transparency taken from the alpha-channel.

I compiled with your modifications but did not see the yellow. But not to doubt you, I thought, what could be different between us?

My current builds are with the GTK2 widgetset.

So I tried with QT5, QT6 and cross compiled with Win32. All worked correctly - the yellow background was there.

Therefore it looks like a bug in the LCL - or do I need to initialise somehow differently?


TRon

  • Hero Member
  • *****
  • Posts: 4003
Re: Artifacts when displaying transpartent png in timage
« Reply #8 on: February 04, 2025, 07:50:17 pm »
My current builds are with the GTK2 widgetset.
It is no problem to reproduce the issue (GTK2/laz 3.6).

Quote
Therefore it looks like a bug in the LCL - or do I need to initialise somehow differently?
You could try workaround it using the memorystream trick discussed earlier the other thread (I haven't checked yet)
« Last Edit: February 04, 2025, 07:57:24 pm by TRon »
I do not have to remember anything anymore thanks to total-recall.

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transpartent png in timage
« Reply #9 on: February 04, 2025, 08:08:43 pm »
Quote from: TRon
It is no problem to reproduce the issue (GTK2/laz 3.6).

Sorry, it is unclear, are you saying that you can or cannot reproduce the issue?

Quote from: TRon
You could try workaround it using the memorystream trick discussed earlier the other thread (I haven't checked yet)

Indeed, I have been toying with that for a while but have had no luck.

TRon

  • Hero Member
  • *****
  • Posts: 4003
Re: Artifacts when displaying transpartent png in timage
« Reply #10 on: February 04, 2025, 08:12:40 pm »
Sorry, it is unclear, are you saying that you can or cannot reproduce the issue?
I can reproduce. I attached an image to my previous post for illustration.

Quote
Indeed, I have been toying with that for a while but have had no luck.
Also if you load the picture using the 2nd method that wp showed ? e.g. imgForm.Picture.LoadFromStream(MyMemoryStream);

fwiw: From the results it is clear that whatever is responsible does not know how to properly handle the alpha channel.
« Last Edit: February 04, 2025, 08:26:57 pm by TRon »
I do not have to remember anything anymore thanks to total-recall.

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transpartent png in timage
« Reply #11 on: February 04, 2025, 08:49:13 pm »
Quote from: TRon
I can reproduce. I attached an image to my previous post for illustration.

Aha, you must have added it afterwards, your image showed the artifacts, @wp had stated that was because Transparent property was harmful with png images.

It is the issue with GTK2 not displaying transparency but QT5, QT6 and Win32 working correctly, that I am now trying to resolve.

Quote from: TRon
Also if you load the picture using the 2nd method that wp showed ? e.g. imgForm.Picture.LoadFromStream(MyMemoryStream);

fwiw: From the results it is clear that whatever is responsible does not know how to properly handle the alpha channel.

OK, I shall try to pass it through a TMemoryStream next. Does this mean the memory requirements will spike again? I am trying to be conservative with resources.

TRon

  • Hero Member
  • *****
  • Posts: 4003
Re: Artifacts when displaying transpartent png in timage
« Reply #12 on: February 04, 2025, 08:59:04 pm »
Aha, you must have added it afterwards, your image showed the artifacts, @wp had stated that was because Transparent property was harmful with png images.
Yes, but I consider it a bug. Alpha is indeed not the same as transparency but if you know that then the alpha channel values should be converted. And in case asking how, then this is not our problem but that of how things are (currently) implemented. Might be a restriction of/issue with GTK2 though, I honestly don't know.

Quote from: TRon
Does this mean the memory requirements will spike again? I am trying to be conservative with resources.
Unfortunately, yes. But, for now at least, also a bit besides the point. First try make it work then see if we can figure out what the best option would be (in case possible and depending on projects preferences).
I do not have to remember anything anymore thanks to total-recall.

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transparent png in timage
« Reply #13 on: February 04, 2025, 10:46:34 pm »
Still the same when passing through a stream - GTK2 TImage is not drawing transparency.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. uses
  4.   Interfaces, Classes, Forms, ExtCtrls, FPImage, FPReadPNG, FPWritePNG;
  5.  
  6. var
  7.   frmMain: TForm;
  8.   imgForm: TImage;
  9.   imgLogo: TFPMemoryImage;
  10.   imgStream: TMemoryStream;
  11.   imgReader: TFPReaderPNG;
  12.   imgWriter: TFPWriterPNG;
  13.  
  14. begin
  15.   Application.Initialize;
  16.   Application.CreateForm(TForm,frmMain);
  17.   frmMain.Width := 600;
  18.   frmMain.Height := 600;
  19.   frmMain.Color := $00e0e0;
  20.   imgForm := TImage.Create(frmMain);
  21.   imgForm.Parent := frmMain;
  22.   imgForm.Proportional := True;
  23.   imgForm.Stretch := True;
  24.   imgForm.BoundsRect := frmMain.BoundsRect;
  25.   try
  26.     imgReader := TFPReaderPNG.Create;
  27.     imgWriter := TFPWriterPNG.Create;
  28.     imgLogo := TFPMemoryImage.Create(0,0);
  29.     imgStream := TMemoryStream.Create;
  30.  
  31.     imgLogo.LoadFromFile('test.png',imgReader);
  32.     imgLogo.SaveToStream(imgStream,imgWriter);
  33.  
  34.     imgStream.Position := 0;
  35.     imgForm.Picture.LoadFromStream(imgStream);
  36.  
  37.     imgWriter.UseAlpha := True;
  38.     imgLogo.SaveToFile('out.png',imgWriter);
  39.   finally
  40.     imgWriter.Free;
  41.     imgReader.Free;
  42.     imgLogo.Free;
  43.   end;
  44.   Application.Run;
  45. end.
  46.  

Jonny

  • Full Member
  • ***
  • Posts: 111
Re: Artifacts when displaying transparent png in timage
« Reply #14 on: February 04, 2025, 11:02:33 pm »
I readded the TImage.Transparent property, fed the image through a TMemoryStream and now GTK2 works....

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. uses
  4.   Interfaces, Classes, Forms, ExtCtrls, FPImage, FPReadPNG, FPWritePNG;
  5.  
  6. var
  7.   frmMain: TForm;
  8.   imgForm: TImage;
  9.   imgLogo: TFPMemoryImage;
  10.   imgStream: TMemoryStream;
  11.   imgReader: TFPReaderPNG;
  12.   imgWriter: TFPWriterPNG;
  13.  
  14. begin
  15.   Application.Initialize;
  16.   Application.CreateForm(TForm,frmMain);
  17.   frmMain.Width := 600;
  18.   frmMain.Height := 600;
  19.   frmMain.Color := $00e0e0;
  20.   imgForm := TImage.Create(frmMain);
  21.   imgForm.Parent := frmMain;
  22.   imgForm.Proportional := True;
  23.   imgForm.Stretch := True;
  24.   imgForm.BoundsRect := frmMain.BoundsRect;
  25.   imgForm.Transparent := True; // <---- Make TImage transparent
  26.  
  27.   try
  28.     imgReader := TFPReaderPNG.Create;
  29.     imgWriter := TFPWriterPNG.Create;
  30.     imgLogo := TFPMemoryImage.Create(0,0);
  31.     imgStream := TMemoryStream.Create;
  32.  
  33.     imgLogo.LoadFromFile('test.png',imgReader);
  34.     imgLogo.SaveToStream(imgStream,imgWriter);
  35.  
  36.     imgStream.Position := 0;
  37.     imgForm.Picture.LoadFromStream(imgStream); // <---- Pass image through stream
  38.  
  39.     imgWriter.UseAlpha := True;
  40.     imgLogo.SaveToFile('out.png',imgWriter);
  41.   finally
  42.     imgWriter.Free;
  43.     imgReader.Free;
  44.     imgLogo.Free;
  45.   end;
  46.   Application.Run;
  47. end.
  48.  

So confused - is this a bug then?

 

TinyPortal © 2005-2018