Outofmemory exception when do bitmapimage dispose - c#

I have created WPF windows application for display more images using grid. My below code getting OutOfMemory Exception when I run my application.exe.
byte[] buffer = File.ReadAllBytes(path);
File.Delete(path);
if (buffer == null)
return null;
using (MemoryStream mStream = new MemoryStream(buffer))
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = mStream;
bi.EndInit();
bitmap = bi;
bitmap.Freeze();
mStream.Close();
mStream.Dispose();
}
I found some solution from stackoverflow and changed my coding as following below,
BitmapImage image = new BitmapImage();
{
image.BeginInit();
// image.CreateOptions = BitmapCreateOptions.n;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(path);
image.EndInit();
File.Delete(path);
bitmap = image;
image.UriSource = null;
image = null;
}
But this code getting exception as that image used by another process or cant open from locked file.
I am totally confused why my application often caused by OutOfMemory or used by another process exception?

Taken from the comments, you are doing something wrong. You are initializing an obejct ob type BitmapImage and instantly declare it as null. So everything you have declared beforehand has gone down the crapper.
you should leverage the using() statements functionality here. If the code leaves this statement the GarbageCollector will automatically take over and dispose everything for you:
using(BitmapImage image = new BitmapImage())
{
image.BeginInit();
// image.CreateOptions = BitmapCreateOptions.n;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(path);
image.EndInit();
bitmap = image.Clone();
}

Related

Memory 'leak' with MemoryStream and BitmapCacheOption.OnLoad

I have to get a BitmapSource from an Image and for this I use an extension method like this:
public static BitmapSource ToBitmapSource(this Image image)
{
LogEx.FunctionEnter();
if (image == null)
throw new ArgumentNullException("image");
BitmapImage bitmapImage = null;
using (MemoryStream memory = new MemoryStream())
{
image.Save(memory, ImageFormat.Jpeg);
memory.Position = 0;
bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
LogEx.FunctionLeave("Rendered image as BitmapSource");
return bitmapImage;
}
If I now release the handle of this and dispose the original Image it stays in the memory, even after calling the GC by hand multiple times. I tested to use files instead of streams with this little piece of code:
string filename = $"c:\\temp\\{page}.jpg";
if (File.Exists(filename))
{
File.Delete(filename);
}
_highResPageImages[page].Save(filename, ImageFormat.Jpeg);
Uri uri = new Uri(filename);
BitmapImage source = new BitmapImage();
source.BeginInit();
source.UriSource = uri;
source.CacheOption = BitmapCacheOption.OnLoad;
source.EndInit();
Document.PageImage = source;
// Ducument.PageImage = _highResPageImages[page].ToBitmapSource();
And even if there is also an OnLoad, it gets disposed when the handle is released. So it must be something with the MemoryStream. But what? I tried this WrapperStream I found somewhere else and to use the Freeze() Method of BitmapImage, but both to no a avail. The problem is, that I cannot cache the images on the drive of the customer (even if it wouldn't cost a huge amount of time to do so) and I get the Image from another DLL, so I cannot change it beforehand. Has someone else an idea?
Edit: I use WPF and the value of the handle is being used in a Binding for display. Maybe that matters somehow. Or that I use BitmapSource in the Binding and handle and not the original BitmapImage.
Try this in ToBitmapSource:
...
bitmapImage.StreamSource = null;
return bitmapImage

BitmapImage from ByteArray/MemoryStream: Pixel format not supported

I am converting a BitmapImage from byte array, and it works fine, except with one specific .tif file. It gives an exception at EndInit():
The bitmap pixel format is unsupported. (Exception from HRESULT: 0x88982F80)
The code used to read the byte array to BitmapImage is:
public BitmapImage LoadImage(byte[] ImageData)
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit(); //Exception here
}
image.Freeze();
return image;
}
What does this mean? The image opens just fine in windows, so it is not corrupted or anything. Is there a way to convert the image to supported pixel format, before the EndInit?

