Free file blocked by new Bitmap (filePath)

I have a PictureBox image pointing to a specific file "A", at runtime I want to change the PictureBox image to another "B", but I get the following error:

"The first exception of type" System.IO.IOException "occurred in mscorlib.dll Additional information: The process cannot access file" A "because it is being used by another process."

I set the image as follows:

pbAvatar.Image = new Bitmap(filePath); 

How can I unlock the first file?

Thanks in advance!

+29
c # file image picturebox
Jan 26 '11 at 11:17
source share
9 answers

Using filestream unlocks the file after reading and deleting it:

 using (var fs = new System.IO.FileStream("c:\\path to file.bmp", System.IO.FileMode.Open)) { var bmp = new Bitmap(fs); pct.Image = (Bitmap) bmp.Clone(); } 

Edit: Updated to allow placement of the original bitmap and allow closing of FileStream.

THIS ANSWER IS NOT SECURE - see comments and see discussion in net_prog's answer . Editing to use Clone does not make it safer - Clone clones all fields, including a link to a stream, which in certain circumstances can cause a problem.

+26
Jan 26 2018-11-11T00:
source share

Here is my approach to opening an image without locking the file ...

 public static Image FromFile(string path) { var bytes = File.ReadAllBytes(path); var ms = new MemoryStream(bytes); var img = Image.FromStream(ms); return img; } 

UPDATE: I did some perfection tests to find out which method was the fastest. I compared it with @net_progs 'copy from bitmap' answer (which seems to be the closest fit, although it has some problems). I downloaded the image 10,000 times for each method and calculated the average time per image. Here are the results:

 Loading from bytes: ~0.26 ms per image. Copying from bitmap: ~0.50 ms per image. 

The results seem to make sense since you need to double-create the image using a copy from the bitmap method.

+40
Feb 12 '13 at 16:37
source share

This is a common blocking issue widely discussed on the Internet.

The suggested thread trick does not work , in fact it works initially, but causes problems later. For example, it will load the image and the file will remain unlocked, but if you try to save the downloaded image using the Save () method, it will throw a general GDI + exception.

Further, the replicated per pixel path does not seem solid, at least it's noisy.

What I found is described here: http://www.eggheadcafe.com/microsoft/Csharp/35017279/imagefromfile--locks-file.aspx

So the image should load:

 Image img; using (var bmpTemp = new Bitmap("image_file_path")) { img = new Bitmap(bmpTemp); } 

I was looking for a solution to this problem, and this method has worked fine for me so far, so I decided to describe it since I found that many people advise using the wrong stream here and over the Internet.

+34
Jan 02 2018-12-12T00:
source share

You cannot delete / close the stream while the raster object is still using it. (Is it possible that the raster image object will have access to it again, will be determinate only if you know what type of file you are working with and what operations you will perform. For example, for .gif images, the stream closed before the constructor returns.)

The clone creates an β€œexact copy” of the bitmap (according to the documentation, ILSpy shows that it calls its own methods, so it is too much to track right now), it also copies the Stream data, and also will not, t is an exact copy.

It’s best to create a perfect copy of the image - although YMMV (with certain types of images there may be more than one frame, or you may have to copy the data from the palette). But for most images, this works:

 static Bitmap LoadImage(Stream stream) { Bitmap retval = null; using (Bitmap b = new Bitmap(stream)) { retval = new Bitmap(b.Width, b.Height, b.PixelFormat); using (Graphics g = Graphics.FromImage(retval)) { g.DrawImage(b, Point.Empty); g.Flush(); } } return retval; } 

And then you can call it like this:

 using (Stream s = ...) { Bitmap x = LoadImage(s); } 
+6
Nov 01 '11 at
source share

Here is the technique that I am currently using, and seems to work best. The advantage is that a Bitmap object is created as the source file with the same pixel (24-bit or 32-bit) resolution and resolution (72 dpi, 96 dpi, etc.).

  // ImageConverter object used to convert JPEG byte arrays into Image objects. This is static // and only gets instantiated once. private static readonly ImageConverter _imageConverter = new ImageConverter(); 

