1

I am developing an desktop application using C#, Winforms, and MS Visual Studio 2010. In the application, I have to take the screenshot of a panel of a form and save the image in disc. The panel size can be large. I have used Panel.DrawToBitmap() method to save the image of the panel. But, when the panel size is too large, it throws exception. I have found in msdn ( http://msdn.microsoft.com/en-us/library/system.windows.forms.control.drawtobitmap%28v=vs.110%29.aspx) that for large size control, the method Control.DrawToBitmap will not work. Is there any alternative way, I can achieve the similar behavior overcoming the size limitation. It is to be noted the panel size can vary.

Update: I have found alternative of Control.DrawToBitmap : WebBrowser.DrawToBitmap() or other methods?. But, it only captures the visible part of the control.

Community
  • 1
  • 1
rksajib
  • 180
  • 1
  • 14
  • What numbers are we talking about? Can you give us the sizes you may need? – TaW Dec 08 '14 at 14:59
  • Is this happening consistently, or first after your program has been running for a while? In the latter case, maybe you need to dispose of some resources - see here: http://stackoverflow.com/questions/11996335/drawtobitmap-system-argumentexception-parameter-is-not-valid – RenniePet Dec 08 '14 at 15:23
  • *"How to overcome [whatever winforms limitation]"* - use current, non deprecated technology. winforms doesn't support anything. – Federico Berasategui Dec 08 '14 at 15:56
  • @HighCore: WinForms deprecated? Where does it say that? – RenniePet Dec 08 '14 at 17:23
  • @RenniePet is COBOL deprecated? where does it say that? – Federico Berasategui Dec 08 '14 at 17:25
  • @Taw: around height greater than 20000 and width greater than 9000. – rksajib Dec 08 '14 at 17:50
  • @RenniePet: I have alteady seen that. My problem is quite simple to reproduce. You can just create a winform application add a form with a panel with big size. in the code call panel.DrawToBitmap inside try block and catch the ecception. – rksajib Dec 08 '14 at 17:54
  • 4
    @Highcore: please don't bring back unnecessary discussion here degressing from the topic – rksajib Dec 08 '14 at 17:56
  • @rksajib I'm actually telling you the solution, not brining unnecessary discussion. If you want to overcome winforms' limitations, then use current technology. Period. – Federico Berasategui Dec 08 '14 at 18:02
  • "height greater than 20000 and width greater than 9000" ... Now I'm curious, what kind of screen has that many pixels? Or are you talking about a Panel control where only a small portion of it is visible, but you want to grab the whole panel anyway? – RenniePet Dec 08 '14 at 19:27
  • @HighCore: It's an old application with lots of legacy code, switching from winforms is not feasible right now. – rksajib Dec 09 '14 at 03:25
  • @RenniePet: The screen is usual screen. Yes. The panel control sometimes is so large that we have to use horizontal and vertical scroll bar to see other portions and Yes, I want to grab the whole panel. – rksajib Dec 09 '14 at 03:28

1 Answers1

2

This question had me confused about quite a few things..

Here is a solution that writes an image file from a Panel of rather large sizes..

One of the limiting factors is the size of the resulting Bitmap. I have tested for sizes of up to 12.5k * 25k and found it to work fine; the sizes may depend on your machine, though. I think you need quite some contiguous memory to create such a large Bitmap.

The other problem is, as your title suggests, indeed with the DrawToBitmap method itself. It looks as if it can't reliably write onto large Bitmaps, which is why I had to buffer its results in a temporary Bitmap. Nor can it work if any dimension of the control is over some size, maybe 4k, but maybe not..

The solution first creates a Bitmap of the Panel's size. Then it creates a temporary Panel to house the large Panel. This container it small enough for DrawToBitmap to work.

Then it loops over the width and height, moving the large Panel up and left, pasting the portions DrawToBitmap brings back, step by step into the large Bitmap.

Finally it writes it back as PNG for best readability and size..

private void button2_Click(object sender, EventArgs e)
{
    Bitmap bmp = new Bitmap(largePanel.ClientSize.Width, largePanel.ClientSize.Height);

    DrawToBitmap(largePanel, bmp);      // the patchwork method

    bmp.Save(yourFileName, System.Drawing.Imaging.ImageFormat.Png);
    bmp.Dispose();                      // get rid of the big one!

    GC.Collect();                       // not sure why, but it helped
}


void DrawToBitmap(Control ctl, Bitmap bmp)
{
    Cursor = Cursors.WaitCursor;         // yes it takes a while
    Panel p = new Panel();               // the containing panel
    Point oldLocation = ctl.Location;    // 
    p.Location = Point.Empty;            //
    this.Controls.Add(p);                //

    int maxWidth = 2000;                 // you may want to try other sizes
    int maxHeight = 2000;                //

    Bitmap bmp2 = new Bitmap(maxWidth, maxHeight);  // the buffer

    p.Height = maxHeight;               // set up the..
    p.Width = maxWidth;                 // ..container

    ctl.Location = new Point(0, 0);     // starting point
    ctl.Parent = p;                     // inside the container
    p.Show();                           // 
    p.BringToFront();                   //

    // we'll draw onto the large bitmap with G
    using (Graphics G = Graphics.FromImage(bmp))
    for (int y = 0; y < ctl.Height; y += maxHeight)
    {
        ctl.Top = -y;                   // move up
        for (int x = 0; x < ctl.Width; x += maxWidth)
        {
            ctl.Left = -x;             // move left
            p.DrawToBitmap(bmp2, new Rectangle(0, 0, maxWidth, maxHeight));
            G.DrawImage(bmp2, x, y);   // patch together
        }
    }

    ctl.Location = p.Location;         // restore..
    ctl.Parent = this;                 // form layout <<<==== ***
    p.Dispose();                       // clean up

    Cursor = Cursors.Default;          // done
}

I have drawn a few things onto the Panel and thrown in a few hundred Buttons and the result looks seamless. Can't post it, for obvious reasons..

*** Note: If your Panel doesn't sit on the form you should change this to the real Parent!

TaW
  • 53,122
  • 8
  • 69
  • 111