Can't overwrite a file wrapped in a using statement - c#

I'm building an app that is supposed to do the following :
User selects an element in a listbox (example : frog)
A picture corresponding to the element is opened as the background on a canvas, on which the user can draw
When the user selects another element of the listbox, the canvas is saved as a picture named after the unchecked element, with "New" added (example : frogNew)
This new element is added to the listbox, and if the user edits it again, it is saved under the same name (example : frogNew)
Things are working out, except the part where I try to save a canvas under the same name (frogNew). I get an error saying that I cannot save the file as it is already open. Can you tell me where if don't close the file properly in my code ?
private void save_picture(string name)
{
//This part takes a screenshot of the canvas, named "paintSurface"
RenderTargetBitmap rtb = new RenderTargetBitmap((int)paintSurface.RenderSize.Width, (int)paintSurface.RenderSize.Height, 96d, 96d, System.Windows.Media.PixelFormats.Default);
rtb.Render(paintSurface);
BitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
//If the file already exists, we add "New" to its name
var regex1 = new Regex(#"New$");
if (regex1.Match(nom).ToString() == "")
{
using (var fs = System.IO.File.OpenWrite(#"D:\Test" + name + "New.png"))
{
pngEncoder.Save(fs);
}
}
else
{
using (var fs = System.IO.File.OpenWrite(#"D:\Test" + name + ".png"))
{
pngEncoder.Save(fs);
}
}
}
private void listBox1_SelectedIndexChanged(object sender, SelectionChangedEventArgs e)
{
//When the index of listbox changes, I save the canvas in a file named after the former index
List<string> oldItemNames = new List<string>();
if (e.RemovedItems.Count != 0)
{
var oldPhoto = e.RemovedItems[0].ToString();
save_picture(oldPicture);
}
//I start a new canvas with the picture corresponding to the new index as a background
paintSurface.Children.Clear();
ImageBrush newBrush = new ImageBrush();
newBrush.ImageSource = new BitmapImage(new Uri(#"D:\Test" + listBox1.SelectedItem.ToString() + ".png", UriKind.Relative));
paintSurface.Background = newBrush;
}
Any idea why this line "using (var fs = System.IO.File.OpenWrite(#"D:\Test" + name + ".png"))" always gives me the error that this file is already open ? How can I close it?

This is because your file is locked by the BitmapImage that you're using as the image source
You need to specify the BitmapCacheOption.OnLoad option while initializing the bitmap image:
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.UriSource = new Uri(#"D:\Test" + listBox1.SelectedItem.ToString() + ".png", UriKind.Relative);
bitmapImage.EndInit();
newBrush.ImageSource = bitmapImage;

I don't think it's your save operation keeping the file open. It's the read operation near the end of your code sample. You open FooNew.png, edit it, and try to write to the same file.
Try this. Where you have:
newBrush.ImageSource = new BitmapImage(new Uri(#"D:\Test" + listBox1.SelectedItem.ToString() + ".png", UriKind.Relative));
Replace with:
using (FileStream fileStream = File.OpenRead(#"D:\Test" + listBox1.SelectedItem.ToString() + ".png"))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = fileStream;
bitmapImage.EndInit();
newBrush.ImageSource = bitmapImage;
}
Once you get this working, you're going to realize that File.OpenWrite() isn't what you want in save_picture. It would append the new PNG to any existing file contents. You want File.Create() which creates a new file or overwrites an existing one.

Related

how to rotate image in File in C# & WPF application

I have WPF and C# application. which captures the images and Save in to file(*.jpg).
I have the image path and i want to rotate image saved in File through the c# code.
and Save the Rotated image in same file.
How can i do that?
Use the rotate flip method.
E.g.:
Bitmap bitmap1 = (Bitmap)Bitmap.FromFile(#"C:\test.jpg");
bitmap1.RotateFlip(RotateFlipType.Rotate180FlipNone);
bitmap1.Save(#"C:\Users\Public\Documents\test rotated.jpg");
you can use my method:
BitmapImage rotateImage(string filename,int angle)
{
WIA.ImageFile img = new WIA.ImageFile();
img.LoadFile(filename);
WIA.ImageProcess IP = new WIA.ImageProcess();
Object ix1 = (Object)"RotateFlip";
WIA.FilterInfo fi1 = IP.FilterInfos.get_Item(ref ix1);
IP.Filters.Add(fi1.FilterID, 0);
Object p1 = (Object)"RotationAngle";
Object pv1 = (Object)angle;
IP.Filters[1].Properties.get_Item(ref p1).set_Value(ref pv1);
img = IP.Apply(img);
File.Delete(filename);
img.SaveFile(filename);
BitmapImage imagetemp = new BitmapImage();
using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
imagetemp.BeginInit();
imagetemp.CacheOption = BitmapCacheOption.OnLoad;
imagetemp.StreamSource = stream;
imagetemp.EndInit();
}
return imagetemp;
}
usage:
string filename = System.AppDomain.CurrentDomain.BaseDirectory + "4.jpg";
image.Source = rotateImage(filename,90);

ObjectDisposedException when I try to use an Image source

I need to add an Image to my Panel, so I use the following code:
var image = new Image();
var source = new BitmapImage();
source.BeginInit();
source.CacheOption = BitmapCacheOption.OnLoad;
source.StreamSource = new FileStream(filename, FileMode.Open);
source.EndInit();
// I close the StreamSource so I can load again the same file
source.StreamSource.Close();
image.Source = source;
The problem is that when I try to use my image source I get an ObjectDisposedException:
var source = ((BitmapImage)image.Source).StreamSource;
// When I use source I get the exception
using (var stream = new MemoryStream((int)(source.Length)))
{
source.Position = 0;
source.CopyTo(stream);
// ...
}
It happens because I closed the source, but if I don't close it I can't be able to load again the same file.
How can I solve this problem (i.e. close the source to be able to load the same file more than once, and to be able to use the source without get the exception)?
The following solution should work for you:
var image = new Image();
var source = new BitmapImage();
source.BeginInit();
source.CacheOption = BitmapCacheOption.OnLoad;
// Create a new stream without disposing it!
source.StreamSource = new MemoryStream();
using (var filestream = new FileStream(filename, FileMode.Open))
{
// Copy the file stream and set the position to 0
// or you will get a FileFormatException
filestream.CopyTo(source.StreamSource);
source.StreamSource.Position = 0;
}
source.EndInit();
image.Source = source;

LockScreen for windows phone 8

Hi I am developing a lockscreen app where I am using listbox of images.After selecting a image when i am clicking a button to set lockscreen,It should updated.But it bot updating .Here is my code
private async void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
MediaLibrary mediaLibrary = new MediaLibrary();
//ImageSource im = image1.Source;
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(mediaLibrary.Pictures[imageList.SelectedIndex].GetImage());
String tempJPEG = "MyWallpaper1.jpg";
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(tempJPEG))
{
myIsolatedStorage.DeleteFile(tempJPEG);
}
IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempJPEG);
StreamResourceInfo sri = null;
Uri uri = new Uri(tempJPEG, UriKind.Relative);
sri = Application.GetResourceStream(uri);
WriteableBitmap wb = new WriteableBitmap(bitmap);
Extensions.SaveJpeg(wb, fileStream, wb.PixelWidth, wb.PixelHeight, 0, 90);
fileStream.Close();
}
LockScreenChange(tempJPEG);
}
private async void LockScreenChange(string filePathOfTheImage)
{
if (!LockScreenManager.IsProvidedByCurrentApplication)
{
await LockScreenManager.RequestAccessAsync();
}
if (LockScreenManager.IsProvidedByCurrentApplication)
{
var schema = "ms-appdata:///Local/";
var uri = new Uri(schema + filePathOfTheImage, UriKind.Absolute);
LockScreen.SetImageUri(uri);
var currentImage = LockScreen.GetImageUri();
MessageBox.Show("Success", "LockScreen changed", MessageBoxButton.OK);
}
else
{
MessageBox.Show("Background cant be changed. Please check your permissions to this application.");
}
}
Actually when first time the app is launched and when I am clicking set button,the current selected image is set as lockscreen,after that when i am selecting another image,it is showing lockscreen changed ,success.No error and no exception.I dont know where is the problem.
Please help........
It got solved by changing temporary file name to original file name i.e. string tempJpeg

How to add PNG and JPG at runtime

I am using C# and WPF. I want to add a PNG and JPG at runtıme to an image source but I get an exception that says:
Can not implicitly add convert type string to Sytem.Windows.Media.imageSource
using System.IO; //for : input - output
using Microsoft.Win32; //For : OpenFileDialog / SaveFileDialog
using System.Windows.Media.Imaging; //For : BitmapImage etc etc
<Image x:Name="img" Margin="9,13.5,6,0.5" Source="Laugh.ico">
private void ac(object sender, RoutedEventArgs args)
{
OpenFileDialog dlg = new OpenFileDialog();
// Configure open file dialog box
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".PNG"; // Default file extension
dlg.Filter = " (.PNG)|*.PNG"; // Filter files by extension
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
img.Source=filename;
}
}
Sorry but as you might have noticed, that code wonT even compile. You cannot set the image source as the filename
img.Source = filename
Have a look at the reference.
Try this:
img.Source = new BitmapImage(new Uri(filename));
Not sure if this will work for an image outside of the program, but you can try:
Uri uri = new Uri(dlg.File.FullName, UriKind.RelativeOrAbsolute);
ImageSource imgSource = new BitmapImage(uri);
img.Source = imgSource;
I think the key line is:
img.Source=filename
which should be something like:
BitmapImage bi= new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(filename, UriKind.Relative);
bi.EndInit();
img.Source = bi;
As you have to actually read the image file in from disk.

C# - The process cannot access the file because it is being used by another process

public static void CopyImage(Image picToSave, string name)
{
if (picToSave.Source != null)
{
BitmapImage src = (BitmapImage)picToSave.Source;
if (!Directory.Exists("Images"))
{
Directory.CreateDirectory("Images");
}
FileStream stream = new FileStream("Images/" + name + ".jpg", FileMode.Create);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
encoder.Save(stream);
stream.Close();
}
}
The problem occurs when i choose a file which already exists in the /Images directory, i guess it just cant overwrite, The exception is thrown at the "FileStream"" line (FileMode.Create I guess).
If i Choose a file which isn't in the /Images directory it works fine and copies the file to the Images Directory like it should..
Thank you :)
How did you load the image in the first place? If you didn't change the default value for CacheOption, the file is locked by the BitmapImage object. You need to specify BitmapCacheOption.OnLoad:
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = imageUri;
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();
Assuming you created Bitmaps from all the images in the image folder this sounds like a known problem with the Bitmap class - it keeps a file lock on the file you created it from until you call dispose. Also see this thread: .NET app locks file.
Hans Passant offers the following workaround in this thread: Loading a file to a Bitmap but leaving the original file intact
public static Image LoadImageNoLock(string path) {
using (var ms = new MemoryStream(File.ReadAllBytes(path))) {
return Image.FromStream(ms);
}
}
Just thought I would post something that worked for me from #Thomas Levesque's comment.
FileStream stream = new FileStream(imageLocation, FileMode.Open);
Image image = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = stream;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.EndInit();
image.Source = bi;
image.Height = 15;
btn.Content = image;
stream.Close();
stream.Dispose();
try with some modifications in your code
set the write permission to your opened file
FileStream stream = new FileStream("Images/" + name + ".jpg", FileMode.Create, FileAccess.Write);

Categories

Resources