The dispose of an OpenFileDialog in C#? - c#

I have searched throughout entire Stack Overflow, but I couldn't find an answer to the following:
When I'm using my OpenFileDialog, the files I open get blocked for use out of my program until I close my program. So if I open an image, I am not allowed to replace that image in my Windows Explorer anymore.
I think this is a problem with disposing my OpenFileDialog, but I'm not sure how to solve it...
My code:
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Title = "Open Image";
ofd.Filter = "PNG Image(*.png|*.png" +
"|GIF Image(*.gif|*.gif" +
"|Bitmap Image(*.bmp|*.bmp" +
"|JPEG Compressed Image (*.jpg|*.jpg";
if (ofd.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(ofd.FileName);
}
}
I thought that the using block would solve this problem, but nope... It still gets used by the program. I want to load the image in the picturebox and then I want the image to be available again (so I can rename it, replace it, etc...).

This is not related to the OpenFileDialog. It couldn't possibly be, because the dialog doesn't actually open the file. It just allows the user to select a file to open, and then returns that path to you so that you can write code that opens the file. Besides, you're correctly disposing of the OpenFileDialog through your use of the using statement.
The problem here comes from your actually opening the file—ofd.FileName—as a Bitmap. When you use the Bitmap constructor overload that accepts a path string, the file on disk that contains the image remains locked until the Bitmap object is disposed. So says the documentation:
The file remains locked until the Bitmap is disposed.
Because you're assigning the bitmap to pictureBox1.Image, the Bitmap object will not be disposed until pictureBox1 is disposed. And therefore your image file on disk will remain locked.
If you want to unlock the file, you will either need to make a copy of the bitmap and dispose the original, or clear out the PictureBox and dispose its previous image when you are finished with it.
As I understand your question, it sounds like you want to be able to make changes to the image file on disk while continuing to display the image in the picture box. If that's the case, you will need to make a copy. Do that using the constructor overload that takes an Image, like this:
if (ofd.ShowDialog() == DialogResult.OK)
{
// Load the image the user selected
using (Image img = Image.FromFile(ofd.FileName))
{
// Create a copy of it
Bitmap bmpCopy = new Bitmap(img);
// Clear out the bitmap currently in the picture box,
// if there is one.
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
// Assign the copy of the bitmap to the picture box.
pictureBox1.Image = bmpCopy;
}
}

As written by Chris, try something like:
pictureBox1.Image = Image.FromStream(new MemoryStream(File.ReadAllBytes(old.FileName)));
It reads all the file with File.ReadAllBytes, put it in a MemoryStream and pass the MemoryStream to the Image static initializer.
Equivalent to:
byte[] bytes = File.ReadAllBytes(old.FileName);
MemoryStream ms = new MemoryStream(bytes);
pictureBox1.Image = Image.FromStream(ms);
You mustn't dispose the MemoryStream! If/when the Image will be disposed, the finalizer of MemoryStream will kick in (if you don't have other references to ms) and the MemoryStream will be disposed (note that this isn't something that will happen immediately... It's something that will happen when the GC will run)

The technique I've found to be best is to read the file into a byte array with File.ReadAllBytes() (that opens and closes the file), and then use ImageConverter to convert the byte array into an Image. See here for example: https://stackoverflow.com/a/16576471/253938
Edit:
Quote from that previous post of mine: "Some of the other techniques I've tried have been non-optimal because they changed the bit depth of the pixels (24-bit vs. 32-bit) or ignored the image's resolution (dpi)."

Related

How can i deleted a file that is using by IronOCR process in winform?

