1

I have a Form and in it an Overlay control (transparent gray backcolor with White text over "Drop here..." and an icon) that is visible only when a file is dragged over the Form. The Overlay is made transparent by drawing the control in its back on it and then filling over with transparent gray (ARGB). The method Works very well when the Overlay should be over a Control that is not a Form, but when I use Control.DrawToBitmap to render a Form, not an usual Control, it also renders the title bar and border.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
silviubogan
  • 3,343
  • 3
  • 31
  • 57
  • You only need the right Rectangle so the title bar and borders are excluded. Use the form's RectangleToScreen() with Point.Empty and ClientSize. – Hans Passant Feb 11 '19 at 11:19

3 Answers3

3

Form.DrawToBitmap draws the whole form including non-client area. You can use BitBlt. The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels from the specified source device context into a destination device context.

const int SRCCOPY = 0xCC0020;
[DllImport("gdi32.dll")]
static extern int BitBlt(IntPtr hdc, int x, int y, int cx, int cy,
    IntPtr hdcSrc, int x1, int y1, int rop);

Image PrintClientRectangleToImage()
{
    var bmp = new Bitmap(ClientSize.Width, ClientSize.Height);
    using (var bmpGraphics = Graphics.FromImage(bmp))
    {
        var bmpDC = bmpGraphics.GetHdc();
        using (Graphics formGraphics = Graphics.FromHwnd(this.Handle))
        {
            var formDC = formGraphics.GetHdc();
            BitBlt(bmpDC, 0, 0, ClientSize.Width, ClientSize.Height, formDC, 0, 0, SRCCOPY);
            formGraphics.ReleaseHdc(formDC);
        }
        bmpGraphics.ReleaseHdc(bmpDC);
    }
    return bmp;
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • This method also works if we need to take screenshots of control, which content is rendered by GPU with Direct3D. – komorra May 28 '22 at 11:08
1

The Control.DrawToBitmap method always return a Bitmap drawn from the upper-left corner of the control, even if you pass the method a Rectangle with specific bounds.

Here, the ClientRectangle portion of a Form is translated using the Size of its Bounds.

Note that, if your application is not DPIAware, you might get wrong measures from all the methods that return a Point or a Rectangle. Non-DPIAware Windows API included.

If you need to save the resulting Bitmap, use PNG as the destination format: its loss-less compression is better suited for this kind of rendering.

Call this method with the ClientAreaOnly argument set to true to have it return a Bitmap of the ClientArea only.

public Bitmap FormScreenShot(Form form, bool clientAreaOnly)
{
    var fullSizeBitmap = new Bitmap(form.Width, form.Height, PixelFormat.Format32bppArgb);
    // .Net 4.7+
    fullSizeBitmap.SetResolution(form.DeviceDpi, form.DeviceDpi);

    form.DrawToBitmap(fullSizeBitmap, new Rectangle(Point.Empty, form.Size));
    if (!clientAreaOnly) return fullSizeBitmap;

    Point p = form.PointToScreen(Point.Empty);
    var clientRect =
        new Rectangle(new Point(p.X - form.Bounds.X, p.Y - form.Bounds.Y), form.ClientSize);

    var clientAreaBitmap = fullSizeBitmap.Clone(clientRect, PixelFormat.Format32bppArgb);
    fullSizeBitmap.Dispose();
    return clientAreaBitmap;
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • The [Form.DeviceDpi](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.devicedpi) property is available only in .NET Framework v4.7+. – silviubogan Feb 13 '19 at 13:12
  • There are other means to get that value, but it's a broad matter (for comments). It's just a precaution (the reason why it can be usefull you can read here: [Image is not drawn at the correct spot](https://stackoverflow.com/a/51456467/7444103)). If you are aware of this, you can just remove it. It's not absolutely nececessary. – Jimi Feb 13 '19 at 13:16
0

You could render the whole form and then take only the part you need with Bitmap.Clone(). Here you have explained how to do it.

Pati K
  • 129
  • 2
  • 11