Recent

Author Topic: Get a screenshot of a form  (Read 8176 times)

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Get a screenshot of a form
« on: March 30, 2015, 03:42:16 am »
Hi all

I want know how i could capture the form image and send it to the printer, if it is posible.

More explained:

I have my own form, with some controls( scrollable); i want capture the image how it looks in the screen and the send it to the printer stretched.

Any help is welcome.
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

Eugene Loza

  • Hero Member
  • *****
  • Posts: 729
    • My games in Pascal
Re: Get a screenshot of a form
« Reply #1 on: March 30, 2015, 05:43:19 am »
If you want to screenshot a form by pascal code - I don't know how to do that.
But you can easily do a screenshot by scrot (under Linux) or print+screen and pasting it into image editor (Paint or, better, Gimp under Windows).
My FOSS games in FreePascal&CastleGameEngine: https://decoherence.itch.io/ (Sources: https://gitlab.com/EugeneLoza)

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: Get a screenshot of a form
« Reply #2 on: March 30, 2015, 05:51:21 am »
AFAIK TCustomForm has a GetFormImage method, which can be captured by a TBitmap.

From Embarcadero:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  FormImage: TBitmap;
begin
  FormImage := GetFormImage;
  try
    Clipboard.Assign(FormImage);
    Image1.Picture.Assign(Clipboard);
  finally
    FormImage.Free;
  end;
end;
« Last Edit: March 30, 2015, 05:56:02 am by typo »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8774
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Get a screenshot of a form
« Reply #3 on: March 30, 2015, 07:38:30 am »
AFAIK TCustomForm has a GetFormImage method, which can be captured by a TBitmap.

From Embarcadero:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  FormImage: TBitmap;
begin
  FormImage := GetFormImage;
  try
    Clipboard.Assign(FormImage);
    Image1.Picture.Assign(Clipboard);
  finally
    FormImage.Free;
  end;
end;
Hmm...it's all black here on qt, gtk2 and win32 widgetset.

Timewarp

  • Full Member
  • ***
  • Posts: 144
Re: Get a screenshot of a form
« Reply #4 on: March 30, 2015, 07:50:04 am »
Hmm...it's all black here on qt, gtk2 and win32 widgetset.
Why it doesn't work is still unknown

http://bugs.freepascal.org/view.php?id=25448

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: Get a screenshot of a form
« Reply #5 on: March 30, 2015, 09:41:16 am »
This works in win32:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  lRect: TRect;
  lFormBitmap: TBitmap;
begin
  lRect := Bounds(0, 0, ClientWidth, ClientHeight);
  lFormBitmap := TBitmap.Create;
  try
    lFormBitmap.Width := ClientWidth;
    lFormBitmap.Height := ClientHeight;
    lFormBitmap.Canvas.CopyRect(lRect, Canvas, lRect);
    lFormBitmap.SaveToFile('D:\Programas\output.bmp');
  finally
    lFormBitmap.Free;
  end;
end;

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: Get a screenshot of a form
« Reply #6 on: March 30, 2015, 02:38:14 pm »
This works too:

Code: [Select]
  Image1.Picture.Assign(GetFormImage);

bylaardt

  • Sr. Member
  • ****
  • Posts: 310
Re: Get a screenshot of a form
« Reply #7 on: March 30, 2015, 03:03:58 pm »
I use GTK here and works fine with this code:
Code: [Select]
 
  MyCapture:=TBitMap.Create(application);
  MyCapture.SetSize(ClientWidth,ClientHeight);
  MyCapture.canvas.FillRect(0,0,ClientWidth,ClientHeight);
  self.PaintTo(MyCapture.canvas,0,0);
  MyCapture.SaveToFile('/home/bylaardt/MyFormImage.bmp');
  MyCapture.free;
felipemdc's code woks too.
« Last Edit: March 30, 2015, 03:54:46 pm by bylaardt »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8774
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Get a screenshot of a form
« Reply #8 on: March 30, 2015, 04:11:32 pm »
I use GTK here and works fine with this code:
Code: [Select]
 
  MyCapture:=TBitMap.Create(application);
  MyCapture.SetSize(ClientWidth,ClientHeight);
  MyCapture.canvas.FillRect(0,0,ClientWidth,ClientHeight);
  self.PaintTo(MyCapture.canvas,0,0);
  MyCapture.SaveToFile('/home/bylaardt/MyFormImage.bmp');
  MyCapture.free;
