2006-06-12

Reading an image from a file without locking it

When you use Image.FromFile to read an image from a file, the file is locked. The following method reads an image from a file without locking it:
public static class Utils
{
    public static Image ImageFromFile(string fileName)
    {
        if (fileName == null) throw new ArgumentNullException("fileName");

        using(FileStream lStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
            return Image.FromStream(lStream);
    }
}
Here's an example how to use it:
// old method that locks the file:
Image img = Image.FromFile("picture.jpg");
// new method that does not lock the file:
Image img = Utils.ImageFromFile("picture.jpg");
Tags: .

5 comments:

Anonymous said...

Thanks! Very helpful.

Anonymous said...

yeah very nice for those lazy types like me :)

Anonymous said...

Thanks a lot for this trick!

Anonymous said...

Thank you so much for this little bit of code. I've spent days looking for this to solve an issue with the locking of image files. Now EVERYTHING WORKS!

Raghavendra, K. said...

This works fine as long as you are only trying to display it in a PictureBox or drawing it yourself onto the screen.

Try saving the image back to file and you will be greeted with the following exception:

System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.

This happens because, the Image class is trying to access the underlying stream which was used to load the image. However, since the FileStream is closed, you get this "not so helpful" exception.

Till now the only way I have figured to avoid this situation is to actually create another In-memory copy of the image and then use the copy to do all further manipulations.

Example code:
public static Image SafeLoadImageFromFile(string imgFilePath)
{
Bitmap retVal = null;
using (Image tmpImage = Image.FromFile(imgFilePath))
{
retVal = new Bitmap(tmpImage.Width, tmpImage.Height);
retVal.SetResolution(tmpImage.VerticalResolution, tmpImage.HorizontalResolution);

using (Graphics g = Graphics.FromImage(retVal))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;

Rectangle rect = new Rectangle(0, 0, tmpImage.Width, tmpImage.Height);

g.DrawImage(tmpImage, rect, rect, GraphicsUnit.Pixel);
}
}

return retVal;
}

This obviously has serious overheads on the memory and CPU. But, as of now, this is the only way I have found of loading an image without locking the file, but at the same time being able to manipulate and save image later on.

Let me know if any of you come up with a better solution.