Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Windows form Control to Image?

I am trying to create an image of a Panel and save it to a folder. The problem is the panel has scrollbars and the image generated is only for the visible portion of the Panel.

The code I use is something like Panel.DrawToImage. Could there be any help out here to save the entire Panel as a picture and not just the visible portion?

like image 305
Shri Avatar asked Feb 27 '23 22:02

Shri


1 Answers

I think the WM_PRINT message is going to be helpful. Here's a sample that almost works. (It still prints the scrollbars themselves, and the background is lost on the "out of scroll" portions.) Perhaps you can play with this and get it working, or someone with more WinForms experience can take this to the next level?

Declare the following in your class:

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

private const int WM_PRINT = 791;

/// <summary>
/// The WM_PRINT drawing options
/// </summary>
[Flags]
private enum DrawingOptions
{
    /// <summary>
    /// Draws the window only if it is visible.
    /// </summary>
    PRF_CHECKVISIBLE = 1,

    /// <summary>
    /// Draws the nonclient area of the window.
    /// </summary>
    PRF_NONCLIENT = 2,
    /// <summary>

    /// Draws the client area of the window.
    /// </summary>
    PRF_CLIENT = 4,

    /// <summary>
    /// Erases the background before drawing the window.
    /// </summary>
    PRF_ERASEBKGND = 8,

    /// <summary>
    /// Draws all visible children windows.
    /// </summary>
    PRF_CHILDREN = 16,

    /// <summary>
    /// Draws all owned windows.
    /// </summary>
    PRF_OWNED = 32
}

Then, to paint the control to a bitmap:

using (Bitmap screenshot = new Bitmap(this.panel1.DisplayRectangle.Width, this.panel1.DisplayRectangle.Height))
using (Graphics g = Graphics.FromImage(screenshot))
{
    try
    {
        SendMessage(this.panel1.Handle, WM_PRINT, g.GetHdc().ToInt32(), (int)(DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_NONCLIENT | DrawingOptions.PRF_OWNED));
    }
    finally
    {
        g.ReleaseHdc();
    }
    screenshot.Save("temp.bmp");
}

EDIT: Here's an alternate paint strategy that might get you what you're looking for. I'm making some assumptions, but perhaps it will work. It paints a dummy background on the Bitmap first, and also removes the scrollbars:

using (Bitmap screenshot = new Bitmap(this.panel1.DisplayRectangle.Width, this.panel1.DisplayRectangle.Height))
using (Graphics g = Graphics.FromImage(screenshot))
{
    g.FillRectangle(SystemBrushes.Control, 0, 0, screenshot.Width, screenshot.Height);
    try
    {
        SendMessage(this.panel1.Handle, WM_PRINT, g.GetHdc().ToInt32(), (int)(DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_OWNED));
    }
    finally
    {
        g.ReleaseHdc();
    }
    screenshot.Save("temp.bmp");
}
like image 183
Dave Mateer Avatar answered Mar 08 '23 03:03

Dave Mateer