BitmapImage from Stream returns 1x1px instead of the whole image

I have a method that opens a FileStream and creates a BitmapImage, by using the StreamSource property.
Somehow, in a single machine, trying to open a big image (6000x4000px) results in the method returning a 1x1px image instead.
First I thought that the image was being loaded from a shared folder on the local network, but It was stored in the downloads folder of the same computer.
I saw that the image was "blocked/locked" by Windows because it was downloaded from an unverified source, so I opened Properties and unlocked it. Trying to load the image again resulted in the same problem.
The image was fully downloaded.
Background information:
The machine with the problem:
Windows 7 SP1.
32 bits.
Net Framework 4.6.2.
4GB of memory, with 2.5GB being used.
My machine (it works as expected):
Windows 10, build 15063.413.
64 bits.
Net Framework 4.7.
8GB of memory, with 6GB being used.
Code:
public static BitmapSource SourceFrom(this string fileSource, int? size = null)
{
using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
if (size.HasValue)
{
//It's not possible to get the size of image while opening, so get from another place.
var refSize = fileSource.ScaledSize(); //Gets the size of the image.
if (refSize.Height > refSize.Width)
bitmapImage.DecodePixelHeight = size.Value;
else
bitmapImage.DecodePixelWidth = size.Value;
}
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
bitmapImage.Freeze(); //Just in case you want to load the image in another thread.
return bitmapImage;
}
}
Usage:
var image = "C:\Image.jpg".SourceFrom(); //Without any other parameter.
Question:
Is there any case that my code is not treating properly, at least that explains why I'm getting a 1x1px image instead of the full size one?
Also, why it does not throw an Exception if it can't load the image?
Probable answer:
My code does not handle if the image finished downloading or not, but the image was fully downloaded, so I'm not sure if this is the case. I've found a similar thread about the same problem.
Working code:
using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
using (var memory = new MemoryStream())
{
stream.CopyTo(memory);
memory.Position = 0;
//...
Just replace this part of the code and use the memory variable instead of stream while setting the StreamSource object.
It seems that when the image file is very large, or for some other reason the source stream can't be read immediately, you'll have to copy the source stream to an intermediate MemoryStream, and assign that to the StreamSource property of the BitmapImage:
using (var fileStream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
using (var memoryStream = new MemoryStream())
{
fileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad
bitmapImage.StreamSource = memoryStream;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
The BitmapImage creates a default image with 1x1px when decoding of the image fails. You need to register the DecodeFailed event to detect this.
Exception decodeEx = null;
using (var fileStream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = fileStream;
bitmapImage.DecodeFailed += (_, e) => decodeEx = e.ErrorException;
bitmapImage.EndInit();
if (decodeEx != null)
throw decodeEx;
bitmapImage.Freeze();
return bitmapImage;
}
In my case it turned out to be a OutOfMemoryException. Indeed decoding only failed when the memory usage was high and the native functionwhich is actually called by BitmapImage (using unmanaged memory) was probably unable to allocate enough memory.
i had the same problem, the CacheOption is not in the right place on your code!! juste add it befor the endInit();
source.CacheOption = BitmapCacheOption.OnLoad;
like this ->
BitmapImage source = new BitmapImage();
source.BeginInit();
source.CacheOption = BitmapCacheOption.OnLoad;
source.StreamSource = fs;
source.EndInit();

BitmapImage - image downloading issue

I use this code to get images from Internet
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.UriSource = new Uri(url, UriKind.Absolute);
image.EndInit();
RSSImage.Source = image;
And sometimes there are no images.
It seems that it happens because of the timeout and etc.
Anyway have I use some async. approaches to get image in time?
Any clue?
Loading image asynchronously (C# 5.0 and .NET Framework 4.5):
using (var client = new WebClient()) {
var bytes = await client.DownloadDataTaskAsync(url);
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = new MemoryStream(bytes);
image.EndInit();
RSSImage.Source = image;
}

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