开发者

Generic GDI+ Error: Avoided when calling GC.Collect()

开发者 https://www.devze.com 2023-02-25 10:35 出处:网络
I have this piece of Code (\"ruta1\" and \"ruta2\" are strings containing the path to different images):

I have this piece of Code ("ruta1" and "ruta2" are strings containing the path to different images):

   Bitmap pic;
   Bitmap b = new Bitmap(SomeWidth, SomeHeight);
   g = Graphics.FromImage(b);
   g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);

   b.Save(ruta2, ImageFormat.Jpeg);
   g.Dispose();
   b.Dispose();

   b = new Bitmap(OtherWidth, OtherHeight);
   pic = new Bitmap(ruta2);开发者_运维知识库
   g = Graphics.FromImage(b);
   g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);
   g.DrawImage(pic, 0, 0, pic.Height, pic.Width); 

   pic.Dispose();
   b.Save(ruta2, ImageFormat.Jpeg);
   g.Dispose();
   b.Dispose();

   pic = new Bitmap(ruta1);
   b = new Bitmap(AnotherWidth, AnotherHeight);
   g = Graphics.FromImage(b);
   g.FillRectangle(new SolidBrush(Color.White), 0, 0, b.Width, b.Height);

   int k = 1;

   // I just draw the "pic" in a pattern on "b"
   for (h = 0; h <= b.Height; h += pic.Height)
       for (w = 0; w <= b.Width; w += pic.Width)
            g.DrawImage(pic, w, h, k * pic.Width, k * pic.Height);

   pic.Dispose();            
   GC.Collect();  // If I comment this line, I get a "generic GDI+ Error" Exception
   b.Save(ruta1, ImageFormat.Jpeg);
   g.Dispose();
   b.Dispose();

It doesn't matter if I set pic = null after disposing it, if I don't call the Garbage Collector, I got a "Generic GDI+ Error" exception. Only when I call the Garbage Collector, my program goes ok, all times.

Can somebody explain this behavior? Does it depend on the .Net framework version? I'm using Visual C# Express 2008, with .Net framework 3.5


First, it would be nice if you were using the "using" keyword to scope the use of your disposable objects (like Bitmap and Graphics), instead of calling Dispose() manually on each. Using "using" is better for lots of reasons like cleaning up stuff when an exception is thrown, but it also greatly helps for code readability.

Second, GDI brushes are also IDisposable objects, so you shouldn't create-and-forget them. Do this instead:

using (var brush = new SolidBrush(Color.White))
{
    g.FillRectangle(brush, 0, 0, width, height)
}

...or better yet, create your brushes at the start of your application, and hang on to them until the end (but don't forget to dispose of them too). IIRC, creating/disposing brushes impacts performance quite a lot if done frequently.

Third, I believe your bug is in the 2nd section:

  1. You open image "ruta2"
  2. You create a new image
  3. You draw the contents of "ruta2" inside that new image
  4. You save that new thing on top of the "ruta2" file, but the original image from step 1 is still loaded, and probably has some handle on the "ruta2" file, so you need to dispose of it before you overwrite the file.

If you refactor that 2nd section like this, it should work:

using (var b = new Bitmap(OtherWidth, OtherHeight))
using (var g = Graphics.FromImage(b))
{
     using (var brush = new SolidBrush(Color.Red))
     {
         g.FillRectangle(brush, 0, 0, b.Width, b.Height);
     }
     using (var pic = new Bitmap(ruta2))
     {
         g.DrawImage(pic, 0, 0, pic.Height, pic.Width);
     }
     b.Save(ruta2, ImageFormat.Jpeg);
 }
0

精彩评论

暂无评论...
验证码 换一张
取 消