Monday, June 16, 2008

Bitmap Clone vs new Bitmap vs ???

I was loading a Bitmap Image from a FileStream and calling the Image.Clone function.  When I tried to save the Image to another file I got the following error "A generic error occurred in GDI+", below is the exact code I was using:

In  Class1.Function1 I had the following:

public Bitmap Functon1(string tempFileName)
{
                Bitmap bm;
                System.IO.FileStream fs;
                fs = new FileStream(tempFileName, FileMode.Open, FileAccess.Read);
                try
                {
                    bm = (Bitmap)System.Drawing.Bitmap.FromStream(fs);
                }
                catch
                {
                    throw;
                }
                finally
                {
                    fs.Close(); // I want to make sure the stream is closed
                }

                return (Bitmap)bm.Clone();
}
I placed the returned Bitmap into an ArrayList, called ListType.  Later on in the program I did the following and got the GDI+ error:
                pic.Image = (Bitmap)ListType[i];
                Bitmap tempImage = (Bitmap)pic.Image.Clone();
                tempImage.Save(@"c:\temp\file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

One solution was to replace, and I no longer got my error.
                Bitmap tempImage = (Bitmap)pic.Image.Clone();
With
                Bitmap tempImage = new Bitmap(pic.Image);

That seemed to work.  However, another developer that was using my program was using an Image Library that did a deep clone, and whenever he ran his clone method on the image in my ArrayList he got the GDI+ error.  Therefore, I felt that I had to change my Function1.  I found a solution on the following website:
http://forums.msdn.microsoft.com/en-US/netfxbcl/thread/970a7951-19f3-4ca3-8061-683b96c11a88/

The solution in my Function was:
        static public Bitmap Function1 (string tempFileName)
        {
            try
            {              
                using (FileStream fs = new FileStream(@tempFileName, FileMode.Open))
                {
                    int len = (int)fs.Length;
                    byte[] buf = new byte[len];
                    fs.Read(buf, 0, len);
                    using (MemoryStream ms = new MemoryStream(buf))
                    {
                        return new Bitmap(ms);
                    }
                }
         }

This solved the problem when the other developer called his deep clone method.  The explanation from the author of this block of code was:
GDI+ holds on to the stream handle and puts a lock on the file. Cloning is handled by GDI+, it probably copies the file handle too. You'll find that saving back the image to the same file will generate an exception too. The workaround is to load the image into memory first so GDI+ can't lock anything. For example:

Anyways, thats about it.

-- Ted



No comments: