Recent

Author Topic: Saving form contents as image partially  (Read 10193 times)

Leledumbo

  • Hero Member
  • *****
  • Posts: 8523
  • Programming + Glam Metal + Tae Kwon Do = Me
Saving form contents as image partially
« on: March 25, 2010, 01:22:58 pm »
I have an application with this layout:
Code: [Select]
+--Form---+
|+-------+|
|| Image ||
|+-------+|
|+-------+|
|| Panel ||
|+-------+|
|+-------+|
||Button ||
|+-------+|
+---------+
And I need to save as image the image and panel part. How can I do so?

So far, though haven't tried, my crazy idea is to copy Canvas.Pixels from top left of image to bottom right of panel. But I'm not sure.
Follow this if you want me to answer: **://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

**://pascalgeek.blogspot.com
**s://bitbucket.org/leledumbohttps://github.com/leledumbo
Code first, think later - Natural programmer B)

LazaruX

  • Hero Member
  • *****
  • Posts: 597
  • Lazarus original cheetah.The cheetah doesn't cheat
Re: Saving form contents as image partially
« Reply #1 on: March 25, 2010, 01:29:09 pm »
Do you mean making a kind of screenshot of Image and Panel together? If you mean this, you could just try to make a partial screenshot.

Zoran

  • Hero Member
  • *****
  • Posts: 1757
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Saving form contents as image partially
« Reply #2 on: March 25, 2010, 01:45:52 pm »
I found this on Wiki:

**://wiki.lazarus.freepascal.org/Developing_with_Graphics#Taking_a_screenshot_of_the_screen

I haven't tried it though.

Zoran

  • Hero Member
  • *****
  • Posts: 1757
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Saving form contents as image partially
« Reply #3 on: March 25, 2010, 02:10:43 pm »
Now I tried and this saves the screenshot of the form:

Code: [Select]
procedure TForm1.Button2Click(Sender: TObject);
var
  MyBitmap: TBitmap;
  MyDC: HDC;
begin
  MyDC := GetDC(Self.Handle);
  MyBitmap := TBitmap.Create;
  try
    MyBitmap.LoadFromDevice(MyDC);
    MyBitmap.SaveToFile('FormsAppearance.bmp');
  finally
    ReleaseDC(Self.Handle, MyDC);
    FreeAndNil(MyBitmap);
  end;
end;


Leledumbo

  • Hero Member
  • *****
  • Posts: 8523
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Saving form contents as image partially
« Reply #4 on: March 26, 2010, 05:30:53 am »
Quote
you could just try to make a partial screenshot
That's another idea, too. The problem is, what do I have to set to limit the region of the TBitmap (my knowledge about this class isn't too deep)? Plus, is there any easy way to get the top left of the image and bottom right of the panel? The screenshot will take a whole screen, so I can't use relative position to the form.
Quote
I found this on Wiki
Yes, I've seen that page. Combined with what BPsoftware suggests, I can make it right.
Follow this if you want me to answer: **://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

**://pascalgeek.blogspot.com
**s://bitbucket.org/leledumbohttps://github.com/leledumbo
Code first, think later - Natural programmer B)

Zoran

  • Hero Member
  • *****
  • Posts: 1757
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Saving form contents as image partially
« Reply #5 on: March 26, 2010, 06:06:19 am »
Only now I understand what you actually asked, sorry.

I beleive that this is what you want:

Code: [Select]
uses
  ...,  LCLIntf, LCLType;

...

procedure TForm1.Button2Click(Sender: TObject);
var
  MyBitmap, MyBitmap2: TBitmap;
  MyDC: HDC;
  R: TRect;
begin
  MyBitmap2 := TBitmap.Create;
  MyBitmap := TBitmap.Create;
  try
    MyDC := GetDC(Self.Handle);
    try
      MyBitmap.LoadFromDevice(MyDC);

    finally
      ReleaseDC(Self.Handle, MyDC);
    end;

    R.TopLeft := Image1.BoundsRect.TopLeft;
    R.BottomRight := Panel1.BoundsRect.BottomRight;

    MyBitmap2.Width := R.Right - R.Left;
    MyBitmap2.Height := R.Bottom - R.Top;

    MyBitmap2.Canvas.CopyRect(Rect(0, 0, MyBitmap2.Width, MyBitmap2.Height),
                                      MyBitmap.Canvas, R);
    MyBitmap2.SaveToFile('ImageAndPanel.bmp');
  finally
    FreeAndNil(MyBitmap);
    FreeAndNil(MyBitmap2);
  end;
end;

Leledumbo

  • Hero Member
  • *****
  • Posts: 8523
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Saving form contents as image partially
« Reply #6 on: April 06, 2010, 04:18:07 am »
Thanks, Zoran. I implemented it more or less the same as you do, except that I use ControlToScreen to get screen coordinates of the image and panel.

However, after trying it myself I conclude that taking screenshot and CopyRect-ing it isn't a good idea. I ask the user for a filename before saving it, and it tries to get the screenshot before the save dialog really closes, so the dialog is included in the image. The temporary solution is to call Sleep() with some value (currently 500) before LoadFromDevice(), this will give (enough?) time for the dialog to close. If anyone has a better idea, please tell me.
Follow this if you want me to answer: **://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

**://pascalgeek.blogspot.com
**s://bitbucket.org/leledumbohttps://github.com/leledumbo
Code first, think later - Natural programmer B)

Zoran

  • Hero Member
  • *****
  • Posts: 1757
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: Saving form contents as image partially
« Reply #7 on: April 12, 2010, 09:44:40 am »
Thanks, Zoran. I implemented it more or less the same as you do, except that I use ControlToScreen to get screen coordinates of the image and panel.

However, after trying it myself I conclude that taking screenshot and CopyRect-ing it isn't a good idea. I ask the user for a filename before saving it, and it tries to get the screenshot before the save dialog really closes, so the dialog is included in the image. The temporary solution is to call Sleep() with some value (currently 500) before LoadFromDevice(), this will give (enough?) time for the dialog to close. If anyone has a better idea, please tell me.

I found a solution, you must call Application.ProcessMessages.

This works:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  MyBitmap, MyBitmap2: TBitmap;
  MyDC: HDC;
  R: TRect;
  S: String;
begin
  if InputQuery(Application.Title, 'Your password:', True, S) then begin
    if S = 'pass' then begin
      Application.ProcessMessages;
      MyBitmap2 := TBitmap.Create;
      MyBitmap := TBitmap.Create;
      try
        MyDC := GetDC(Self.Handle);
        try
          MyBitmap.LoadFromDevice(MyDC);

        finally
          ReleaseDC(Self.Handle, MyDC);
        end;

        R.TopLeft := Image1.BoundsRect.TopLeft;
        R.BottomRight := Panel1.BoundsRect.BottomRight;

        MyBitmap2.Width := R.Right - R.Left;
        MyBitmap2.Height := R.Bottom - R.Top;

        MyBitmap2.Canvas.CopyRect(Rect(0, 0, MyBitmap2.Width, MyBitmap2.Height),
                                          MyBitmap.Canvas, R);
        MyBitmap2.SaveToFile('ImageAndPanel.bmp');
      finally
        FreeAndNil(MyBitmap);
        FreeAndNil(MyBitmap2);
      end;

    end else
      ShowMessage('Wrong password');

  end;
end;

The password dialog is not actually removed from screen (and the main form is not repainted yet) until the Application.ProcessMessages is called.

It gets called automaticaly AFTER the buttons message handler, but you need to call it before taking the screenshot, so the solution is rather simple -- call it manually!
« Last Edit: April 12, 2010, 09:46:39 am by Zoran »

 

TinyPortal © 2005-2018