felipemdc's code woks too.
Your code works on qt, felipe's code doesn't (again, black image). Seems like PaintTo is the angel here, while CopyRect somewhat doesn't work everywhere. It's weird, though. I remember in the past using CopyRect too to get a partial "screenshot" of my forms. I'll have to dig in my old code.

torbente

  • Sr. Member
  • ****
  • Posts: 325
    • Noso Main Page
Re: Get a screenshot of a form
« Reply #9 on: March 30, 2015, 04:25:38 pm »
This works in win32:

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  lRect: TRect;
  lFormBitmap: TBitmap;
begin
  lRect := Bounds(0, 0, ClientWidth, ClientHeight);
  lFormBitmap := TBitmap.Create;
  try
    lFormBitmap.Width := ClientWidth;
    lFormBitmap.Height := ClientHeight;
    lFormBitmap.Canvas.CopyRect(lRect, Canvas, lRect);
    lFormBitmap.SaveToFile('D:\Programas\output.bmp');
  finally
    lFormBitmap.Free;
  end;
end;

This one worked perfet for me. Now im trying to send this image to the printer. I guess printer4lazarus is the way but i can not figure how i could do that for myself.
Noso Cryptocurrency Main Developer
https://github.com/DevTeamNoso/NosoWallet

rvk

  • Hero Member
  • *****
  • Posts: 6572
Re: Get a screenshot of a form
« Reply #10 on: March 30, 2015, 04:34:15 pm »
AFAIK TCustomForm has a GetFormImage method, which can be captured by a TBitmap.
Hmm...it's all black here on qt, gtk2 and win32 widgetset.
Just FYI:
For Win32 GetFormImage does work but assigning it first to the Clipboard and then Clipboard to your Image1 does give a black result. Assigning FormImage directly to Image1.Picture does works ok (in win32, not sure on qt and gtk2).

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  FormImage: TBitmap;
begin
  FormImage := GetFormImage;
  try
    // Clipboard.Assign(FormImage); // <=== NOPE
    Image1.Picture.Assign(FormImage); // <-- this works ok
  finally
    FormImage.Free;
  end;
end;

Jiří Huňáček

  • New Member
  • *
  • Posts: 28
Re: Get a screenshot of a form
« Reply #11 on: November 03, 2024, 08:33:18 pm »
I can't figure out how to get the Caption of the form into the screenshot and not just part of it.

Does anyone know how to fix this?

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls,
  9.   LCLIntf, LCLType;
  10.  
  11. type
  12.  
  13.   { TfrmForm1 }
  14.  
  15.   TfrmForm1 = class(TForm)
  16.     Button1: TButton;
  17.     procedure Button1Click(Sender: TObject);
  18.   private
  19.  
  20.   public
  21.     { public declarations }
  22.     procedure SaveScreenShot(aFilename:string);
  23.  
  24.   end;
  25.  
  26. var
  27.   frmForm1: TfrmForm1;
  28.   BMPFileName: String;
  29.  
  30. implementation
  31.  
  32. {$R *.lfm}
  33.  
  34. { TfrmForm1 }
  35.  
  36. procedure TfrmForm1.SaveScreenShot(aFilename:string);
  37. var
  38.   ScreenDC: HDC;
  39.   SaveBitmap: TBitmap;
  40. begin
  41.   SaveBitmap := TBitmap.Create;
  42.   try
  43.     SaveBitmap.SetSize(Screen.Width, Screen.Height);
  44.     //ScreenDC := GetWindowDC(frmForm1.WindowHandle);
  45.     ScreenDC := GetDC(frmForm1.WindowHandle);
  46.     try
  47.       SaveBitmap.LoadFromDevice(ScreenDC);
  48.     finally
  49.       ReleaseDC(0, ScreenDC);
  50.     end;
  51.     SaveBitmap.SaveToFile(aFilename);
  52.   finally
  53.     SaveBitmap.Free;
  54.   end;
  55. end;
  56.  
  57. procedure TfrmForm1.Button1Click(Sender: TObject);
  58. begin
  59.   BMPFileName := 'C:\picture.bmp';
  60.   SaveScreenShot(BMPFileName);
  61. end;
  62.  
  63. end.
Best regards / mit freundlichen Grüßen / s pozdravem
Jiří Huňáček (George)

Lazarus v3.6 and FPC v3.2.2 on Windows 10 x64

Fibonacci

  • Hero Member
  • *****
  • Posts: 594
  • Internal Error Hunter
