Problems overwriting (re-saving) image when it was set as image source - c#

Good day all,
I am having some trouble with image permissions.
I am loading an image from file, resizing it and then saving it out to another folder.
I am then displaying this like so:
uriSource = new Uri(Combine(imagesDirectoryTemp, generatedFileName), UriKind.Absolute);
imgAsset.Source = new BitmapImage(uriSource);
This is working fine, the trouble comes if the user then selects another image immediately after and tries to save it over the original file.
An exception is generated upon saving my image "ExternalException: A generic error occurred in GDI+."
After some playing around i have narrowed the error down to imgAsset.Source = new BitmapImage(uriSource); as removing this line and not setting the imagesource will allow me to overwrite this file many times.
I have also tried setting the source to something else, before re-saving in the hope that the old reference would be disposed, this was not the case.
How can i get past this error?
Thanks,
Kohan
Edit
Now using this code i am not getting the exception however the image source is not updating. Also since i am not using a SourceStream, im not sure what i need to dispose of to get this working.
uriSource = new Uri(Combine(imagesDirectoryTemp, generatedFileName), UriKind.Absolute);
imgTemp = new BitmapImage();
imgTemp.BeginInit();
imgTemp.CacheOption = BitmapCacheOption.OnLoad;
imgTemp.UriSource = uriSource;
imgTemp.EndInit();
imgAsset.Source = imgTemp;

You're almost there.
Using BitmapCacheOption.OnLoad was the best solution to keep your file from being locked.
To cause it to reread the file every time you also need to add BitmapCreateOptions.IgnoreImageCache.
Adding one line to your code should do it:
imgTemp.CreateOption = BitmapCreateOptions.IgnoreImageCache;
thus resulting in this code:
uriSource = new Uri(Combine(imagesDirectoryTemp, generatedFileName), UriKind.Absolute);
imgTemp = new BitmapImage();
imgTemp.BeginInit();
imgTemp.CacheOption = BitmapCacheOption.OnLoad;
imgTemp.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
imgTemp.UriSource = uriSource;
imgTemp.EndInit();
imgAsset.Source = imgTemp;

When you load an Image in any WPF control it let's handle to your image and doesn't release it until you close your application. The reason for this... I dont know exactly, problably is relaying on some DirectX code behind the scene which never knows when the WPF application releases the image..
Use this code to load the image..
MemoryStream mstream = new MemoryStream();
System.Drawing.Bitmap bitmap = new Bitmap(imgName);
bitmap.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg);
bitmap.Dispose(); // Releases the file.
mstream.Position = 0;
image.BeginInit();
image.StreamSource = mstream;
image.EndInit();
this.img.Source = image ;
it worked for me..

Sounds very much like the problem I had developing Intuipic, where WPF would not dispose of the image, thus locking the file. Check out this converter I wrote to deal with the problem.

Related

C# - Monogame - Program still uses an image after setting it to null

Okay so basically I want to load an image (check), use it (check), unload it(semi-check) and then load it again (fail)...
So here is what I did:
TileTexture = Texture2D.FromStream(GraphicsDevice, new System.IO.FileStream(tileTextureName, System.IO.FileMode.Open));
It load a textuure, works fine, I can draw it no problem, then when I don't want to use it I set it to null
this.TileTexture = null;
and it works fine, image dissapears, and I am able to load some other image from anywhere on my computer again (and then that image is put into that Texture2D variable where the previous one was), but when I want to load the image I used before again, even though now another image is stored in that Texture2D variable, I get an exception:
The program cannot acces the file because it is being used by another process. (Which would be my program).
How do I then completly stop my Monogame program from using this image so I can acces it again at the same runtime if maybe I would need to ?
You need to close your stream when you are done with it. Instead of this:
TileTexture = Texture2D.FromStream(GraphicsDevice, new System.IO.FileStream(tileTextureName, System.IO.FileMode.Open));
Try:
using (var fs = new System.IO.FileStream(tileTextureName, System.IO.FileMode.Open))
{
TileTexture = Texture2D.FromStream(GraphicsDevice, fs);
}
using will take care of closing and disposing the stream
You are calling a new steam on your method call:
new System.IO.FileStream(tileTextureName, System.IO.FileMode.Open))
Instead, place it in a var and then call the .Close method
var stream = new System.IO.FileStream(tileTextureName, System.IO.FileMode.Open)
...
stream.Close();

C# How to dispose of OpenFileDialog file

