[SOLVED] Can you reproduce this TBitmap-Bug? (Linux only) lazarus / 39-Graphics ---------------------------------------------------------------------- Hartmut · 2024-08-07 13:59 If you have a Linux OS: please help to test, if you can reproduce this bug:  - compile and run attached project on Linux  - if a graphic image is displayed, then the bug did not occur  - if instead the form is completely gray, then the bug did occur  - if the bug occurs, please uncomment lines 54..57. Does the bug now disapear? Please report your results here and include the detailed version numbers of your Linux OS and your Lazarus installation. Thanks a lot. If the but is reproduceable, I will file a bug report. The attached program is a demo which was created by wp in reply #11 of this Topic: https://forum.lazarus.freepascal.org/index.php/topic,68059.0.html It displays a picture file (demo.png) which is also included in the attached project. I added only 1 line (line 52): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, ComCtrls,  math; const  FileSpec = 'demo.png'; {picture file to show}  Margin = 10; {Margin for background-color in 'clYellow'} type { TForm1 } TForm1 = class(TForm)   PaintBox1: TPaintBox;   ScrollBox1: TScrollBox;   procedure FormDestroy(Sender: TObject);   procedure PaintBox1Paint(Sender: TObject);   procedure showPicture(fspec: string);   procedure FormActivate(Sender: TObject); private   FPicture: TPicture;   FBuffer: TBitmap;   FScalingFactor: Double; end; var  Form1: TForm1; implementation {$R *.lfm} const  MaxFormWidth = 1000;  MaxFormHeight = 800; { TForm1 } procedure TForm1.ShowPicture(FSpec: String);var  w, h, i: Integer;  R: TRect;begin  FPicture.Free; // To prevent memory leak when ShowPicture might be called a second time  FPicture := TPicture.Create;  if FBuffer = nil then FBuffer := TBitmap.Create;   FBuffer.PixelFormat:=pf32bit; // added(*  i:=33; {values < 33 do not work}    // this seems to solve the bug:  FBuffer.SetSize(i,i);  FBuffer.Canvas.Brush.Color:=clBlack;  FBuffer.Canvas.FillRect(0,0,i,i);*)  try    FPicture.LoadFromFile(FSpec);     w := round(FScalingFactor*FPicture.Width) + 2*Margin;    h := round(FScalingFactor*FPicture.Height) + 2*Margin;    Paintbox1.SetBounds(0, 0, w, h);     SetBounds(0, 0, Min(Paintbox1.Width, MaxFormWidth), Min(Paintbox1.Height, MaxFormHeight));     FBuffer.SetSize(w, h);    FBuffer.Canvas.Brush.Color := clYellow;    FBuffer.Canvas.FillRect(0, 0, FBuffer.Width, FBuffer.Height);    R := Rect(Margin, Margin, FBuffer.Width - Margin, FBuffer.Height - Margin);    FBuffer.Canvas.StretchDraw(R, FPicture.Bitmap);  except    on E:Exception do      begin        ShowMessage('Error on loading file!');        FreeAndNil(FPicture);        FreeAndNil(FBuffer);      exit;      end;  end;end; const  Counter: Integer = 0; procedure TForm1.PaintBox1Paint(Sender: TObject);begin  if FBuffer = nil then  exit;   WriteLn('OnPaint ' + IntToStr(Counter));  inc(Counter);   Paintbox1.Canvas.Draw(0, 0, FBuffer);end; procedure TForm1.FormDestroy(Sender: TObject);begin  FPicture.Free;  FBuffer.Free;end; procedure TForm1.FormActivate(Sender: TObject);const  first: boolean = true;begin  if not first then exit;   first:=false;  ScrollBox1.Align:=alClient;  ScrollBox1.BorderStyle:=bsNone;  ScrollBox1.HorzScrollBar.Tracking:=true; {scroll in Realtime: }  ScrollBox1.VertScrollBar.Tracking:=true;   Paintbox1.Left := 0;  Paintbox1.Top := 0;   FScalingFactor := 0.75; {0.75 causes bug, 0.74 and 0.76 work}   ShowPicture(FileSpec); {shows the picture in file 'FileSpec'}end; end. The reason for this line 52 is, that I found out, that the memory consumption with 'pf32bit' is significantly smaller (1 GB less for 'FScalingFactor=14'). After I did this, I got this bug for many FScalingFactor's:  - the bug occurs with values of 0.71, 0.73, 0.75 and so on  - the bug does not occur with values of 0.72, 0.74, 0.76 and so on. This bug only occurs on Linux (Ubuntu 18.04 64-bit) with gtk2, not with qt5. And not on Windows. I tested with:  - Lazarus 3.99 (rev main_3_99-2316-g00f3d3b397) FPC 3.3.1 x86_64-linux-gtk2  - Lazarus 3.4.0 with FPC 3.2.2  - Lazarus 2.2.4 with FPC 3.2.2  - Lazarus 2.0.10 with FPC 3.2.0 I found out, that lines 54..57 seem to be a workaround for this bug. Can you confirm this? ---------------------------------------------------------------------- wp · 2024-08-07 17:15 In Manjaro Linux I can confirm the gray paintbox, but do not observe the crash when the pf32bit line is added. Without this line the bitmap uses a device-specific pixel format. I wonder why pf32bit results in the least memory consumption for you, I would have expected to be highest. BTW, the code that I presented in that other thread is really not very clever since it blows up the input image to a huge buffer bitmap in case of large magnification factor. I think now that it would be better to use the Canvas.CopyRect command which magnifies only the rectangle specified as source. The destination rect, into which the source rect is blown-up, then should be the scrollbox area. You must scale the scrollbox area back into the original image to find the src rect, i.e. divide dimension by your scaling factor. Please try it yourself, I don't have my mind free for this right now, ---------------------------------------------------------------------- Hartmut · 2024-08-08 07:55 Quote from: wp on August 07, 2024, 07:15:43 pmIn Manjaro Linux I can confirm the gray paintbox Thank you wp for testing. Quote... but do not observe the crash when the pf32bit line is added. Maybe we misunderstood here. This Topic here has nothing to do with the crash, which I had for *big* scaling factors > 14 in reply # 12 of https://forum.lazarus.freepascal.org/index.php/topic,68059.0.html QuoteI wonder why pf32bit results in the least memory consumption for you, I would have expected to be highest. I agree. But in the attached screenshot you see the memory consumption in my Linux taskmanager (for scaling factor=14) with the Default = 'pfDevice' in red and with 'pf32bit' in blue. The difference is 1 GB. And the peak at start is higher for 'pfDevice'. QuoteBTW, the code that I presented in that other thread is really not very clever since it blows up the input image to a huge buffer bitmap in case of large magnification factor. I think now that it would be better to use the Canvas.CopyRect command which magnifies only the rectangle specified as source. The destination rect, into which the source rect is blown-up, then should be the scrollbox area. You must scale the scrollbox area back into the original image to find the src rect, i.e. divide dimension by your scaling factor. Please try it yourself, I don't have my mind free for this right now Thank you for that suggestion. I will try if I can realize that. ---------------------------------------------------------------------- Hartmut · 2024-08-08 10:25 Thank you wp for this very detailed informations. I agree that especially the dependency of the scaling factor is very strange. But the fact, that you can solve the problem by uncommenting lines 54..57 lets me assume, that the initialization of Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i FBuffer.PixelFormat:=pf32bit;is not correct. ---------------------------------------------------------------------- iLya2IK · 2024-08-08 16:15 I think the problem is that you delete fpicture before you create it. Try to add assigned-check at line 48 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i if Assigned(FPicture) then FreeAndNil(FPicture); And i advise you to set the pointer fields to nil on creation cause they may be intialized as a garbage on startup. ---------------------------------------------------------------------- marcov · 2024-08-08 16:17 Fields of classes are initialized to zero as per language spec. ---------------------------------------------------------------------- Hartmut · 2024-08-08 16:36 @iLya2IK: Thanks for that suggestion. I replaced line 48 with your command, but it made no difference. As marcov said, fields of classes are filled with zeros on class creation. You can rely on that. @marcov: Thanks for clarification. ---------------------------------------------------------------------- iLya2IK · 2024-08-09 08:25 Yep. This is the bug. Under normal conditions, all scaleFactor variants should show an empty PaintBox, since when creating an instance of gdkpixbuf, all bits in the image mask are zero (the image is completely transparent). But the problem is that gtkwidget, for some reason, uses a certain algorithm to determine whether the image is transparent (whether the mask provided is valid). The mentioned algorithm, it seems to me, was designed incorrectly (gtk2lclintf.inc lines 354, 355). Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i // GraphType.pp (expanded)MaskSize := ((Width +  7) and not PtrUInt(7) * Height) shr 3;// gtk2lclintf.incDivMod(ARawImage.DataSize, ARawImage.MaskSize, ADivResult, ARemainder);CreateWithAlpha := ARemainder = 0;  Thus, all the combinations of heights/widths where the image is shown in the paintbox are the bug. Not the bug - these are those few combinations of heights/widths when the image disappears (it is transparent - CreateWithAlpha = true). ---------------------------------------------------------------------- Hartmut · 2024-08-09 13:13 This sounds very interesting, iLya2IK. Thank you. I will mention in my bug report, that you found the reason, why and where the bug occors. Is this correct? BTW: you have a typo in the filename. I think it must be gtk2lclintf.inc and not gdk2lclintf.inc. Maybe you want to correct this in your post (at 2 places), because I want to reference this post in my bug report. Addendum: What would be a good subject for the bug report? TPaintBox: error in transparent mode detection (Linux gtk2 only) or TBitmap: error in transparent mode detection (Linux gtk2 only) ---------------------------------------------------------------------- iLya2IK · 2024-08-09 17:54 Of course! I don't mind at all if you refer to my post. It's a pity that I didn't have the patience to understand the idea of the developers why this particular check of the size of the mask is performed. In my opinion, it is more logical to describe the bug as TBitmapCanvas: error in transparent mode detection (Linux gtk2 only) ---------------------------------------------------------------------- wp · 2024-08-09 18:17 Title: Stretch draw issue with TBitmap Canvas (gtk2 only) And attach a simpler demo project, something like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.PaintBox1Paint(Sender:TObject);var  bmp: TBitmap;begin  bmp := TBitmap.Create;  try    bmp.PixelFormat := pf32bit;    bmp.SetSize(1000, 1000);    bmp.Canvas.Brush.Color := clRed;    bmp.Canvas.FillRect(0, 0, bmp.Width div 2, bmp.Height);    bmp.Canvas.Brush.Color := clYellow;    bmp.Canvas.FillRect(bmp.Width div 2, 0, bmp.Width, bmp.Height);    Caption := FormatFloat('0.000', bmp.RawImage.DataSize/bmp.RawImage.MaskSize);    Paintbox1.Canvas.StretchDraw(Rect(0, 0, Paintbox1.Width, Paintbox1.Height), bmp);  finally    bmp.Free;  end;end;The bitmap is not drawn when its size is 1000x1000 like in above code (the form caption displays the no-remainder ratio of RawImage.DataSize/.MaskSize), but incrementing width or height by 1 makes the bitmap appear (and DataSize-to-MaskSize ratio is fractional now). Mention issue #8553 in which the code shown by iLya2IK was added. If possible assign the report to Zeljan Rikalo (if you can't I'll do it for you then). ---------------------------------------------------------------------- Hartmut · 2024-08-10 12:32 Thanks a lot wp for that demo. I had prepared a bug report with an own demo, but I will change it to use your demo, because it is much shorter and better. I have a visitor today, so it will be Sunday, when I can file the bug report. BTW: I miss your post, which did exist between replies #2 und #3. There you described detailed how you made your test. Did you delete it? Or is this an issue of the forum software? ---------------------------------------------------------------------- wp · 2024-08-10 14:19 Quote from: Hartmut on August 10, 2024, 02:32:17 pmBTW: I miss your post, which did exist between replies #2 und #3. There you described detailed how you made your test. Did you delete it? Or is this an issue of the forum software? Sorry, I unintentionally deleted it (Touchpad-mouse jumped over from "modify" to "delete", and I did not read the confirmation prompt carefully).) ---------------------------------------------------------------------- Hartmut · 2024-08-11 13:06 I filed a bug report in https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/41070 @wp: can you please assign this report to Zeljan Rikalo? I saw no way to do it. Thanks. ---------------------------------------------------------------------- wp · 2024-08-11 20:04 Done