Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DrawToBitmap - System.ArgumentException: Parameter is not valid

Im creating a Label and sometimes Im using .DrawToBitmap(). I dont know why, but after Im running my program for a while (and calling .DrawToBitmap() often) I get the exception:

System.ArgumentException: Parameter is not valid.
   at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
   at System.Drawing.Bitmap..ctor(Int32 width, Int32 height)

Somehow I cannot call this function that often. If I would radically try this:

while(true)
{

  System.Windows.Forms.Label label = new Label();

  label.Font = new Font("Arial", 20);
  label.Text = "test";

  try
  {
    Bitmap image = new Bitmap(300, 500);
    label.DrawToBitmap(image, label.ClientRectangle);
  }
  catch (Exception e)
  {
    Console.WriteLine(e);
  }
}

I got after 5-6 secs (1000-2000 calls) the exception. What is the problem? How to avoid this?

Edit: Thank you guys for the idea with Dispose() - somehow everything is working perfect if I use it on label. Even if I dont use it on Bitmap its fine. Both of the answers are great, I can only accept 1 of them :(

like image 572
miri Avatar asked Aug 16 '12 22:08

miri


2 Answers

So, that error message comes from deep down in GDI+ and may appear for a lot of reasons. I see one glaring problem with your code that is a candidate however:

 label.Font = new Font("Arial", 20);

Font objects implement IDisposable and you are creating a lot of them in a tight loop and never calling Dispose(). Same goes for the Bitmap itself. I would bet that GDI is running out of resources.

It's hard to make sense of your code as it stands. It essentially does absolutely nothing but create a ton of Font and Bitmap objects, so I can't even suggest to wrap each of those declarations in a using statement. That aside, when you create a ton of GDI objects in quick succession without disposing of them you will eventually run into this problem.

If you need these objects to be valid for some time then you need to make sure you call Dispose() on them later to release native resources in as timely a manner as possible (the finalizer will do this for you, but it's best not to wait for it to). If they are local objects then wrap them in a using statement so Dispose() will be called when the block exits:

using(var b = new Bitmap(w, h))
{
    // use 'b' for whatever
} // b.Dispose() is called for you
like image 195
Ed S. Avatar answered Nov 12 '22 02:11

Ed S.


GDI+ exceptions are fairly poor, they often don't describe the real issue well. In this case it really means "the bitmap is too large". Which still doesn't it describe it well, you are actually running out of unmanaged memory. The bitmap is too large to fit the amount of memory still available.

Because you are not calling the Dispose() method on the bitmap. You can often skimp on that without noticing trouble. But not with Bitmap, it is a class that takes very little garbage collected memory but a lot of unmanaged memory. It doesn't trigger the garbage collector quick enough to let the finalizer release the unmanaged memory.

The code snippet doesn't make sense, but you'd write it like this to avoid the exception:

using (Bitmap image = new Bitmap(300, 500)) {
    label.DrawToBitmap(image, label.ClientRectangle);
}
like image 24
Hans Passant Avatar answered Nov 12 '22 04:11

Hans Passant