I use OpenFileDialog to get the path of an image and then set it to my image source property imgSelected.Source = new BitmapImage(new Uri(filenameSteg, UriKind.Absolute)); in a WPF application.
The thing is, I need to open that file again later but I can't open it since the file is being used by another process ( System.IO.IOException -> The process cannot access the file pathToFile because it is being used by another process.).
The code that needs to access it later it as follow :
bitmapSource = JpegBitmapDecoder.Create(File.Open(filenameSteg, FileMode.Open),
BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames[0];
This bitmapSource is used to give that image to a WriteableBitmap and from there I go through the pixels.
Is there any way to dispose of a File opened with an OpenFileDialog ?
I tried to cast to to IDisposable, to use a using block and so on but this thing is persistent.
EDIT :
1 - I tried this (#ctacke answer) :
using (var stream = File.Open(filenameSteg, FileMode.Open)){
bitmapSource = JpegBitmapDecoder.Create(stream, BitmapCreateOptions.None,
BitmapCacheOption.OnLoad).Frames[0];}
But it still gives me the error about the process being already in used by another process because even though it will be disposed after, I still am trying to open the same file (filenameSteg) than I opened in the OpenFileDialog. (Or at least, that's how I see it.)
2 - I then tried this (based on #ctacke recommended link:
using (FileStream fileStream = new FileStream(filenameSteg+1, FileMode.Create)){
MemoryStream memoryStream = new MemoryStream();
BitmapImage bi = new BitmapImage();
byte[] fileBytes = File.ReadAllBytes(filenameSteg);
memoryStream.Write(fileBytes, 0, fileBytes.Length);
memoryStream.Position = 0;
bi.BeginInit();
bi.StreamSource = memoryStream;
bi.EndInit();
bitmapSource = bi;}
Note : Notice that I here ask for filenameSteg +1. That is because I wanted to test the rest of my method so I create a copy the file and simply added a 1 to its name. That being said, when using filenameSteg for real, it gave me the same error about being already in used which I again suspect is that I still am asking to open the same image that was previously opened in the OpenFileDialog.
3 - I thought of another approach which does not require me to dispose the opened image :
When I open the image for the first time in the OpenFileDialog, I store the byte array of the image in a variable so I could create the WriteableBitmap using the BitmapFactory and the byte array.
// This is in the OpenFileDialog. It is where I stock the image "pixels" in a byte array.
bytesArrayImage = File.ReadAllBytes(filenameSteg);
//And then later when I needed the WriteableBitmap, I used the byte array and the BitmapFactory
//imgSelected being the Image containing the image I opened in the OpenFileDialog, I used it's
//width and height
wb = BitmapFactory.New(Convert.ToInt32(imgSelected.Width),
Convert.ToInt32(imgSelected.Height)).FromByteArray(bytesArrayImage);
The problem with this approach is that, some pictures works fine and I can use the byte array to create the WriteableBitmap and go through it's pixels but in other cases it gives me an AccessViolationException stating : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.. In other words, trying to bypass the dispose problem got me into another problem.
You should release the original image, something like this:
if(imgSelected.Source != null)
{
imgSelected.Source.Dispose;
}
imgSelected.Source = new BitmapImage(new Uri(filenameSteg, UriKind.Absolute));
Next, File.Open returns a stream, which you need to explicitly release.
using(var stream = File.Open(filenameSteg, FileMode.Open))
{
var bitmapSource = JpegBitmapDecoder.Create(stream,
BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames[0];
}
See also: Load a BitmapSource and save using the same name in WPF -> IOException

Deleting image displayed in Windows Phone Image Control

I have the following code to display image in an Image control.
var stream = isolatedStorage.OpenFile(imageName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
imageControl.Source = bitmapImage;
I also want to give the user option to delete the image. I have the following code for it.
myImage.Source = null;
isolatedStorage.DeleteFile(imageName);
But this results in IsolatedStorageException with the message 'Unable to delete the file'.
I can't use stream source property of the bitmap or use Cache option, since Windows phone doesn't support them.
Any other workaround?
May be you need to close the fileStream before deleting the file.
Try
stream.Close()
or something like this before deleting the file
OR
If your isolatedStorage variable is of type IsolatedStorageFile then you can directly use
isolatedStorage.DeleteFile("yourfilename.ext");

Silverlight image loading problems

I simply cannot load Silverlight images synchronously. ImageOpened is all well and good but it doesn't really help me if if I have 20 textures to load BEFORE the app is allowed to execute! You cannot use threads as it causes multiple cross domain / cross thread exceptions. I have solved it but I am v curious as to how anyone else has tackled this.
My requirement is to load a jpeg / png / whatever into a pixel array, as i say, asynchronous options are a no go as I NEED the pixels before I start rendering.
Help!
you didn't say, from where you load a jpeg / png / whatever. If from resource, you can try to load first to BitmapImage, but not by UriSource property. Just use a method SetSource() - for me it loads the image immediately.
For example:
using System.Windows.Media.Imaging;
using System.Windows.Resources;
BitmapImage bmp = new BitmapImage();
Uri uri = new Uri("/SilverlightApp1;component/Resources/foto.jpg", UriKind.Relative);
StreamResourceInfo sri = Application.GetResourceStream(uri);
bmp.SetSource(sri.Stream);
Image image = new Image();
image.Source = bmp;

A Generic error occurs at GDI+ at Bitmap.Save() after using SaveFileDialog

I use the following code block with some more code inside the using block:
using (System.Drawing.Bitmap tempImg =
(System.Drawing.Bitmap)tempObj.GetData(System.Windows.Forms.DataFormats.Bitmap))
{
// ...
tempImg.Save("..\\..\\testdata\\tempImg.bmp", ImageFormat.Bmp);
// ...
}
But I still get the error:
A Generic Error occured at GDI+
only after I make some action which is not related to the code inside the using block. In other times this works well.
Also the tempImg.bmp is a temporary file, so I delete the tempImg.bmp within the using block itself.
Since the tempImg is inside the using and this it's disposed, I think the locking problem should be solved.
Can someone please let me know what is the mistake in this code?
Edit:
System.Drawing.Image to System.Drawing.Bitmap as the type of tempImg.
Edit:
I have identified I get this error only after SaveFileDialog is created and user clicks on 'Save'.
Finally I could find what was wrong in my code and would like to mention it here as I think it may be useful to someone....
As I have given a relative path in tempImg.Save, and after the user clicks 'Save' in SaveFileDialog, the actual path for tempImg.Save become :
Path specified by SaveFileDialog + the relative path
automatically.
Thus if the path does not exist, this error occurs.
Thanks every one for the answers.
I also had once this problem- it happens because the bitmap locks and you can't save it( if you want I can find the exact explanation) so anyway a fix around is this:
Create a new bitmap the size of the original bitmap you have- copy the original bitmap to the new created bitmap and then dispose the original bitmap and save the new one.
Bitmap bm3 = new Bitmap(bm2);
And then save.
This is usually an indicator that something else, potentially some other thread in your own application, already has the target file that you're trying to save locked at the file system level. If you look at the inner exception I believe it should mention this. If it's not directly in the InnerException Another way to confirm this (or discover what it might really be instead) is to turn on first chance exceptions in the debugger and watch for what exception is being thrown "underneath" Save and then being turned into this generic exception.
Tried all the solutions given here, but in vain. Found the solution eventually.
Dispose any Graphics applied on image: g.dispose();
Make sure save path exists: System.IO.Directory.Exists(dir);
Is this an ASP.NET application?
A Generic Error occured at GDI+ in asp.net mostly because of missing target folder / access permissions.
Also your code could be simplified to :
using (Image image= dataObject.GetImage())
{
if (image != null)
{
image.Save("test.bmp");
}
}
In my case it was an ASP.NET application in which I replaced a single DLL, and I had to simply re-start the application pool after deployment. Then it worked fine.
This is code sample from Microsoft Forums.
// new image with transparent Alpha layer
using (var bitmap = new Bitmap(330, 18, PixelFormat.Format32bppArgb))
{
using (var graphics = Graphics.FromImage(bitmap))
{
// add some anti-aliasing
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var font = new Font("Arial", 14.0f, GraphicsUnit.Pixel))
{
using (var brush = new SolidBrush(Color.White))
{
// draw it
graphics.DrawString(user.Email, font, brush, 0, 0);
}
}
}
// setup the response
Response.Clear();
Response.ContentType = "image/png";
Response.BufferOutput = true;
// write it to the output stream
bitmap.Save(Response.OutputStream, ImageFormat.Png);
Response.Flush();
}
I am trying to save image from resource and it gives me too GDI error when I directly use the method Bitmap.Save(filepath).
I think We can use the same below code for any other bitmap image by cloning it.
Private void SaveResourceImage() {
object resBmpObject = Resource.Image1.Clone();//Bitmap Image from resource file
//object resBmpObject = anyBmpImage.clone(); //for image other than resource image
Bitmap resBmpImage = (Bitmap)resBmpObject;
resBmpImage.Save(destFilePath, System.Drawing.Imaging.ImageFormat.Png);
resBmpImage.dispose();
}
Dispose your bitMap object after save image:
bitMap.Dispose()
oimg.Dispose()
bitMap = Nothing
oimg = Nothing
In my case, i was saving the bitmap file on the same location as the source,
So that's the problem.
I save the bitmap to the new location and all fine now.
I was facing the same issue, by changing image type ".bmp" to ".png" its work form me

Categories

Resources