Reputation: 3358
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.
The machine with the problem:
My machine (it works as expected):
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;
}
}
var image = "C:\Image.jpg".SourceFrom(); //Without any other parameter.
Exception
if it can't load the image?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.
Upvotes: 1
Views: 1445
Reputation: 31
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.
Upvotes: 2
Reputation: 1382
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();
Upvotes: 1
Reputation: 128061
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;
}
Upvotes: 2