Open Image from File, Then Release Lock

Open Image from file, then release lock?

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);
}

how to prevent the Image.FromFile() method to lock the file

When you use the Image.FromFile(strFileName) method to create the Image, the method locks the file until you release the Image. The exact reason is explained below. And it's why you can't access more than one time to the same image file with this method.

You could instead:

  • use the Image.FromStream(stream) method.
  • that you use with a New FileStream or a MemoryStream that you create from the image file.

Here are possible implementation of a custom SafeImageFromFile method that doesn't lock the image file:

Public Shared Function SafeImageFromFile(path As String) As Image
Using fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Dim img = Image.FromStream(fs)
Return img
End using
End Function

Or

Public Shared Function SafeImageFromFile(path As String) As Image
Dim bytes = File.ReadAllBytes(path)
Using ms As New MemoryStream(bytes)
Dim img = Image.FromStream(ms)
Return img
End Using
End Function

Usage

If strFileName.ToLower.EndsWith(".jpg") Then
Dim inImg As Image = SafeImageFromFile(strFileName)
Dim index as integer = DataGridView4.Rows.Add()
DataGridView4.Rows(index).Cells(0).Value = inImg
End If

Important note

Here I create the FileStream or a MemoryStream using a Using statement to make sure the stream is released. It works fine on my system and it seems it work for you too, though MSDN says about Image.FromStream(stream) method:

You must keep the stream open for the lifetime of the Image.

The reason of this sentence is explain here: KB814675 Bitmap and Image constructor dependencies

GDI+, and therefore the System.Drawing namespace, may defer the
decoding of raw image bits until the bits are required by the image.

Additionally, even after the image has been decoded, GDI+ may
determine that it is more efficient to discard the memory for a large
Bitmap and to re-decode later.
Therefore, GDI+ must have access to the
source bits for the image for the life of the Bitmap or the Image
object.

To retain access to the source bits, GDI+ locks any source file, and
forces the application to maintain the life of any source stream, for
the life of the Bitmap or the Image object.

So know the code above could generate GDIexceptions because of releasing the stream using Using. It could happen when you save the image from the file or during the image creation. From this thread Loading an image from a stream without keeping the stream open and Hans Passant's comment they fixed several problems with indexed pixel formats in the Vista version of gdiplus.dll., it would happen only on XP.

To avoid this you need to keep the stream open. The methods would be:

Public Shared Function SafeImageFromFile(path As String) As Image
Dim fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Dim img = Image.FromStream(fs)
Return img
End Function

Or

Public Shared Function SafeImageFromFile(path As String) As Image
Dim bytes = File.ReadAllBytes(path)
Dim ms = New MemoryStream(bytes)
Dim img = Image.FromStream(ms)
Return img
End Function

But those last methods have some disadvantage like not releasing the stream (memory issue) and they violate rule CA2000 Dispose objects before losing scope .

The KB article gives some workarounds:

Create a Non-Indexed Image

This approach requires that the new image be in a non-indexed pixel
format (more than 8 bits-per-pixel), even if the original image was in
an indexed format. This workaround uses the Graphics.DrawImage()
method to copy the image to a new Bitmap object:

  1. Construct the original Bitmap from the stream, from the memory, or from the file.
  2. Create a new Bitmap of the same size, with a pixel format of more than 8 bits-per-pixel (BPP).
  3. Use the Graphics.FromImage() method to obtain a Graphics object for the second Bitmap.
  4. Use Graphics.DrawImage() to draw the first Bitmap onto the second Bitmap.
  5. Use Graphics.Dispose() to dispose of the Graphics.
  6. Use Bitmap.Dispose() to dispose of the first Bitmap.

Create an Indexed Image

