[SOLVED] Screenshot shows only a part of the monitor lazarus / 39-Graphics ---------------------------------------------------------------------- Hartmut · 2024-05-21 11:18 I use the following code, which shall take a screenshot of the whole monitor: 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 uses Graphics, LCLType, LCLIntf; procedure make_screenshot_PNG(filespec: string);   {creates a screenshot and saves it into a PNG-file}   var PNG: TPortableNetworkGraphic;       ScreenDC: HDC; {= THandle}   begin   ScreenDC:=GetDC(0);   PNG:=TPortableNetworkGraphic.Create;   try      PNG.LoadFromDevice(ScreenDC);      PNG.SaveToFile(filespec);   finally      PNG.Free;      ReleaseDC(0,ScreenDC);   end; {try}   end; On most computers this works correctly, but one of my users has the following problem: the screenshots show not the complete monitor, both on the right side and the bottom side a part is missing. See attached screenshots: "screen03_bad.png" = 1536 x 864 pixel is what my program created, while "screen04_ok.jpg" = 1920 x 1080 pixel is a correct screenshot taken by another tool. The OS of this user is Windows 10 Pro, 64-bit. I compiled with Lazarus 2.0.10 / FPC 3.2.0 / 32-bit. I'm not familiar with this DPI stuff, but I run this code on the computer of this user 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 show_DPI_factors;   {shows some DPI-factors}   var x,y,m: longint;   begin   x:=-1; y:=-1;   if Graphics.ScreenInfo.Initialized then      begin      x:=Graphics.ScreenInfo.PixelsPerInchX;      y:=Graphics.ScreenInfo.PixelsPerInchY;      end;    write(Forms.Screen.PixelsPerInch, ' ', x, ' ', y, ' ',         Form1.DesignTimePPI, ' ', Form1.PixelsPerInch);    for m:=0 to Screen.MonitorCount-1 do      write(' ', Forms.Screen.Monitors[m].PixelsPerInch);   writeln;   end; and the result was: 96 96 96 96 96 96 (which looks normal to me). Question 1: are there others who see the same problem? Question 2: can anybody help? Thanks in advance. ---------------------------------------------------------------------- Josh · 2024-05-21 11:35 Just a thought. Do you have High DPI on for your project. ---------------------------------------------------------------------- Hartmut · 2024-05-21 12:47 Thanks Josh for that thought. "LCL scaling (Hi-DPI)" and "DPI awareness" are both off. I experimented with them 2 years ago in this project and run into problems (but I don't remember more details - too long ago), so I want to keep them off. ---------------------------------------------------------------------- KodeZwerg · 2024-05-21 18:30 Here is how I do, try if it works on the complicated system: 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 function TForm1.CreateScreenShot(const AMonitor: Integer; const AExcludeForm: Boolean = True): TBitmap;var  LMon: TMonitor;  ScreenCanvas: TCanvas;begin  if ((AMonitor < 0) or (AMonitor >= Screen.MonitorCount)) then    Exit;  LMon := Screen.Monitors[AMonitor];  if AExcludeForm then    begin      Self.Hide;      Application.ProcessMessages;      Sleep(250);    end;   ScreenCanvas := TCanvas.Create;  try    ScreenCanvas.Handle := GetDC(0);    Result := TBitmap.Create;    try      Result.PixelFormat := pf32bit;      Result.SetSize(LMon.WorkareaRect.Width, LMon.WorkareaRect.Height);      Result.Canvas.CopyMode := cmSrcCopy;    Result.Canvas.CopyRect(Result.Canvas.ClipRect, ScreenCanvas, LMon.BoundsRect);    finally    end;  finally    ScreenCanvas.Free;  end;  if AExcludeForm then    Self.Show;end;Attached is a demo project with monitor selector. If that is not working as expected, its worth a try to change the DC like: "ScreenCanvas.Handle := GetDC(LMon.MonitorNum);" //edit: Please update source by removing all "WorkareaRect" calls, exemplary: "Result.SetSize(LMon.WorkareaRect.Width, LMon.WorkareaRect.Height);" --> "Result.SetSize(LMon.Width, LMon.Height);" ---------------------------------------------------------------------- KodeZwerg · 2024-05-21 19:51 Small feature added to choose if you want to snapshot also the taskbar. 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 function TForm1.CreateScreenShot(const AMonitor: Integer; const AExcludeForm: Boolean = True; const AExcludeTaskbar: Boolean = False): TBitmap;var  LMon: TMonitor;  LScreen: TCanvas;  LRect: TRect;begin  if ((AMonitor < 0) or (AMonitor >= Screen.MonitorCount)) then    Exit;   if AExcludeForm then    begin      Self.Hide;      Application.ProcessMessages;      Sleep(250);    end;   LMon := Screen.Monitors[AMonitor];   if AExcludeTaskbar then    LRect := LMon.WorkareaRect  else    LRect := LMon.BoundsRect;   LScreen := TCanvas.Create;  try    LScreen.Handle := GetDC(LMon.MonitorNum);    Result := TBitmap.Create;    try      Result.PixelFormat := pf32bit;    Result.SetSize(LRect.Width, LRect.Height);      Result.Canvas.CopyMode := cmSrcCopy;      Result.Canvas.CopyRect(Result.Canvas.ClipRect, LScreen, LRect);    finally      ReleaseDC(LMon.MonitorNum, LScreen.Handle);    end;  finally    LScreen.Free;  end;  if AExcludeForm then    Self.Show;end; ---------------------------------------------------------------------- Hartmut · 2024-05-22 10:50 Thank you KodeZwerg for your code. I tried your attachment from reply #3 on my computer both on Linux Ubuntu 22.04 and Windows 7 and both failed (with my code from my 1st post this works perfectly). Here is what I changed in your attachment:  - removed "WorkareaRect" 4 times as you had requested  - added "ReleaseDC(0, ScreenCanvas.Handle);" in line 82 in function "CreateScreenShot" because I think this was missing  - added "bmp.SaveToFile('d:\Tst\xxx.bmp');" in line 106 in procedure "Button1Click" to save the bitmap to a file. The result is, that your screenshots show only a part of the monitor: both on the right side and the bottom side a part is missing. See attached screenshots: "xx282_bad.zip" is what your program created, while "screen_0282_ok.png" is a correct screenshot taken by another tool. That means, now I have (with your code) nearly the same problem on my computer as the problematic user has (with my code from my 1st post, which works perfectly on my computer both with Linux and Windows). The only difference is:  - the screenshot on the problematic computer (with my code) is only 1536 x 864 pixel, while this computer has a resulution of 1920 x 1080 pixel (so the screenshot is too small, has not enough pixels)  - the screenshot on my computer (with your code) has the correct size (1280 x 1024 pixel), but the picture is augmented, so a part is missing on the right side and bottom side. Very strange. Has somebody an explanation for that? Or an idea for a solution? ---------------------------------------------------------------------- wp · 2024-05-22 11:31 Tested KodeZwerg's project from reply #3 without any modifications, and it works perfectly: - Win 11 / Laz main/FPC 3.2.2 (32 bit), 96ppi - Win 11 / Laz main/FPC 3.2.2 (64 bit), 96 ppi - Win 7 / Laz main/FPC3.2.2 (32 bit), 120 ppi - Win 7 / Laz 2.0.10/FPC 3.20 (32 bit), 120 ppi ---------------------------------------------------------------------- TRon · 2024-05-22 11:43 Does not seem to work as intended on Linux Mate (gtk2). It actually does not seem to be doing anything at all ---------------------------------------------------------------------- KodeZwerg · 2024-05-22 11:52 Quote from: Hartmut on May 22, 2024, 12:50:11 pmThank you KodeZwerg for your code. I tried your attachment from reply #3 on my computer both on Linux Ubuntu 22.04 and Windows 7 and both failed (with my code from my 1st post this works perfectly).You are welcomed, the only difference I see on your screen is that you are using GTK2 widgetset where I am more than unaware if it support the stuff I use. I've tested on Windows 10 64bit with win64 widgetset and run into no problems on whatever resolution/dpi. Lazarus 3.99 (rev main_3_99-1993-g5ad1922ccb) FPC 3.2.2 x86_64-win64-win32/win64 ---------------------------------------------------------------------- KodeZwerg · 2024-05-22 14:03 Quote from: TRon on May 22, 2024, 01:43:19 pmDoes not seem to work as intended on Linux Mate (gtk2). It actually does not seem to be doing anything at all  How do you access screen/desktop canvas (similar to GetDC()) on Linux Mate (gtk2) ? ---------------------------------------------------------------------- Hartmut · 2024-05-22 15:47 Quote from: wp on May 22, 2024, 01:31:56 pmTested KodeZwerg's project from reply #3 without any modifications, and it works perfectly: - Win 11 / Laz main/FPC 3.2.2 (32 bit), 96ppi - Win 11 / Laz main/FPC 3.2.2 (64 bit), 96 ppi - Win 7 / Laz main/FPC3.2.2 (32 bit), 120 ppi - Win 7 / Laz 2.0.10/FPC 3.20 (32 bit), 120 ppi Thank you very much wp for those tests. Because you tested without modifications, I added again "WorkareaRect" 4 times and repeated the tests on my computer on both Linux Ubuntu and Windows 7. But I got the same results as before: the screenshots show only a part of the monitor, both on the right side and the bottom side a part is missing. Only the heights is now some pixel less than before. Sadly the "WorkareaRect" was not the root cause. Quote from: TRon on May 22, 2024, 01:43:19 pmDoes not seem to work as intended on Linux Mate (gtk2). It actually does not seem to be doing anything at all  Thanks TRon. On my Linux I first had the same problem. Therefore I added "bmp.SaveToFile('xxx.bmp');" in procedure "Button1Click" to save the bitmap into a file: 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.Button1Click(Sender: TObject);var  bmp: TBitmap;begin  if ((cbMonitors.ItemIndex < 0) or (cbMonitors.ItemIndex >= cbMonitors.Items.Count)) then    Exit;  bmp := CreateScreenShot(cbMonitors.ItemIndex, cbExclude.Checked);  try    bmp.SaveToFile('xxx.bmp');    Image1.Picture.Assign(bmp);  finally    bmp.Free;  end;end; Would you test with this again? And what Lazarus/FPC version are you using? Quote from: KodeZwerg on May 22, 2024, 01:52:13 pmYou are welcomed, the only difference I see on your screen is that you are using GTK2 widgetset where I am more than unaware if it support the stuff I use. I've tested on Windows 10 64bit with win64 widgetset and run into no problems on whatever resolution/dpi. Lazarus 3.99 (rev main_3_99-1993-g5ad1922ccb) FPC 3.2.2 x86_64-win64-win32/win64 Thanks for this informations. As said, on Windows 7 I have the same problem with your code as on Linux GTK2. ---------------------------------------------------------------------- TRon · 2024-05-23 07:19 Sorry for the delay. Quote from: KodeZwerg on May 22, 2024, 04:03:38 pmQuote from: TRon on May 22, 2024, 01:43:19 pmDoes not seem to work as intended on Linux Mate (gtk2). It actually does not seem to be doing anything at all  How do you access screen/desktop canvas (similar to GetDC()) on Linux Mate (gtk2) ? That is the stupid ... usually exactly the same. Quote from: Hartmut on May 22, 2024, 05:47:42 pmThanks TRon. On my Linux I first had the same problem. Therefore I added "bmp.SaveToFile('xxx.bmp');" in procedure "Button1Click" to save the bitmap into a file: Yes, the saved picture indeed contains the caption of the desktop QuoteWould you test with this again? And what Lazarus/FPC version are you using? See above answer and it doesn't matter which Lazarus/FPC version, I've tried with Lazarus 3.0, 3.2 and trunk with FPC 3.2.2. I'll love to have a closer look to figure out what's going on there but am a bit busy atm so that might take some time. ---------------------------------------------------------------------- KodeZwerg · 2024-05-23 08:46 Quote from: Hartmut on May 22, 2024, 05:47:42 pmI added again "WorkareaRect" 4 times and repeated the tests on my computer on both Linux Ubuntu and Windows 7. But I got the same results as before: the screenshots show only a part of the monitor, both on the right side and the bottom side a part is missing. Only the heights is now some pixel less than before. Sadly the "WorkareaRect" was not the root cause.You might switch to the last version, there in code you see what the WorkareaRect is for, it is similar to a forms ClientRect where the titlebar and frame + eventually shadow is excluded, the area where you can paint in, for the desktop you got the same, WorkareaRect is the part of the screen where each app is displayed on = excluding the taskbar. In the demo project I simply added another checkbox to set that argument (Exclude Taskbar). Anyway, it would not change a thing since the work with canvas is somehow blocked by OS, unsure if its in general the try to access the screen canvas on gtk2. Will patiently wait for TRon Quote from: TRon on May 23, 2024, 09:19:48 amThat is the stupid ... usually exactly the same. I'll love to have a closer look to figure out what's going on there but am a bit busy atm so that might take some time.Thank you for help finding a solution for gtk2! ---------------------------------------------------------------------- TRon · 2024-05-23 08:57 Quote from: KodeZwerg on May 23, 2024, 10:46:05 amQuote from: TRon on May 23, 2024, 09:19:48 amThat is the stupid ... usually exactly the same. I'll love to have a closer look to figure out what's going on there but am a bit busy atm so that might take some time.Thank you for help finding a solution for gtk2! I can at least provide the hint to change the pixel depth to 24 bit. That provides a visible picture. Now to figure out how to test for that ---------------------------------------------------------------------- Hartmut · 2024-05-23 11:37 Quote from: TRon on May 23, 2024, 09:19:48 amQuote from: Hartmut on May 22, 2024, 05:47:42 pmThanks TRon. On my Linux I first had the same problem. Therefore I added "bmp.SaveToFile('xxx.bmp');" in procedure "Button1Click" to save the bitmap into a file: Yes, the saved picture indeed contains the caption of the desktop Thanks TRon for this test. Do I understand you correctly, that this screenshot shows the *complete* desktop? Nothing missing on the right margin or bottom margin? Quote from: KodeZwerg on May 23, 2024, 10:46:05 amYou might switch to the last version, there in code you see what the WorkareaRect is for, it is similar to a forms ClientRect where the titlebar and frame + eventually shadow is excluded, the area where you can paint in, for the desktop you got the same, WorkareaRect is the part of the screen where each app is displayed on = excluding the taskbar. In the demo project I simply added another checkbox to set that argument (Exclude Taskbar). Anyway, it would not change a thing since the work with canvas is somehow blocked by OS, unsure if its in general the try to access the screen canvas on gtk2. Thanks for this explanations. Quote from: TRon on May 23, 2024, 10:57:04 amI can at least provide the hint to change the pixel depth to 24 bit. That provides a visible picture. Now to figure out how to test for that  I can confirm this. On Linux Ubuntu with 'pf32bit' the Image 'Form1.Image1' stays empty (nothing shown), while with 'pf24bit' a small screenshot is displayed there. ---------------------------------------------------------------------- Hartmut · 2024-05-23 15:08 I made a strange and very interesting observation. I changed the code from KodeZwerg to the following (which I can read and understand easier): 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 show_TRect(R: TRect);   begin   writeln('X1=', R.Left, ' Y1=', R.Top, ' X2=', R.Right, ' Y2=', R.Bottom);   end; function createScreenShot(mon: integer): TBitmap;   var M: TMonitor;       CVS: TCanvas;       RS,RD: TRect;       w,h: integer;   begin   if (mon < 0) or (mon >= Screen.MonitorCount) then exit;   M:=Screen.Monitors[mon];   CVS:=TCanvas.Create;    try      CVS.Handle:=GetDC(0);      Result:=TBitmap.Create;      try         Result.PixelFormat:=pf24bit;         w:=M.Width; h:=M.Height;writeln('w=', w, ' h=', h);   // => w=1280 h=1024         Result.SetSize(w,h);         Result.Canvas.CopyMode:=cmSrcCopy;       RS:=M.BoundsRect;           {Source}         RD:=Result.Canvas.ClipRect; {Destination}show_TRect(RS);             // => X1=0 Y1=0 X2=1280 Y2=1024show_TRect(RD);               // => X1=0 Y1=0 X2=2000 Y2=2000 !!         RD.Right:=1280; RD.Bottom:=1025; // 1025 works / 1024 not!!         Result.Canvas.CopyRect(RD,CVS,RS); {Dest-Rect,Src-Canvas,Src-Rect}      finally         ReleaseDC(0,CVS.Handle);      end;   finally      CVS.Free;   end;   end; {createScreenShot} When I start this code on my computer (Linux Ubuntu 22.04 64-bit), then it works correctly (with Lazarus/FPC = 2.0.10/3.2.0 and 2.2.4/3.2.2). My screen resolution is 1280 x 1024. Very strange are 2 things: a) line 28: why contains 'RD' 2x 2000? Where can this come from? Obviously this is wrong. It causes the screenshot to be augmented and therefore parts at the right margin and botton margin are missing. That is the same problem which my "problematic user" has. b) line 29: when I set 'RD.Bottom:=1024' (which IMHO should be the correct value), then the screenshot is completely black (contains nothing). 1025 works correctly. Is this a bug? Can somebody explain this 2 strange things? Edit: I repeated above test on Windows 7 32-bit: Issue a) Again 'RD' contains 2x 2000! Is this a default, if nothing was (correctly) set? Issue b) In Win7 '1024' works correctly. No need to use 1025. ---------------------------------------------------------------------- TRon · 2024-05-24 12:25 Quote from: Hartmut on May 23, 2024, 01:37:50 pmThanks TRon for this test. You are more than welcome  QuoteDo I understand you correctly, that this screenshot shows the *complete* desktop? Nothing missing on the right margin or bottom margin? That is affirmative. Nothing seems to be missing from the resulting saved bmp, Including the taskbar (or whatever panel they named it in Linux). BTW also note this recent thread (there were many others in the past) that has some similarities wrt differences between platforms. ---------------------------------------------------------------------- KodeZwerg · 2024-05-24 13:01 Feel free to rename and change the order of thing however you like but... Quote from: Hartmut on May 23, 2024, 05:08:13 pma) line 28: why contains 'RD' 2x 2000? Where can this come from? Obviously this is wrong. It causes the screenshot to be augmented and therefore parts at the right margin and botton margin are missing. That is the same problem which my "problematic user" has. b) line 29: when I set 'RD.Bottom:=1024' (which IMHO should be the correct value), then the screenshot is completely black (contains nothing). 1025 works correctly. Is this a bug? a) because you changed the logic, RD is the screen dimension including taskbar where you set the bitmap size wrong since later you use boundsrect -> the desktop without taskbar. b) idk, i suggest that you use my last posted code without modify beside to log both, the screen dimension and the boundsrect of screen. ---------------------------------------------------------------------- Hartmut · 2024-05-24 13:59 Quote from: TRon on May 24, 2024, 02:25:54 pm... BTW also note this recent thread (there were many others in the past) that has some similarities wrt differences between platforms. Thanks for that link. I checked this article 'Broken example "Creating and drawing a transparent bitmap for a TImage" in Linux' but did not find something which dealt with image- or screenshot-sizes. Do you mean a certain reply number? Quote from: KodeZwerg on May 24, 2024, 03:01:05 pma) because you changed the logic, RD is the screen dimension including taskbar where you set the bitmap size wrong since later you use boundsrect -> the desktop without taskbar. Thanks for your help. As far as I can see I did not change the logic. 'boundsrect' contains 1280x1024 which is my desktop including taskbar which are the same values as in Result.SetSize(). Quote from: KodeZwerg on May 24, 2024, 03:01:05 pmb) idk, i suggest that you use my last posted code without modify beside to log both, the screen dimension and the boundsrect of screen. I tested your unmodified code and got the same problem: the screenshots show not the complete monitor, both on the right side and the bottom side a part is missing (both on Linux and Windows). I assume, the 2x 2000 in 'Result.Canvas.ClipRect' are the reason for this. Meanwhile I tested my code from reply #15 on 4 more Windows computers (3x Win10, 1x Win7) with 4 different screen resulutions and always line 28 returned 'X1=0 Y1=0 X2=2000 Y2=2000', where the 2x 2000 obviously are wrong. That means, in sum I have 5x Windows and 1x Linux computers with this wrong values. In the sources I found in line 55 in /lazarus/lcl/include/canvas.inc: 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 function TCanvas.GetClipRect: TRect;begin  // return actual clipping rectangle  if GetClipBox(FHandle, @Result) = ERROR then    Result := Rect(0, 0, 2000, 2000);{Just in Case}end;which seems to be the reason for that. Questions: has somebody an idea,  - why returns GetClipBox() this ERROR?  - can it be, that some initialization of the 'TBitmap' (or its Canvas) in my code is wrong or incomplete? I attached a compilable project with the code from reply #15, if somebody wants to run own tests. Thanks in advance. ---------------------------------------------------------------------- Hartmut · 2024-05-25 14:06 I started the debugger to explore function TCanvas.GetClipRect(), which is called in line 26 in the code in reply #15. I did this on Windows 7, 32 bit with Lazarus 2.0.10 / FPC 3.2.0. The goal was to check, why the 'ERROR' in function TCanvas.GetClipRect() occurs, which lets this function return Rect(0, 0, 2000, 2000), which is wrong: Source of function TCanvas.GetClipRect(): 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 // found in line 55 in \lcl\include\canvas.inc function TCanvas.GetClipRect: TRect;begin  // return actual clipping rectangle  if GetClipBox(FHandle, @Result) = ERROR then    Result := Rect(0, 0, 2000, 2000);{Just in Case}end; // above function GetClipBox() returns '0' = 'ERROR' Source of function GetClipBox(): 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 // found in line 353 in \lcl\include\winapi.inc// DC contains '0' function GetClipBox(DC : hDC; lpRect : PRect) : Longint;begin  Result := WidgetSet.GetClipBox(DC, lpRect);end;   // above function WidgetSet.GetClipBox() returns '0' Source of function WidgetSet.GetClipBox(): 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 // found in line 1697 in \lcl\interfaces\win32\win32winapi.inc// DC contains '0' function TWin32WidgetSet.GetClipBox(DC : hDC; lpRect : PRect) : Longint;begin  Result := Windows.GetClipBox(DC, Windows.LPRECT(lpRect));end;   // above function Windows.GetClipBox() returns '0' I'm a bloody beginner to Graphics and WidgetSets. Does somebody else understand, why the ERROR in function TCanvas.GetClipRect() occurs? Can it be, that some initialization of the 'TBitmap' (or its Canvas) in my code in reply #15 is wrong or incomplete? A compilable project with the code from reply #15 is attached in reply #18. ---------------------------------------------------------------------- nanobit · 2024-05-25 14:24 I recall that I reported this bug and it has been fixed. RequiredState([csHandleValid]); was missing in TCanvas.GetClipRect ---------------------------------------------------------------------- wp · 2024-05-25 14:50 Quote from: nanobit on May 25, 2024, 04:24:15 pmI recall that I reported this bug and it has been fixed. RequiredState([csHandleValid]); was missing in TCanvas.GetClipRect Maybe an indication to you, Hartmut, to update your Lazarus? 2.0.10 is really "ancient" when v3.4 is about to be released. ---------------------------------------------------------------------- Hartmut · 2024-05-25 15:05 Quote from: wp on May 25, 2024, 04:50:20 pmMaybe an indication to you, Hartmut, to update your Lazarus? 2.0.10 is really "ancient" when v3.4 is about to be released. Yes... I have newer versions that 2.0.10, but this project is older and was made with 2.0.10 and I don't want to change this at the end of the race ;-) Quote from: nanobit on May 25, 2024, 04:24:15 pmI recall that I reported this bug and it has been fixed. RequiredState([csHandleValid]); was missing in TCanvas.GetClipRect Thank you very much nanobit for that valuable information. I found your bug report in https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/40114 But you wrote there "eg. is needed if getClipRect is the first call in canvas use" which might lead us to a workaround: is it possible, before getClipRect() is called, to make some dummy-call to the Canvas which ensures/initializes a valid Handle? What could this dummy-call be? Does someone have an idea? ---------------------------------------------------------------------- wp · 2024-05-25 15:12 Quote from: Hartmut on May 25, 2024, 05:05:19 pmBut you wrote there "eg. is needed if getClipRect is the first call in canvas use" which might lead us to a workaround: is it possible, before getClipRect() is called, to make some dummy-call to the Canvas which ensures/initializes a valid Handle? What could this dummy-call be? Does someone have an idea? For example, fill the background of the bitmap, or simply set a single pixel - this is enough to create the handle, and GetClipRect should work then. But still, why do you need the canvas.ClipRect at all? You've set the size of the bitmap already, and unless you set the ClipRect by yourself GetClipRect should report nothing else. Quote from: Hartmut on May 25, 2024, 05:05:19 pmYes... I have newer versions that 2.0.10, but this project is older and was made with 2.0.10 and I don't want to change this at the end of the race ;-) Then you have to live with the bugs of that old version... Maybe that "partial screenshot" issue that you report has been fixed already, too? ---------------------------------------------------------------------- Hartmut · 2024-05-25 15:55 Quote from: wp on May 25, 2024, 05:12:26 pmFor example, fill the background of the bitmap, or simply set a single pixel - this is enough to create the handle, and GetClipRect should work then. Now I use 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 Result.Canvas.Pixels[0,0]:=0;before the 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 RD:=Result.Canvas.ClipRect;which works perfectly. Thank you very much, wp! QuoteBut still, why do you need the canvas.ClipRect at all? You've set the size of the bitmap already, and unless you set the ClipRect by yourself GetClipRect should report nothing else. I don't know. The original code is from KodeZwerg (from the attachment in reply #3). Maybe he only needed a 'TRect' with the dimensions of the Canvas and choosed Canvas.ClipRect() for that? Maybe you know a better way? @KodeZwerg: can you explain for what you use 'Result.Canvas.ClipRect' (in the attachment in reply #3)? ---------------------------------------------------------------------- Hartmut · 2024-05-30 09:54 I have a solution for my origin problem, for what I created this Topic (see my 1st post): screenshots on a "problematic computer" taken with "normal code" resulted in a screenshot which is too small, both on the right side and bottom side a part is missing. I could improve the code from KodeZwerg in the attachment of reply #3 in a way, that the taken screenshot is larger by a selectable factor 'ppi'. Maybe others have the same problem, so here is my code: 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 const DPI96  = 96;  {Standard DPI-Value}      DPI120 = 120; {alternative DPI- Value}      DPI150 = 150; {alternative DPI-Value} procedure save_ScreenShot_PNG(mon: integer; ppi: integer; filespec: string);   {creates a screenshot from Monitor 'mon' und saves it into a PNG-file 'filespec'.    I: - mon: use [0..Screen.MonitorCount] / all other values select the         Primary Monitor.       - ppi: greater values then 'DPI96' result in a greater screenshot on         computers, where the screenshot is too small with 'DPI96'}   var PNG: TPortableNetworkGraphic;       M: TMonitor;       CVS: TCanvas; {Canvas of the Screen}       RS,RD: TRect;       w,h: integer;   begin   if (mon < 0) or (mon >= Screen.MonitorCount)      then mon:=Screen.PrimaryMonitor.MonitorNum;   M:=Screen.Monitors[mon];   CVS:=TCanvas.Create; {Canvas of the Screen}    try      CVS.Handle:=GetDC(0); {get Handle for Device Context (DC) of Desktop}      PNG:=TPortableNetworkGraphic.Create;      try         w:=M.Width; h:=M.Height; {standard size of wanted monitor}         RS:=M.BoundsRect;        {RS=Source}          if ppi > DPI96 then    {if the screenshot is too small: }            begin            w:=round((longint(w)*ppi) / DPI96); {increase 'w' and 'h': }          h:=round((longint(h)*ppi) / DPI96);            RS.Right:=RS.Left+w;  {increase Source analog: }            RS.Bottom:=RS.Top+h;          end;          PNG.SetSize(w,h);         PNG.Canvas.CopyMode:=cmSrcCopy;         PNG.Canvas.Pixels[0,0]:=0; {workaround for the 2x 2000 bug}         RD:=PNG.Canvas.ClipRect;   {RD=Destination}{$IFDEF LINUX}         inc(RD.Bottom); {otherwise in Linux the screenshot is only black}{$ENDIF}         PNG.Canvas.CopyRect(RD,CVS,RS);         PNG.SaveToFile(filespec);     finally         PNG.Free;         ReleaseDC(0,CVS.Handle);      end; {try}   finally      CVS.Free;   end; {try}   end; {save_ScreenShot_PNG}  Normally parameter 'ppi' has the value 'DPI96'. Greater values then 'DPI96' result in a greater screenshot on computers, where the screenshot is too small with 'DPI96'. On the "problematic computer" of one of my users I use a command line switch to activate 'DPI120' which results in perfect screenshots. Again thanks to all who helped me. ---------------------------------------------------------------------- wp · 2024-05-30 10:52 This kind of solution makes me think: maybe all this is a home-made problem because you refuse to use LCLScaling (reply #2) where all these scaling tasks are done in the background? ---------------------------------------------------------------------- Hartmut · 2024-05-30 11:37 You are right, wp. But these 7 lines are the minimal invasive solution in a project, which is old and was developed without LCL-Scaling (because at that time I did not know about this setting) and where I tried enabling LCL-Scaling retroactive 2 years ago and run into problems. The project is graphics intensive and has about 40000 lines of code and everything is tested and working (on a dozen of computers). So I had no interest to put things upside down at the end of the race.