Sorry for my bad English.
I would like to extract text from a image then delete it. Can you show me how to stop Ocr process after i extracted text from file to delete it?
this is my code
Image image = Image.FromFile(#"C:\Users\Admin\Desktop\testtool.png");
var ocr = new AutoOcr();
result_text.Text = ocr.Read(image).ToString();
string textforClipboard = result_text.Text.Replace("\n", Environment.NewLine);
Clipboard.Clear();
Clipboard.SetText(textforClipboard);
//File.Delete(#"C:\Users\Admin\Desktop\testtool.png");
This is the error:
System.IO.IOException: 'The process cannot access the file 'C:\Users\Admin\Desktop\testtool.png' because it is being used by another process.'
An image is Disposable. Before you delete files that contains Images, you should Dispose all Images that are extract from the file.
Make it good practice: always consider using when you are dealing with an IDisposable. This way, you can be certain that whatever happens: the object is disposed when you don't need it anymore, even after exceptions.
using (Image image = Image.FromFile(#"C:\Users\Admin\Desktop\testtool.png"))
{
// do with the image what you need to do
// Is AutoOcr also IDisposable?
using (var autoOcr = new AutoOcr())
{
...
}
// object autoOcr is disposed
}
// object image is disposed. You can delete the file that contains this image
System.IO.File.Delete(...);

Overwrite Existing Image

I have this code
private void saveImage()
{
Bitmap bmp1 = new Bitmap(pictureBox.Image);
bmp1.Save("c:\\t.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
// Dispose of the image files.
bmp1.Dispose();
}
i already have an image t.jpg at my drive "c:\".
i wanted to replace it with a new image every time my program runs. but a GDI+ error shows up
how could i fix it?
You must remove your image if that is already exists.
private void saveImage()
{
Bitmap bmp1 = new Bitmap(pictureBox.Image);
if(System.IO.File.Exists("c:\\t.jpg"))
System.IO.File.Delete("c:\\t.jpg");
bmp1.Save("c:\\t.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
// Dispose of the image files.
bmp1.Dispose();
}
I presume you earlier loaded the c:\t.jpg image using the Image.Load method. If so, the Image object is holding an open file handle on the image file, which means that the file can't be overwritten.
Instead of using Image.Load to get the original image, load it from a FileStream that you create and dispose of.
So, instead of
Image image = Image.Load(#"c:\\t.jpg");
do this:
using(FileStream fs = new FileStream(#"c:\\t.jpg", FileMode.Open))
{
pictureBox.Image = Image.FromStream(fs);
fs.Close();
}
The file handle has been released so overwriting the file with Bitmap.Save can succeed. The code you gave in your question should therefore work. There is no need to delete the original file or dispose of the image before saving.
Additional:
If you close the FileStream as above,then calls to Image.Save will throw an exception. See here: A Generic error occurred in GDI+ in Bitmap.Save method

Save Icon File To Hard Drive

I know that this must be incredibly easy - It's unbelievable how long I have searched for an answer to this question based on how simple it is in VB6. I simply want to extract an Icon from an EXE File using Icon.ExtractAssociatedIcon, and then save this icon file to my hard drive.
So, here is what I have, and I will also show you what I have tried so you don't think I'm being lazy.
OpenFileDialog ofd = new OpenFileDialog();
ofd.ShowDialog();
string s = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\IconData.ico";
Icon ico = Icon.ExtractAssociatedIcon(ofd.FileName);
Bitmap bmp = ico.ToBitmap();
bmp.Save(s, System.Drawing.Imaging.ImageFormat.Icon);
The above code just makes a file called "IconData.ico" on my desktop which is 0 bytes in length. Again, I am sure this must be incredibly easy to do, but for the life of my I can't figure it out.
Thank you!
You will get better results if you save the icon without first converting to a bitmap. This is because an "Icon" can contain multiple sizes whereas a bitmap is a single size chosen during the conversion.
The Icon class does not have a save to file method, but it does have a save to FileStream method, so you can save it like this:
string s = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + #"\IconData.ico";
using (FileStream fs = new FileStream(s, FileMode.Create))
ico.Save(fs);

Load a bitmap to a PictureBox control

This is not working for some reason. I'm not sure why:
objBitmap = new Bitmap(Resource1.im);
Stream stream;
objBitmap.Save(stream, ImageFormat.Bmp);
this.pictureBox2.Image = Image.FromStream(stream);
objBitmap.Dispose();
Basically, I need to show an image in a PictureBox control and I am not sure how to do that.
pictureBox2.Image = objBitmap;
Well, it ought to go kaboom on the Save() method, the stream was never initialized. Not sure what the point of doing this was. There might be one but it isn't visible from your code. The normal version is:
if (this.pictureBox2.Image != null) this.pictureBox2.Dispose();
this.pictureBox2.Image = Properties.Resources.im;
With some question marks about what Resource1 might be. You get my version going by using Project + Properties, Resource tab and click the arrow on the Add Resource button, Add Existing File.
You can change that to
pictureBox2.Image = Resource1.im;
To answer your question, you need to put a stream (probably a MemoryStream) in the stream variable.
You'll also need to "rewind" the stream before reading it back into a Bitmap. (stream.Position = 0)

Loading an image from a stream without keeping the stream open

Is it possible to use the FromStream method of System.Drawing.Image without having to keep the stream open for the lifetime of the image?
I have an application which loads a bunch of toolbar graphics from resource files, using a combination of Image.FromStream and Assembly.GetManifestResourceStream.
The problem I'm having is while this works fine on Windows 7, on Windows XP the application crashes if a user interface element linked to one of these images is disabled. On Windows 7, the image is rendered in grayscale. On XP, it crashes with an out of memory exception.
After a load of hairpulling I have finally traced it to the initial loading of the image. As a matter of course, if I create any object implementing IDisposable that is also destroyed in the same method, I wrap it in a using statement, for example
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
image = Image.FromStream(resourceStream);
}
If I remove the using statement so that the stream isn't disposed, then the application no longer crashes on XP. But I now have a bunch of "orphan" streams hanging about - the images are stored in command classes and these correctly dispose of the images when they themselves are disposed, but the original stream isn't.
I checked the documentation for FromStream and it confirms the stream needs to remain open. Why this hasn't crashed and burned on the Windows 7 development system is a mystery however!
I really don't want this stream hanging around, and I certainly don't want to have to store a reference to this stream as well as the image so I can dispose of it later. I only have need of that stream once so I want to get rid of it :)
Is it possible to create the image and then kill of the stream there and then?
The reason the stream needs to be open is the following:
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.
The documented workaround is to create either a non-indexed image using Graphics.DrawImage or to create an indexed Bitmap from the original image as described here:
Bitmap and Image constructor dependencies
According to the documentation of Image.FromStream, the stream must be kept open while the image is in use. Therefore, even if closing worked (and there's nothing to say you can't close a stream before it's disposed, as far as the stream object itself goes) it may not be a very reliable approach.
You could copy the image to another image object, and use that. However, this is likely to be more memory intensive than just keeping the stream open.
You could save the stream to a temporary file and use the Image.FromFile method. Or simply don't embed the image, keep it as a file and load it from this file at runtime.
I'am sure this will help someone :)
I used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}

Categories