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 aMemoryStream
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:
- Construct the original Bitmap from the stream, from the memory, or from the file.
- Create a new Bitmap of the same size, with a pixel format of more than 8 bits-per-pixel (BPP).
- Use the Graphics.FromImage() method to obtain a Graphics object for the second Bitmap.
- Use Graphics.DrawImage() to draw the first Bitmap onto the second Bitmap.
- Use Graphics.Dispose() to dispose of the Graphics.
- Use Bitmap.Dispose() to dispose of the first Bitmap.
Create an Indexed Image
This workaround creates a Bitmap object in an indexed format:
- Construct the original Bitmap from the stream, from the memory, or from the file.
- Create a new Bitmap with the same size and pixel format as the first Bitmap.
- Use the Bitmap.LockBits() method to lock the whole image for both Bitmap objects in their native pixel format.
- Use either the Marshal.Copy function or another memory copying function to copy the image bits from the first Bitmap to the second Bitmap.
- 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
How to Update the Entityset - Because It Has a Definingquery and No <Updatefunction> Element Exist
Css, Images, Js Not Loading in Iis
Bulk-Deleting in Linq to Entities
How to Decode a Base64 Encoded String
Does Xaml Have a Conditional Compiler Directive for Debug Mode
How to Get the Propertyinfo of a Specific Property
Concat All Strings Inside a List<String> Using Linq
How to Get This ASP.NET MVC Selectlist to Work
Convert Any Object to a Byte[]
What Is the Minimum Client Footprint Required to Connect C# to an Oracle Database
Multiple Actions Were Found That Match the Request in Web API
How to Get a List of Properties with a Given Attribute
Windows Application Startup Error Exception Code: 0Xe0434352