tags:

views:

58

answers:

2

I'm currently attempting to take snapshot of a specified portion of my application's window from a specified starting coordinate (which is where my problem comes in).

Rectangle bounds = new Rectangle((this.Width/2)-400,(this.Height/2)-200, 800,400);

using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb))
{   
    using (Graphics graphics = Graphics.FromImage(bitmap))
    {
        IntPtr hdc = graphics.GetHdc();
        PrintWindow(this.axS.Handle, hdc, 0);
        graphics.ReleaseHdc(hdc);
        graphics.Flush();
        string file = "example.png";
        bitmap.Save(file, ImageFormat.Png);
    }
}

I'm attempting to make a dynamic-adaptive method to take a screenshot of the center of the window, even after being resized. I'm not sure how to apply x and y to the screenshot as a starting point for the screenshot. Dimensions will always remain 800,400 and always taking a screenshot of the center of the application regardless of window size.

Every attempt I have pegged, the bitmap took a screenshot from 0 (+800), 0 (+400) where 0, 0 I need to change.

Is Bitmap capable of this? If not, what other method could I use?

A: 

Instead of using PrintWindow try using Graphics.CopyFromScreen which allows you to specify both an upper-left corner as well as dimensions.

http://msdn.microsoft.com/en-us/library/6yfzc507.aspx

Performs a bit-block transfer of color data, corresponding to a rectangle of pixels, from the screen to the drawing surface of the Graphics.

CopyFromScreen works on screen coordinates so you'll have to calculate that for the call.

Sam
That would seem like a solution, however, the first thing that came to mind was multi-monitors; I'm unsure if that would be compatible or would be ensued by a multitude of problems. Is there any 'local' method (as `PrintWindow` does, utilizing only the application window)? I'm not entirely sure how I would get the coordinates on the screen. I assume it would involve a function to get the position of the window (also assuming the position returned would be an XY coordinate of the top-left corner of the application), and would have to compensate for the title bar and window border?
Salt
A: 

You can use SetViewportOrgEx to set the origin on the HDC. I found that the title bar of the window was throwing off the calculation of the center point, so I took that into account as well.

int x = (this.Width / 2) - 400;
int y = ((this.Height + SystemInformation.CaptionHeight) / 2) - 200;

Rectangle bounds = new Rectangle(x, y, 800, 400);

using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb))
{
    using (Graphics graphics = Graphics.FromImage(bitmap))
    {
        IntPtr hdc = graphics.GetHdc();
        POINT pt;

        SetViewportOrgEx(hdc, -x, -y, out pt);

        // rest as before
    }
}

And the signatures for SetViewportOrgEx and POINT:

[DllImport("gdi32.dll")]
static extern bool SetViewportOrgEx(IntPtr hdc, int X, int Y, out POINT lpPoint);

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int X;
    public int Y;

    public POINT(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }

    public static implicit operator System.Drawing.Point(POINT p)
    {
        return new System.Drawing.Point(p.X, p.Y);
    }

    public static implicit operator POINT(System.Drawing.Point p)
    {
        return new POINT(p.X, p.Y);
    }
}
adrift
Thanks, adrift! Seems to be working perfectly. I don't necessarily understand /how/ it worked; something I'll look into later. :)
Salt
@Salt, you're welcome, and if you find your captures are not exactly centered, please see the updated code above to take the title bar height into account.
adrift
The center was a few 30 pixels off; I trial-and-error'd until I got it pixel-perfect. However, I strive for efficiency, so I'll make the necessary modifications. I sincerely appreciate your and Sam's effort in helping me. :)
Salt