This can be used as often as needed, as follows:

  Bitmap newBitmap = (Bitmap)_imageConverter.ConvertFrom(File.ReadAllBytes(fileName)); 

Edit: Here's an update to the technique described above: https://stackoverflow.com/a/212969/

+4
Apr 18 '13 at 14:30
source share

( The accepted answer is incorrect. When you try to execute LockBits(...) on a cloned bitmap, you will encounter GDI + errors.)




I see only 3 ways to get rid of this:
  • copy the file to a temporary file and open that easy way new Bitmap(temp_filename)
  • open the file, read the image, create a copy of the pixel-pixel size (not Clone() ) and delete the first bitmap
  • (accept the locked file function)
+3
Jan 10 '14 at
source share

Read it in the stream, create a bitmap, close the stream.

0
Jan 26 '11 at 11:21
source share

Three years ago, I wrote an image viewer to see if I could do this. Last week I added code to scan images. (I plan to add this to the genealogy program after I get the errors.) To crop an unused area, I have a call to the MSPaint program with the file name. I edit it there, then save. When I close Paint, the image shows the changes.
I was getting an error in Paint about a locked file if I did something with the image. I change the program to block the image using Image, FromStream (). I no longer receive this message in Paint. (My program is in VB 2010.)

0
Dec 20 '13 at 18:27
source share

As far as I know, this is 100% safe, since the resulting image is 100% created in memory without any associated resources and without open threads remaining in memory. It acts like any other Bitmap created from a constructor that does not specify any input sources, and unlike some other answers, it saves the original pixel format here, that is, it can be used in indexed formats.

Based on this answer , but with additional corrections and without importing an external library.

 /// <summary> /// Clones an image object to free it from any backing resources. /// Code taken from /questions/340802/filedelete-failing-when-imagefromfile-was-called-prior-it-despite-making-copy-of-loaded-image-and-destroying-original-one/1616671#1616671 with some extra fixes. /// </summary> /// <param name="sourceImage">The image to clone</param> /// <returns>The cloned image</returns> public static Bitmap CloneImage(Bitmap sourceImage) { Rectangle rect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); Bitmap targetImage = new Bitmap(rect.Width, rect.Height, sourceImage.PixelFormat); targetImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); BitmapData sourceData = sourceImage.LockBits(rect, ImageLockMode.ReadOnly, sourceImage.PixelFormat); BitmapData targetData = targetImage.LockBits(rect, ImageLockMode.WriteOnly, targetImage.PixelFormat); Int32 actualDataWidth = ((Image.GetPixelFormatSize(sourceImage.PixelFormat) * rect.Width) + 7) / 8; Int32 h = sourceImage.Height; Int32 origStride = sourceData.Stride; Int32 targetStride = targetData.Stride; Byte[] imageData = new Byte[actualDataWidth]; IntPtr sourcePos = sourceData.Scan0; IntPtr destPos = targetData.Scan0; // Copy line by line, skipping by stride but copying actual data width for (Int32 y = 0; y < h; y++) { Marshal.Copy(sourcePos, imageData, 0, actualDataWidth); Marshal.Copy(imageData, 0, destPos, actualDataWidth); sourcePos = new IntPtr(sourcePos.ToInt64() + origStride); destPos = new IntPtr(destPos.ToInt64() + targetStride); } targetImage.UnlockBits(targetData); sourceImage.UnlockBits(sourceData); // For indexed images, restore the palette. This is not linking to a referenced // object in the original image; the getter of Palette creates a new object when called. if ((sourceImage.PixelFormat & PixelFormat.Indexed) != 0) targetImage.Palette = sourceImage.Palette; // Restore DPI settings targetImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); return targetImage; } 

To call just use:

 /// <summary>Loads an image without locking the underlying file.</summary> /// <param name="path">Path of the image to load</param> /// <returns>The image</returns> public static Bitmap LoadImageSafe(String path) { using (Bitmap sourceImage = new Bitmap(path)) { return CloneImage(sourceImage); } } 
0
Jan 09
source share



All Articles