Recent

Author Topic: Broken example "Creating and drawing a transparent bitmap for a TImage" in Linux  (Read 5756 times)

jipété

  • Full Member
  • ***
  • Posts: 182
Hello,

Running a Linux-Debian 12.5 64bits gtk2 computer, if I try the example https://wiki.freepascal.org/Developing_with_Graphics#Creating_and_drawing_a_transparent_bitmap_for_a_TImage using Copy-and-Paste, the only display I get is nothing in the TImage, due to the setup of Image1.Transparent to True (read it 3 lines above the example).
If set to False, the TImage is black.
Someone told me that the same example works fine in Windows : see img

A little tip : I've added two lines :
Code: Pascal  [Select][+][-]
  1. ...
  2.     img := bmp.CreateIntfImage;
  3.     if bmp.PixelFormat = pf32bit then Caption := 'ok 32'; // line added, seen the word
  4. ...
  5.       finally
  6.         cnv.Free;
  7.       end;
  8.       bmp.LoadFromIntfImage(img);
  9.       if bmp.PixelFormat = pf32bit then ShowMessage('ok 32'); // line added, message NOT seen
  10. ...
  11.  

Another help with bmp.SaveToFile('a_path') shows a black bitmap.

Thanks a lot for your help.
« Last Edit: May 23, 2024, 06:46:10 pm by jipété »

wp

  • Hero Member
  • *****
  • Posts: 12471
