79

I'm using the following line of code to open an Image from a file:

pictureBox1.Image = Image.FromFile("test.png");

I expect it to lock the file, load the image to memory, set pictureBox1.Image to the copy in memory, and release the lock. In reality, the lock won't go away until I Dispose() of the Image in memory. I can not release the lock on the file on the harddrive that I am no longer using until I get rid of the file in memory that I am using.
Microsoft's site mentions it in a C#-labeled article, but their solution is written in visual basic, which is useless to me.

In summary: I want to set pictureBox1.Image to the image stored in "test.png", then let the user edit or delete "test.png" or whatever.

Fedor
  • 1,548
  • 3
  • 28
  • 38
Eagle-Eye
  • 1,468
  • 2
  • 18
  • 26
  • 6
    The advantage of .Net is that a VB code is easy to translate to C#, and vice-versa : http://www.developerfusion.com/tools/convert/vb-to-csharp/ – thomasb Jan 02 '12 at 14:10
  • Your image is a GIF? Current answers in this entry won't work for that. See this instead https://stackoverflow.com/a/22017675/354756 – daniloquio Nov 30 '17 at 02:31

5 Answers5

111

The approach with stream is not correct.

See here https://stackoverflow.com/a/8701748/355264

Correct code from above link:

Image img;
using (var bmpTemp = new Bitmap("image_file_path"))
{
    img = new Bitmap(bmpTemp);
}
Community
  • 1
  • 1
net_prog
  • 9,921
  • 16
  • 55
  • 70
  • 1
    For a good discussion of what's going on, see [this answer](http://stackoverflow.com/a/13935966/3367144). Notably, the `.Clone()` method will keep the file locked, even after the original is `.Disposed()`. Copy-constructed clones, as in this answer, are the way to do it. – kdbanman Aug 19 '15 at 18:41
  • 1
    [Better approach](http://stackoverflow.com/a/7972963/199364) if you want to retain the PixelFormat of the original bitmap. – ToolmakerSteve Oct 07 '16 at 23:17
52

Or better yet, use a using statement (the code below is otherwise copied from sylon's [deleted] post). This way if the Image.FromStream throws an exception, you can still be assured that the stream is immediately closed.

using (FileStream stream = new FileStream("test.png", FileMode.Open, FileAccess.Read))
{
    pictureBox1.Image = Image.FromStream(stream);
}
Sumner Evans
  • 8,951
  • 5
  • 30
  • 47
JoshL
  • 10,737
  • 11
  • 55
  • 61
  • 7
    VERY bad. You never do this, it will cause issues later. Read this: http://stackoverflow.com/a/8701748/355264 – FrostyFire Mar 25 '15 at 19:04
  • 3
    Passersby, **do not do this**. It is better to copy-construct the `Image` or `Bitmap` after opening it, then `.Dispose()` the one used to open from a file. That will release the file lock. Note that a `.Clone()` copy will keep the file locked, even after the original is `.Disposed()`. Copy-constructed copies will release the file lock. [See here.](http://stackoverflow.com/a/13935966/3367144) – kdbanman Aug 19 '15 at 18:38
  • 1
    If you do it this way, you will get GDI+ errors and also "OutOfMemory" errors if you try to .Clone() the image. – Moon Jan 22 '16 at 17:29
  • I like this approach because there is a third parameter to FileStream in .NET 4.6.2/4.7 and .NET Core which allows releasing the lock while reading to allow multiple users to Read the Same File Concurrently. However, I use ImageMagick for conversions. – justdan23 Feb 01 '19 at 02:37
12

You can also use a stream to read the image then close the stream.

FileStream stream = new FileStream("test.png", FileMode.Open, FileAccess.Read);
pictureBox1.Image = Image.FromStream(stream);
stream.Close();
lahsrah
  • 9,013
  • 5
  • 37
  • 67
2

The easiest ever way I found is to freeze the object that contains the Source (path to the file). All controls that can contain an image, seem to have a .Source which, if not null, it will lock the file it points to.

Now the trick is to change the Image control to a "read-only" state, which then unlocks the file.

My solution:

    private Image CreatePreviewImage()
    {
        Image ReportImage = new Image();
        Uri path = new Uri(@"C:\Folder\Image1.png");
        if (File.Exists(path.OriginalString))
        {
            ReportImage.Name = "Report1";
            ReportImage.Source = LoadImageFromFile(path);
        }
        return ReportImage;
    }

    public ImageSource LoadImageFromFile(Uri path)
    {
        BitmapImage bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.UriSource = path;
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
        bitmap.DecodePixelWidth = 900;
        bitmap.EndInit();
        bitmap.Freeze(); //This is the magic line that releases/unlocks the file.
        return bitmap;
    }
Rafael Ventura
  • 284
  • 3
  • 13
  • 1
    NOTE: `BitmapImage` is a WPF class; the original question is about WinForms `Bitmap`. Nice to see that, if one is using WPF, `BitmapImage` provides a solution to this long-standing annoyance. – ToolmakerSteve Oct 07 '16 at 23:22
-1

talking open, read and release

    StreamReader streamReader = new StreamReader("picture.png");
    Bitmap tmpBitmap = (Bitmap)Bitmap.FromStream(streamReader.BaseStream);
    streamReader.Close();
    pictureBox1.Image = tmpBitmap;`
    
psycobot
  • 39
  • 2