Re: Get a screenshot of a form
« Reply #12 on: November 03, 2024, 09:04:53 pm »
If its for Windows only I can share some of my code.

First, add Windows unit to the uses, and under the uses add this declaration as its not in the Windows unit:

Code: Pascal  [Select][+][-]
  1. function DwmGetWindowAttribute(hwnd: HWND; dwAttribute: DWORD; pvAttribute: PVOID; cbAttribute: DWORD): HRESULT; stdcall; external 'dwmapi.dll';

This is the function:

Code: Pascal  [Select][+][-]
  1. function get_ss_of(window: hwnd; var bmp: graphics.TBitmap): integer;
  2. var
  3.   outer: TRect;
  4.   dc: HDC;
  5. begin
  6.   result := 0; // 0 = success
  7.   if not IsWindow(window) then exit(1);
  8.   if not (DwmGetWindowAttribute(window, 9{DWMWA_EXTENDED_FRAME_BOUNDS}, @outer, sizeof(outer)) = S_OK) then exit(2);
  9.   bmp.Width := outer.Width;
  10.   bmp.Height := outer.Height;
  11.   bmp.PixelFormat := pf24bit;
  12.   dc := GetDC(GetDesktopWindow);
  13.   bmp.BeginUpdate(true);
  14.   if not BitBlt(bmp.Canvas.Handle, 0, 0, outer.Width, outer.Height, dc, outer.Left, outer.Top, SRCCOPY) then result := 3;
  15.   bmp.EndUpdate(true);
  16.   bmp.Canvas.Changed;
  17.   ReleaseDC(GetDesktopWindow, dc);
  18. end;

Usage:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   bmp: graphics.TBitmap;
  4. begin
  5.   try
  6.     bmp := graphics.TBitmap.Create;
  7.  
  8.     if get_ss_of(Form1.Handle, bmp) = 0 then begin
  9.       // display on TImage
  10.       image1.Picture.Assign(bmp);
  11.       // or save to file
  12.       bmp.SaveToFile('ss.bmp');
  13.     end;
  14.   finally
  15.     bmp.Free;
  16.   end;
  17. end;

If anything is over the form, it will be captured on the screenshot.

kupferstecher

  • Hero Member
  • *****
  • Posts: 603
Re: Get a screenshot of a form
« Reply #13 on: November 03, 2024, 11:28:36 pm »
Below the three methods that I know of, PainTo and BitBlt already were mentioned. The example below shows the capturing of a control, not the whole form.

In my experience all have some quirks.

Code: Pascal  [Select][+][-]
  1.   try
  2.  
  3.     ////PAINTTO
  4.     //vControl.PaintTo(aImage.Canvas,0,0);
  5.  
  6.     ////LM_PAINT
  7.     //SendMessage(vControl.Handle, LM_Paint, aImage.Canvas.Handle, 0);
  8.  
  9.     ////BITBLT
  10.     BitBLT(aImage.Canvas.Handle,0,0,aImage.Width,aImage.Height,
  11.                                           GetDC(vControl.Handle),0,0,SRCCOPY);
  12.  
  13.  
  14.   except
  15.     On E: Exception do aImage.Clear;
  16.   end;
  17.   aImage.Canvas.Changed;

jamie

  • Hero Member
  • *****
  • Posts: 6733
Re: Get a screenshot of a form
« Reply #14 on: November 04, 2024, 12:24:31 am »
For windows.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. Var
  3.   B:TBitMap;
  4.   R:TRect;
  5. begin
  6.   GetWindowRect(Handle, R);
  7.   B:= TBitMap.Create;
  8.   B.SetSize(R.Width,R.Height);
  9.   SendMessage(Handle,WM_PRINT,B.Canvas.Handle,PRF_CHILDREN or PRF_NONCLIENT or PRF_CLIENT);
  10.   Form2.Canvas.Draw(0,0,B);
  11.   B.Free;
  12. end;                                                              
  13.  

 This will capture the complete form frame even if it's off the screen a bit, however, you need to ensure the form's client area is fully exposed, which means no scrollbars to capture all of it.

 So, prior to capturing the image, you need to ensure the form is large enough where the complete client area is visible, even if it's off screen, then you will get the complete image along with the FRAME.

 One note here with windows, you will get the XP style frame, not the style you see starting like in Vista.

 Also, you can add "PRF_OWNED" to the list to capture other types of controls within the client area.
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018