Lazarus

Programming => General => Topic started by: SaraT on April 08, 2020, 10:46:36 pm

Title: SOLVED: Capturing a Panel inside ScrollBox
Post by: SaraT on April 08, 2020, 10:46:36 pm
Hi there,

I want to save a Panel to image but the saved image has a part in black.
The scrollbox is hidding the rest of the Panel.

How can I take a screen shot of the whole panel?

See attached gif. Thanks a lot.

Used code:
Code: Pascal  [Select][+][-]
  1. var
  2.   bmp: TBitmap;
  3.   d:THandle;
  4. begin
  5.   d:=GetDC(Panel1.Handle);
  6.   bmp := TBitmap.Create;
  7.   bmp.Width := Panel1.Width;
  8.   bmp.Height := Panel1.Height;
  9.   bmp.LoadFromDevice(d);
  10.   bmp.SaveToFile('C:\Users\Username\Desktop\test.bmp');
  11.   bmp.Free;
  12.   ReleaseDC(Panel1.Handle, d);
Title: Re: Capturing a Panel inside ScrollBox
Post by: jamie on April 08, 2020, 10:53:48 pm
You have PaintTo, but I thinking it isn't going to work for you if it's covered up..

of course you prep a Tbitmap to accept it.


 You could always use a Timageā€¦

Title: Re: Capturing a Panel inside ScrollBox
Post by: winni on April 09, 2020, 12:20:12 am
Hi!

If you make a screenshot with

LoadFromDevice

it does exactly what the names says:

It shots all visible parts of a visible element.
If a part is hidden it can not be shot.
Like a camera.

Further : give all message or dialog boxes time to vanish with an
application.processmessages.

I once took a screenshot with a big black rectangle in the middle:
That was the "leftover" of the file save dialog because it was not complete closed, when the screenshot was done.

Winni
Title: Re: Capturing a Panel inside ScrollBox
Post by: eljo on April 09, 2020, 03:12:41 am
Sorry the way the windows widgets works that is not possible. Why not just copy everything from the image directly?
Title: Re: Capturing a Panel inside ScrollBox
Post by: SaraT on April 09, 2020, 04:13:29 am
Sorry the way the windows widgets works that is not possible. Why not just copy everything from the image directly?
Thnx coders,

@eljo, I have others TImages controls with transparent png (like layers) so I have to do a screenshot the panel.

Estructure (bottom to up):

->TImage...
->TImage (smaller than main)
->Timage (main background)
Panel container
Title: Re: Capturing a Panel inside ScrollBox
Post by: eljo on April 09, 2020, 04:35:38 am
@eljo, I have others TImages controls with transparent png (like layers) so I have to do a screenshot the panel.

Estructure (bottom to up):

->TImage...
->TImage (smaller than main)
->Timage (main background)
Panel container
That does not change the fact that the portion that is outside the visible area of the scrollbox is not painted at all. There is nothing on screen to capture.
You have to create a bitmap, set its size to the maximum size required to paint everything then work your way up the EStructure from bottom to top and use bitmap.canvas.draw(x,y, imageX.picture) to paint the different graphics on the bitmap then save it, copy it to the clipboard, or print it as you need.
Title: Re: Capturing a Panel inside ScrollBox
Post by: bobkos on April 09, 2020, 08:15:56 am
Some time ago I've wrote the following function:

Code: Pascal  [Select][+][-]
  1. function ScrollBox2Bmp(const ExportArea:THandle;ScrollArea:TScrollBox;ReportFile:string;CompressFile:boolean):boolean;
  2. var
  3.   ScrollStep:integer;
  4.   MySCRcap:THandle;
  5.   bmp,buff:TBitmap;
  6.   SourceRect,DestRect:TRect;
  7.   jpg:TJPEGImage;
  8. begin
  9.   Result:=True;
  10.   ScrollStep:=ScrollArea.ClientHeight;
  11.   ScrollArea.VertScrollBar.Position:=0;
  12.   ScrollArea.Refresh;
  13.   buff:=TBitmap.Create;
  14.   bmp:=TBitmap.Create;
  15.   MySCRcap:=GetDC(ExportArea);
  16.   buff.LoadFromDevice(MySCRcap);
  17.   ReleaseDC(ExportArea,MySCRcap);
  18.   bmp.Assign(buff);
  19.   repeat
  20.     if ScrollArea.VertScrollBar.Position+ScrollStep >= ScrollArea.VertScrollBar.Range-ScrollArea.ClientHeight then repeat
  21.       dec(ScrollStep,1);
  22.     until ScrollArea.VertScrollBar.Position+ScrollStep <= ScrollArea.VertScrollBar.Range-ScrollArea.ClientHeight;
  23.     ScrollArea.VertScrollBar.Position:=ScrollArea.VertScrollBar.Position+ScrollStep;
  24.     ScrollArea.Refresh;
  25.     MySCRcap:=GetDC(ExportArea);
  26.     buff.LoadFromDevice(MySCRcap);
  27.     ReleaseDC(ExportArea,MySCRcap);
  28.     bmp.Height:=bmp.Height+ScrollStep;
  29.     SourceRect:=Rect(0,buff.Height-ScrollStep,buff.Width,buff.Height);
  30.     DestRect:=Rect(0,bmp.Height-ScrollStep,bmp.Width,bmp.Height);
  31.     bmp.Canvas.CopyRect(DestRect,buff.Canvas,SourceRect);
  32.   until (ScrollArea.VertScrollBar.Position >= ScrollArea.VertScrollBar.Range-ScrollArea.ClientHeight);
  33.   FreeAndNil(buff);
  34.   bmp.Width:=ScrollArea.ClientWidth;
  35.   jpg:=TJPEGImage.Create;
  36.   jpg.Assign(bmp);
  37.   jpg.CompressionQuality:=CompressRatio;
  38.   try
  39.     if CompressFile then jpg.SaveToFile(ReportFile) else bmp.SaveToFile(ReportFile);
  40.   except
  41.     Result:=False;
  42.   end;
  43.   FreeAndNil(jpg);
  44.   FreeAndNil(bmp);
  45.   ScrollArea.VertScrollBar.Position:=0;
  46.   ScrollArea.Refresh;
  47. end;
  48.  

I believe you can try to use it.
Title: Re: Capturing a Panel inside ScrollBox
Post by: zeljko on April 09, 2020, 09:14:38 am
Hi there,

I want to save a Panel to image but the saved image has a part in black.
The scrollbox is hidding the rest of the Panel.

How can I take a screen shot of the whole panel?

See attached gif. Thanks a lot.

Used code:
Code: Pascal  [Select][+][-]
  1. var
  2.   bmp: TBitmap;
  3.   d:THandle;
  4. begin
  5.   d:=GetDC(Panel1.Handle);
  6.   bmp := TBitmap.Create;
  7.   bmp.Width := Panel1.Width;
  8.   bmp.Height := Panel1.Height;
  9.   bmp.LoadFromDevice(d);
  10.   bmp.SaveToFile('C:\Users\Username\Desktop\test.bmp');
  11.   bmp.Free;
  12.   ReleaseDC(Panel1.Handle, d);

Try with Panel1.PaintTo(). Don't know what widgetset you use, but under qt/qt5 everything works fine with PaintTo() and LoadFromDevice().
Note that LoadFromDevice() takes screenshoot of control, so if it's obscured by some other window you'll get garbled output.
Title: Re: Capturing a Panel inside ScrollBox
Post by: jamie on April 09, 2020, 01:04:23 pm
Its best to have a background image.

In the end you'll go this way.. ;)

The Display wasn't designed to be used this way.

if you were doing gaming/GL stuff then you would have buffers of the image but this leads us back to just using a Timage or a background TBitmap to contain your image you display in the panel
Title: Re: Capturing a Panel inside ScrollBox
Post by: SaraT on April 09, 2020, 06:54:36 pm
Try with Panel1.PaintTo(). Don't know what widgetset you use, but under qt/qt5 everything works fine with PaintTo() and LoadFromDevice().
Note that LoadFromDevice() takes screenshoot of control, so if it's obscured by some other window you'll get garbled output.

Hi @zeljko, it worked like a charm with PaintTo(). No more missing part even if the window is smaller than scrollbox.
Below the final code.

Many thanks guys, for all your help.

Code: Pascal  [Select][+][-]
  1. bmp := TBitmap.Create;
  2. bmp.Width := Panel1.Width;
  3. bmp.Height := Panel1.Height;
  4. Panel1.PaintTo(bmp.Canvas,0,0);
  5. bmp.SaveToFile('C:\Users\Username\Desktop\test.bmp');
  6. bmp.Free;
TinyPortal © 2005-2018