Создание WPF BitmapImage из MemoryStream png, gif

У меня возникли проблемы с созданием BitmapImage из MemoryStream из байтов png и gif, полученных из веб-запроса. Кажется, что байты загружены отлично, и объект BitmapImage создается без проблем, однако изображение на самом деле не отображается в моем пользовательском интерфейсе. Проблема возникает только тогда, когда загруженное изображение имеет тип png или gif (отлично работает для jpeg).

Вот код, который демонстрирует проблему:

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

Чтобы проверить, что веб-запрос правильно получил байты, я попробовал следующее, которое сохраняет байты в файл на диске, а затем загружает изображение с помощью UriSource, а не StreamSource и работает для всех типов изображений

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

Кто-нибудь получил свет, чтобы светить?

Ответ 1

Добавьте bi.CacheOption = BitmapCacheOption.OnLoad непосредственно после .BeginInit():

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

Без этого BitmapImage по умолчанию использует ленивую инициализацию, и к тому времени поток будет закрыт. В первом примере вы пытаетесь прочитать изображение из возможного собранного мусора закрытого или даже удаленного MemoryStream. Второй пример использует файл, который по-прежнему доступен. Кроме того, не пишите

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

лучше

using (MemoryStream byteStream = new MemoryStream(buffer))
{
   ...
}

Ответ 2

Я использую этот код:

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

Может быть, вы должны удалить эту строку:

bi.DecodePixelWidth = 30;