I'm trying create a user perfil edit window, in this window has a Image control
When I selected a image file, it will show in this Image control and copy this file at my image folder, first time is all right, but second time, it show a error
"The process cannot access the file 'C:\1.jpg' because it is being used by another process."
I think it is because my Image control is using this file, so, I don't know what can I do
private void Select_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog od = new OpenFileDialog();
if (od.ShowDialog() == true)
{
string imageLocal = #"C:/1.jpg";
File.Copy(od.FileName, imageLocal, true);
image1.Source = new BitmapImage(new Uri(imageLocal));
}
}
If you want to load and display an image, and keep the file amenable to operations in the file system (like reloading it or moving it to another directory), the Uri constructor will not work because (as you point out), the BitmapImage class hangs on to the file handle.
Instead, use a method like this...
private static BitmapImage ByStream(FileInfo info)
{ //http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dee7cb68-aca3-402b-b159-2de933f933f1
try
{
if (info.Exists)
{
// do this so that the image file can be moved in the file system
BitmapImage result = new BitmapImage();
// Create new BitmapImage
Stream stream = new MemoryStream(); // Create new MemoryStream
Bitmap bitmap = new Bitmap(info.FullName);
// Create new Bitmap (System.Drawing.Bitmap) from the existing image file
(albumArtSource set to its path name)
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
// Save the loaded Bitmap into the MemoryStream - Png format was the only one I
tried that didn't cause an error (tried Jpg, Bmp, MemoryBmp)
bitmap.Dispose(); // Dispose bitmap so it releases the source image file
result.BeginInit(); // Begin the BitmapImage's initialisation
result.StreamSource = stream;
// Set the BitmapImage's StreamSource to the MemoryStream containing the image
result.EndInit(); // End the BitmapImage's initialisation
return result; // Finally, set the WPF Image component's source to the
BitmapImage
}
return null;
}
catch
{
return null;
}
}
This method takes a FileInfo and returns a BitmapImage which you can display and simultaneously move it to another directory or display it again.
A much simpler method, copied from another answer below, is this:
public static BitmapImage LoadBitmapImage(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
The method shown below loads a BitmapImage from file and immediately closes the file after loading. Note that it is necessary to set the BitmapCacheOption.OnLoad flag when the source stream is closed right after EndInit.
public static BitmapImage LoadBitmapImage(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze(); // just in case you want to load the image in another thread
return bitmapImage;
}
}
This code will work for any image format that is supported by WPF. When passing the image file content as stream to the StreamSource property, WPF will automatically create the appropriate decoder.
Very simple solution:
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
File.Copy(od.FileName, imageLocal, true);
Related
Using .net Framework 4.8 I have a method to resize images to thumbnails. It seems to work OK as I can see the file properties after it’s resized and all looks good. However, when I execute the save method which should save the new thumbnail to a new folder, no files are found in the new folder. All paths are correct. And I can confirm that the source files have not been altered (as expected). Lastly I’m getting no errors. Any ideas what is going wrong?
This image’s original width is 600 and looking at the screenshot you can see the new width is 212, so this confirms we have a valid bitmap to save.
Thanks.
Like I have a bitmap like bmp Then Now I want to save it Like this way ....
BitmapImage bitmapimage;
using (MemoryStream memory = new MemoryStream())
{
bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);
memory.Position = 0;
bitmapimage = new BitmapImage();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
}
imgQR1.Source = bitmapimage;
string filePath = #"C:\Demo_Project\Image\test.png";
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapimage));
using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
{
encoder.Save(fileStream);
}
The error is that the memory stream is not accessible when it is closed. It occurs when I try to set the previous image of the image control back to a Gif. When the previous image was a gif, I convert it to a bitmap with a memory stream. When the previous image was a normal png or jpg, it can display successfully.
I have tried to research how to fix the error. A solution I've tried is to convert the images to byte[] but then the gif isn't animating like they have been converted to a static image.
To display the gif I use a NuGet package called WPFAnimatedGif and to make the Wpf look better I use the NuGet package Materialdesigntheme
This is the event code that fires upon drag leave
if (previousIcon != null)
{
ToggleButton buttonControl = (ToggleButton)sender;
Image imageControl = (Image)((Grid)buttonControl.Content).Children[1];
if (previousIcon.ContainsKey(buttonControl))
ImageBehavior.SetAnimatedSource(imageControl, previousIcon[buttonControl]);
}
How I convert it
BitmapImage bmImage = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
bmImage.BeginInit();
bmImage.CacheOption = BitmapCacheOption.OnLoad;
bmImage.StreamSource = stream;
bmImage.EndInit();
bmImage.Freeze();
}
For full code visit these Pastebins:
https://pastebin.com/PQkFAhQj
https://pastebin.com/wCEBeN1X
https://pastebin.com/wAERvDW3
Edit
Updated conversion function based upon responses
public BitmapImage ConvertWriteableBitmapToBitmapImage(WriteableBitmap wbm)
{
BitmapImage bmImage = new BitmapImage();
MemoryStream stream = new MemoryStream();
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
//stream.Position = 0;
bmImage.BeginInit();
bmImage.CacheOption = BitmapCacheOption.OnLoad;
bmImage.StreamSource = stream;
bmImage.EndInit();
bmImage.Freeze();
return bmImage;
}
I'm trying create a user perfil edit window, in this window has a Image control
When I selected a image file, it will show in this Image control and copy this file at my image folder, first time is all right, but second time, it show a error
"The process cannot access the file 'C:\1.jpg' because it is being used by another process."
I think it is because my Image control is using this file, so, I don't know what can I do
private void Select_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog od = new OpenFileDialog();
if (od.ShowDialog() == true)
{
string imageLocal = #"C:/1.jpg";
File.Copy(od.FileName, imageLocal, true);
image1.Source = new BitmapImage(new Uri(imageLocal));
}
}
If you want to load and display an image, and keep the file amenable to operations in the file system (like reloading it or moving it to another directory), the Uri constructor will not work because (as you point out), the BitmapImage class hangs on to the file handle.
Instead, use a method like this...
private static BitmapImage ByStream(FileInfo info)
{ //http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dee7cb68-aca3-402b-b159-2de933f933f1
try
{
if (info.Exists)
{
// do this so that the image file can be moved in the file system
BitmapImage result = new BitmapImage();
// Create new BitmapImage
Stream stream = new MemoryStream(); // Create new MemoryStream
Bitmap bitmap = new Bitmap(info.FullName);
// Create new Bitmap (System.Drawing.Bitmap) from the existing image file
(albumArtSource set to its path name)
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
// Save the loaded Bitmap into the MemoryStream - Png format was the only one I
tried that didn't cause an error (tried Jpg, Bmp, MemoryBmp)
bitmap.Dispose(); // Dispose bitmap so it releases the source image file
result.BeginInit(); // Begin the BitmapImage's initialisation
result.StreamSource = stream;
// Set the BitmapImage's StreamSource to the MemoryStream containing the image
result.EndInit(); // End the BitmapImage's initialisation
return result; // Finally, set the WPF Image component's source to the
BitmapImage
}
return null;
}
catch
{
return null;
}
}
This method takes a FileInfo and returns a BitmapImage which you can display and simultaneously move it to another directory or display it again.
A much simpler method, copied from another answer below, is this:
public static BitmapImage LoadBitmapImage(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
The method shown below loads a BitmapImage from file and immediately closes the file after loading. Note that it is necessary to set the BitmapCacheOption.OnLoad flag when the source stream is closed right after EndInit.
public static BitmapImage LoadBitmapImage(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze(); // just in case you want to load the image in another thread
return bitmapImage;
}
}
This code will work for any image format that is supported by WPF. When passing the image file content as stream to the StreamSource property, WPF will automatically create the appropriate decoder.
Very simple solution:
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
File.Copy(od.FileName, imageLocal, true);
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.
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);
}
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);
}
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();
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;
}
talking open, read and release
StreamReader streamReader = new StreamReader("picture.png");
Bitmap tmpBitmap = (Bitmap)Bitmap.FromStream(streamReader.BaseStream);
streamReader.Close();
pictureBox1.Image = tmpBitmap;`
I have an image control with a source image located in my c drive. I get a message that the image is being used by another process whenever I try to delete the original image to change it with another one dynamically. How do I release the image from the image control to be able to delete it.
I tried this variants:
string path = ((BitmapImage)img.Source).UriSource.LocalPath;
img.SetValue(System.Windows.Controls.Image.SourceProperty, null);
File.Delete(path);
And:
string path = ((BitmapImage)img.Source).UriSource.LocalPath;
img.Source = null;
File.Delete(path)
But it's not work...
Try setting the bitmap image through the stream source property. That way the app won't put a lock on the file since you loaded it through a stream.
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.streamsource(VS.85).aspx
//this function allows you to load an image from a file and release it
BitmapImage loadPhoto(string path)
{
BitmapImage bmi = new BitmapImage();
bmi.BeginInit();
bmi.CacheOption = BitmapCacheOption.OnLoad;
bmi.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bmi.UriSource = new Uri(path);
bmi.EndInit();
return bmi;
}