32

I am having some trouble creating a BitmapImage from a MemoryStream from png and gif bytes obtained from a web request. The bytes seem to be downloaded fine and the BitmapImage object is created without issue however the image is not actually rendering on my UI. The problem only occurs when the downloaded image is of type png or gif (works fine for jpeg).

Here is code that demonstrates the problem:

var webResponse = webRequest.GetResponse();
var stream = webResponse.GetResponseStream();
if (stream.CanRead)
{
    Byte[] buffer = new Byte[webResponse.ContentLength];
    stream.Read(buffer, 0, buffer.Length);

    var byteStream = new System.IO.MemoryStream(buffer);

    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.DecodePixelWidth = 30;
    bi.StreamSource = byteStream;
    bi.EndInit();

    byteStream.Close();
    stream.Close();

    return bi;
}

To test that the web request was correctly obtaining the bytes I tried the following which saves the bytes to a file on disk and then loads the image using a UriSource rather than a StreamSource and it works for all image types:

var webResponse = webRequest.GetResponse();
var stream = webResponse.GetResponseStream();
if (stream.CanRead)
{
    Byte[] buffer = new Byte[webResponse.ContentLength];
    stream.Read(buffer, 0, buffer.Length);

    string fName = "c:\\" + ((Uri)value).Segments.Last();
    System.IO.File.WriteAllBytes(fName, buffer);

    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.DecodePixelWidth = 30;
    bi.UriSource = new Uri(fName);
    bi.EndInit();

    stream.Close();

    return bi;
}

Anyone got any light to shine?

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Simon Fox
  • 10,409
  • 7
  • 60
  • 81

2 Answers2

51

Add bi.CacheOption = BitmapCacheOption.OnLoad directly after your .BeginInit():

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
...

Without this, BitmapImage uses lazy initialization by default and stream will be closed by then. In first example you try to read image from possibly garbage-collected closed or even disposed MemoryStream. Second example uses file, which is still available. Also, don't write

var byteStream = new System.IO.MemoryStream(buffer);

better

using (MemoryStream byteStream = new MemoryStream(buffer))
{
   ...
}
Matt Roberts
  • 26,371
  • 31
  • 103
  • 180
alxx
  • 9,897
  • 4
  • 26
  • 41
  • 6
    The `BitmapCacheOption.OnLoad` trick is important. I would just like to add that it should be between `BeginInit()` and `EndInit()`. – Pieter Müller Jan 06 '12 at 09:48
  • 1
    @PieterMüller: Very helpful clue; in addition, the stream still *must* be open when calling `EndInit()` as another constraint that you might stumble over. – O. R. Mapper Sep 02 '12 at 19:24
14

I'm using this code:

public static BitmapImage GetBitmapImage(byte[] imageBytes)
{
   var bitmapImage = new BitmapImage();
   bitmapImage.BeginInit();
   bitmapImage.StreamSource = new MemoryStream(imageBytes);
   bitmapImage.EndInit();
   return bitmapImage;
}

May be you should delete this line:

bi.DecodePixelWidth = 30;
some_engineer
  • 1,844
  • 1
  • 19
  • 26
  • 1
    But what about closing the memory stream that you created by : new MemoryStream(imageBytes) I think change the CacheOption is better, Should such as streams closed? – Amer Sawan Nov 27 '12 at 14:02