Search code examples
c#wpfbitmapsource

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:

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.


Solution

  • 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;
    }