Re-tested on gtk2, gtk3 and qt5: Sample working correctly (except for gtk3 where the red and blue channels are exchanged, but that's another issue).

the only display I get is nothing in the TImage, due to the setup of Image1.Transparent to True (read it 3 lines above the example).
If set to False, the TImage is black.
Sorry, this is a left-over from the long history of this article... Added some clarification notes. The code that you copied and pasted does not use the Image.Transparent property (not 100% sure, but I'd even suggest to turn it off in this example). Image.Transparent is a property to control "color-transparency" in which one particular color is declared to be transparent and not painted.

jipété

  • Full Member
  • ***
  • Posts: 182
Hi !

Re-tested on gtk2, gtk3 and qt5: Sample working correctly
With Red-Hat ? Ubuntu ? Suse ? Other ?

The code that you copied and pasted does not use the Image.Transparent property (not 100% sure, but I'd even suggest to turn it off in this example).
I've tried off and on and never seen the beaufiful and colored image, except once at the start of my tests (three or four days ago), at one point, by randomly changing things here and there, I got the pretty image but as I was starting to get tired I didn't think about making a screenshot of the image and code, what a shame...

Thanks a lot for the bug report in my other post.

Handoko

  • Hero Member
  • *****
  • Posts: 5377
  • My goal: build my own game engine using Lazarus
I tested the code on Ubuntu Mate 23.10 GTK2 using Lazarus 3.0 64-bit. The "ok 32" message was fired. See the result on screenshot.png below.

The only thing I couldn't make it works is, the saved bmp did not support transparency. See the saved-image.png below. (to reduce the file size, I converted the bmp to png)

This is the code I used:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Forms, Graphics, StdCtrls, fpImage, fpCanvas, IntfGraphics, ExtCtrls,
  9.   LazCanvas, Dialogs;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Image1: TImage;
  18.     procedure Button1Click(Sender: TObject);
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. { TForm1 }
  29.  
  30. procedure TForm1.Button1Click(Sender: TObject);
  31. var
  32.   bmp: TBitmap;
  33.   img: TLazIntfImage;
  34.   cnv: TLazCanvas;
  35. begin
  36.   bmp := TBitmap.Create;
  37.   try
  38.     bmp.PixelFormat := pf32Bit;           // IMPORTANT!
  39.     bmp.SetSize(Image1.Width, Image1.Height);
  40.     bmp.Transparent := True;
  41.     bmp.TransparentColor := clBlack;
  42.     bmp.Clear;
  43.     bmp.TransparentColor := clBlack;
  44.     bmp.Transparent := True;
  45.     img := bmp.CreateIntfImage;
  46.     try
  47.       cnv := TLazCanvas.Create(img);
  48.       try
  49.         cnv.DrawingMode := dmAlphaBlend;  // This activates the alpha-blend mode.
  50.  
  51.         // Background
  52.         cnv.Pen.Style := psClear;
  53.         cnv.Brush.FPColor := colTransparent;
  54.         cnv.FillRect(0, 0, img.Width, img.Height);
  55.  
  56.         // Yellow opaque rectangle
  57.         cnv.Brush.FPColor := FPColor($FFFF, $FFFF, 0);
  58.         cnv.Rectangle(10, 10, 190, 100);
  59.  
  60.         // Overlapping semi-transparent red circle
  61.         cnv.Brush.FPColor := FPColor($FFFF, 0, 0, $4000);
  62.         cnv.Ellipse(60, 60, 140, 140);
  63.  
  64.         // Overlapping semi-transparent blue circle
  65.         cnv.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
  66.         cnv.Ellipse(0, 100, 100, 200);
  67.       finally
  68.         cnv.Free;
  69.       end;
  70.  
  71.       bmp.LoadFromIntfImage(img);
  72.       if bmp.PixelFormat = pf32bit then ShowMessage('ok 32');
  73.       bmp.SaveToFile('Test.bmp');
  74.       Image1.Picture.Assign(bmp);
  75.     finally
  76.       img.Free;
  77.     end;
  78.   finally
  79.     bmp.Free;
  80.   end;
  81. end;
  82.  
  83. end.

Anyone if you want to help, please the download the code, run it and report back your test result.
« Last Edit: May 23, 2024, 08:10:04 pm by Handoko »

Fred vS

  • Hero Member
  • *****
  • Posts: 3414
    • StrumPract is the musicians best friend
I tested the code on Ubuntu Mate 23.10 GTK2 using Lazarus 3.0 64-bit. The "ok 32" message was fired. See the result on screenshot.png below.

The only thing I couldn't make it works is, the saved bmp did not support transparency. See the saved-image.png below. (to reduce the file size, I converted the bmp to png)

This is the code I used:
...
Anyone if you want to help, please the download the code, run it and report back your test result.

Hello Handoko.

On Xubuntu 22.04 x86_64.

In your code, adding this gives a Test2.png with transparency (but only with png files, bmp afaik is not champion of transparency things).
But strangely Test.png is without transparency.
 
Code: Pascal  [Select][+][-]
  1.     ....
  2.       bmp.LoadFromIntfImage(img);
  3.       if bmp.PixelFormat = pf32bit then ShowMessage('ok 32');
  4.       bmp.SaveToFile('Test.png');
  5.       Image1.Picture.Assign(bmp);
  6.       Image1.Picture.SaveToFile('Test2.png');   // Adding this gives transparency      
  7.      ....

« Last Edit: May 23, 2024, 08:52:58 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

wp

  • Hero Member
  • *****
  • Posts: 12471
With Red-Hat ? Ubuntu ? Suse ? Other ?
What a mess... The initial test was with Mint / Laz-main / FPC3.2.2 - everything was fine with gtk2, qt5 (and gtk3 with the exception of red-blue order).

Then I switched to Manjaro: gtk2 - black image as reported, but: qt5 - ok, gtk3 - "half-ok" with red-blue exchanged.

Some more experiments in Manjaro/gtk2:
  • Filled the bitmap with white color before creating the intfimage -> I see the expected image, but on a white background. The same image is returned when I leave the bitmap untouched but set the IntfImg's backgroud color to colWhite = ($FFFF, FFFF, FFFF, FFFF). When I set the alpha channel (the last $FFFF) to 0 the background turns black, but the circles and the rectangle remain visible.
  • Taking the code from the previous experiment, I switched the Image.Transparent property to true. Now the image becomes "color-transparent" - everything what was black in the prvious image becomes transparent. OK? No, because the areas where the semitransparent circles overlap still have the black background below and look too dark.
  • Knowing that a png file can be displayed correctly with alpha channel I wrote the generated image to a stream and read it back - same result: black background with embedded circles and rectangle.

jipété

  • Full Member
  • ***
  • Posts: 182
Hello,

@Handoko : with your code using Copy/Paste,
with Image1.Transparent set at True, nothing displayed on the form ;
with Image1.Transparent set at False, black is shown.
In both cases, test.bmp is black.

@Fred : with your added line,
with Image1.Transparent set at True, nothing displayed on the form ;
with Image1.Transparent set at False, black is shown.
In both cases, test2.png is black.

@wp :
>>> Filled the bitmap with white color before creating the intfimage
I'll be happy to read your  code, just to be sure I'll do the same as you.

Anyway, this story becomes a nightmare...
Maybe there is something wrong in my computer but what ? Where ?
See you later, thanks for your help.

Thaddy

  • Hero Member
  • *****
  • Posts: 16196
  • Censorship about opinions does not belong here.
Can it be that the wrong transparency pixel is picked up, because of the rounded edges from the title bar? Because that corner is black!
If I smell bad code it usually is bad code and that includes my own code.

wp

  • Hero Member
  • *****
  • Posts: 12471
@wp :
>>> Filled the bitmap with white color before creating the intfimage
I'll be happy to read your  code, just to be sure I'll do the same as you.
I am attaching a full project, ready for the compiler, so that you can test easily. It comes with build modes for gtk2, gtk3, qt5 and windows, gtk2 pre-selected. It creates the alpha-blended image of the wiki article in two ways:
  • Button "Create image as LazIntfImage" works with a TLazIntfImage, like in the wiki. As already noted several times this works correctly in all widgetsets, except for gtk2 where the entire image turns black (this happens now also on my Mint-VM - strange...). When the "Use white background" checkbox is checked the blackness disappears, the drawing can be seen, however on a white background.
  • Button "Create Image as FPImage" uses the must fundamental fcl-image library to create the alpha-blended drawing. Since this cannot be displayed directly in a TImage (at least to my knowledge) I saved the image to a temporary stream and made the TImage load the image from it - now the result is correct, even on gtk2! 
I'd conclude that something is wrong with TLazIntfImage in gtk2. It definitely is not your hardware.

[EDIT]
Filed a bug report: https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40971
« Last Edit: May 24, 2024, 12:43:03 pm by wp »

jipété

  • Full Member
  • ***
  • Posts: 182
I'd conclude that something is wrong with TLazIntfImage in gtk2. It definitely is not your hardware.
Oh, your project is wonderful !

Works really fine and nice with FPimage, thanks thanks thanks !
(images and more comments later...)

jipété

  • Full Member
  • ***
  • Posts: 182
Hello everybody !

Well, nothing more to say, simply displaying my results with Debian/Gtk2 :

With LazIntfImage, the black window :
LazIntfImage.png

With LazIntfImage and the White Background, that's fine :
LazIntfImage+white_bkg.png

With FPImage, with or without the White Background, the same wonderful result :
FPImage.png

But (because there is always a "but") I've noticed a little rounding error, I think : compare the bottoms of the blue circles, left and round from LazIntfImage, right and flat from FPImage...
little_rounding_error.png see below  :D

If I try the following snippet, the bottom of the circle is ok ;
Code: Pascal  [Select][+][-]
  1.     // Overlapping semi-transparent blue circle
  2.     canv.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
  3. //  canv.Ellipse(0, 100, 100, 200);
  4.     canv.Ellipse(0, 100, 100, 199);
(and I cannot post the fifth image showing the corrected rounding error, due to forum limits, sorry, try yourself)
Two images in one file  :P :
little_rounding_error+error_corrected.png
On the left side the striked text above, on the right side, the left image is made with Bottom @ 200, and the right image is made with Bottom @ 199.

And again, thank's a lot for your time.
Next step, learning FPImage !
« Last Edit: May 24, 2024, 07:50:25 pm by jipété »

wp

  • Hero Member
  • *****
  • Posts: 12471
Ah, I think this is due to a tiny inconsistency in the two drawing routines:

The lower button creates the TFPMemoryImage as 200x200 pixels; since the lower circle reaches down to exactly 200 it is a bit unclear whether the pixels at y=200 are drawn or not - the old question in graphics - search the forum, there has been a recent discussion abou this. Obviously, the last pixel row is not drawn here.

The upper button, on the other hand, creates the TLazIntfImages as large as the TImage component - and this is much larger than 200x200! Therefore, the lower pixel row can be drawn for sure.

Please change the code so that the upper image is 200x200 px as well, and you will see the same clipping effect in both images.

wp

  • Hero Member
  • *****
  • Posts: 12471
  • Button "Create Image as FPImage" uses the must fundamental fcl-image library to create the alpha-blended drawing. Since this cannot be displayed directly in a TImage (at least to my knowledge) I saved the image to a temporary stream and made the TImage load the image from it
This statement is not correct, of course... An FPImage can be assigned to the Picture property of a TImage and this be displayed in a TImage without needing a temporary stream:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button2Click(Sender: TObject);
  2. var
  3.   img: TFPMemoryImage;
  4.   canv: TFPImageCanvas;
  5. begin
  6.   img := TFPMemoryImage.Create(200, 200);
  7.   canv := TFPImageCanvas.Create(img);
  8.   try
  9.     canv.DrawingMode := dmAlphaBlend;  // This activates the alpha-blend mode
  10.  
  11.     // Background
  12.     canv.Pen.Style := psClear;
  13.     canv.Brush.FPColor := colTransparent;
  14.     canv.FillRect(0, 0, img.Width, img.Height);
  15.  
  16.     // Yellow opaque rectangle
  17.     canv.Brush.FPColor := FPColor($FFFF, $FFFF, 0);
  18.     canv.Rectangle(10, 10, 190, 100);
  19.  
  20.     // Overlapping semi-transparent red circle
  21.     canv.Brush.FPColor := FPColor($FFFF, 0, 0, $4000);
  22.     canv.Ellipse(60, 60, 140, 140);
  23.  
  24.     // Overlapping semi-transparent blue circle
  25.     canv.Brush.FPColor := FPColor(0, 0, $FFFF, $8000);
  26.     canv.Ellipse(0, 100, 100, 200);
  27.  
  28.     // Display image
  29.     Image1.Picture.Assign(img);
  30.   finally
  31.     canv.Free;
  32.     img.Free;
  33.   end;
  34. end;

jipété

  • Full Member
  • ***
  • Posts: 182
An FPImage can be assigned to the Picture property of a TImage and this be displayed in a TImage without needing a temporary stream:
Not here !
I still get a black background...

To look at a nice display, the only way (for me) is to use the stream :
Code: Pascal  [Select][+][-]
  1.     ...
  2.     stream := TMemoryStream.Create;
  3.     writer := TFPWriterPNG.Create;
  4.     try
  5.       writer.UseAlpha := True;  // Make sure that the alpha channel is not dropped.
  6.       img.SaveToStream(stream, writer);
  7.       // Save to image file
  8.       img.SaveToFile('Transp_with-stream.png'); // black background !
  9.       stream.Position := 0;
  10.       Image1.Picture.LoadFromStream(stream); // no background, nice !
  11.       Image1.Picture.SaveToFile('Transp_Picture.png'); // also ok
  12.     finally
  13.       writer.Free;
  14.       stream.Free;
  15.     end;
  16.   finally
  17.     canv.Free;
  18.     img.Free;
  19.   end;
  20. end;
And I've discovered a trap : we must look at the created .png in an image editor (Gimp or whatever) because if looking at the images in a FileExplorer, there is no way to distinguish between a white background and a transparent background.
Study my 2 images displayed in a FileExplorer : one with white background on top and the other below with a transparent background.
white-or-none

And compare with the same files in The Gimp
compar_classic-stream.png

Another nightmare...

wp

  • Hero Member
  • *****
  • Posts: 12471
An FPImage can be assigned to the Picture property of a TImage and this be displayed in a TImage without needing a temporary stream:
Not here !
I still get a black background...
Sorry I was confused by another thread (Too many different threads for my limited brain...). You are absoluteley right.

And I've discovered a trap : we must look at the created .png in an image editor (Gimp or whatever) because if looking at the images in a FileExplorer, there is no way to distinguish between a white background and a transparent background.
Study my 2 images displayed in a FileExplorer : one with white background on top and the other below with a transparent background.
white-or-none

And compare with the same files in The Gimp
compar_classic-stream.png
Well, when Gimp displays the checkboard background for an alpha-channel image you know for sure that the alpha channel and the transparency exists and is correct. When other programs do display a white background, it's not the image's fault.

Another nightmare...
I would not call it a "nightmare". Just be prepared that the transparency of images may be a bit difficult to detect. My default image viewer, for example is IrfanView; I set its background to some unusual color; with that it not very likely that I can be fooled about the presence of transparency.

 

TinyPortal © 2005-2018