This workaround creates a Bitmap object in an indexed format:

  1. Construct the original Bitmap from the stream, from the memory, or from the file.
  2. Create a new Bitmap with the same size and pixel format as the first Bitmap.
  3. Use the Bitmap.LockBits() method to lock the whole image for both Bitmap objects in their native pixel format.
  4. Use either the Marshal.Copy function or another memory copying function to copy the image bits from the first Bitmap to the second Bitmap.
  5. Use the Bitmap.UnlockBits() method to unlock both Bitmap objects.
    Use Bitmap.Dispose() to dispose of the first Bitmap.

Here is an implementation of Non-Indexed Image creation, based on KB article and this answer https://stackoverflow.com/a/7972963/2387010 Your best bet is creating a pixel-perfect replica of the image -- though YMMV (with certain types of images there may be more than one frame, or you may have to copy palette data as well.) But for most images, this works:

Private Shared Function SafeImageFromFile(path As String) As Bitmap
Dim img As Bitmap = Nothing
Using fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Using b As New Bitmap(fs)
img = New Bitmap(b.Width, b.Height, b.PixelFormat)
Using g As Graphics = Graphics.FromImage(img)
g.DrawImage(b, Point.Empty)
g.Flush()
End Using
End Using
End Using
Return img
End Function

Someone indicated that what is important is that the FileStream is opened in read mode (FileAccess.Read).

True, but it makes more sens if you don't use Using statement and so you don't release the stream, or in multi threads context: FileAccess.Write is inappropriate, and FileAccess.ReadWrite is not required, but open the stream with FileAccess.Read mode won't prevent to have an IO.Exception if another program (or yours in multi threads context) has opened the file with another mode than FileAccess.Read.


If you want to be able to display the image and at the same time be able to save data to the file, Since you don't lock the file with those methods, you should be able to save the image (delete/overwrite the previous file) using the Image.Save method.

lock image file in PictureBox

Image.FromFile will keep the File open which prevents access to the image file till the Image is disposed. If you want to release the lock, you need to keep the Image file in memory.

myPictureBox.Image = Image.FromStream(new MemoryStream(File.ReadAllBytes(strImageFile)));

File lock on created image?

From the documentation

The file name and path can be relative to the application or an
absolute path. Use this constructor to open images with the following
file formats: BMP, GIF, EXIF, JPG, PNG and TIFF. For more information
about supported formats, see Types of Bitmaps. The file remains locked
until the Bitmap is disposed.

Not sure why that is but I suppose the Bitmap class can lazy-load parts of the file. For that feature, it needs access after the constructor has run.

You can use the Stream-taking overload of the constructor, and close the stream at a time of your choice.

Disposing dynamically created picturebox to release file lock?

The problem is Because of loading image using Image.FromFile(file).

When you load image using Image.FromFile(file) the file will be locked.

To avoid locking file you can load your images using Image.FromStream.

Code:

Dim filePath = "path to your image file"
Dim contentBytes = File.ReadAllBytes(filePath)
Dim memoryStream As New MemoryStream(contentBytes)
Dim image= Image.FromStream(memoryStream)
YourPictureBox.Image = image

Free file locked by new Bitmap(filePath)

Using a filestream will unlock the file once it has been read from and disposed:

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 the original bitmap to be disposed, and allow the FileStream to be closed.

THIS ANSWER IS NOT SAFE - See comments, and see discussion in net_prog's answer. The Edit to use Clone does not make it any safer - Clone clones all fields, including the filestream reference, which in certain circumstances will cause a problem.

Releasing File Locks

As hinted by Chris Dunaway, the answer was to close() the TextFieldParser and Dispose of the respective Image before trying to move the file.

View Image file without locking it. (Copy to memory?)

myBitmap.CacheOption = BitmapCacheOption.OnLoad is the line you're looking for. It "caches the entire image into memory at load time. All requests for image data are filled from the memory store." From MSDN

Something like this:

BitmapImage bmi = new BitmapImage();
bmi.BeginInit();
bmi.UriSource = new Uri(myFilePath);
bmi.CacheOption = BitmapCacheOption.OnLoad;
bmi.EndInit();
Image1.Source = bmi;


Related Topics



Leave a reply



Submit