将字节数组转换为位图图像

37
我将把字节数组转换为 System.Windows.Media.Imaging.BitmapImage 并显示在图像控件中。使用第一段代码时,什么都不会发生!没有错误,也没有显示图像。但是当我使用第二段代码时,它正常工作!有人能解释一下发生了什么吗?第一段代码如下:
public BitmapImage ToImage(byte[] array)
{
   using (System.IO.MemoryStream ms = new System.IO.MemoryStream(array))
   {
       BitmapImage image = new BitmapImage();
       image.BeginInit();
       image.StreamSource = ms;
       image.EndInit();
       return image;
   }
}

第二段代码如下:

public BitmapImage ToImage(byte[] array)
{
   BitmapImage image = new BitmapImage();
   image.BeginInit();
   image.StreamSource = new System.IO.MemoryStream(array);
   image.EndInit();
   return image;
 }
2个回答

79
在第一个代码示例中,在图像实际加载之前流被关闭(通过离开using块)。您还必须设置BitmapCacheOptions.OnLoad,以实现立即加载图像,否则需要保持流打开,就像第二个示例中一样。
public BitmapImage ToImage(byte[] array)
{
    using (var ms = new System.IO.MemoryStream(array))
    {
        var image = new BitmapImage();
        image.BeginInit();
        image.CacheOption = BitmapCacheOption.OnLoad; // here
        image.StreamSource = ms;
        image.EndInit();
        return image;
    }
}

BitmapImage.StreamSource 的备注中:

如果您希望在创建 BitmapImage 后关闭流,请将 CacheOption 属性设置为 BitmapCacheOption.OnLoad。


此外,您还可以使用内置类型转换将类型 byte[] 转换为类型 ImageSource(或派生自 BitmapSource 的类型):

var bitmap = (BitmapSource)new ImageSourceConverter().ConvertFrom(array);

当您将类型为ImageSource(例如图像控件的Source属性)的属性绑定到类型为stringUribyte[]的源属性时,隐式调用了ImageSourceConverter


2
你提到了关于 CacheOption 的一个非常好的观点,但是在你的代码中,MemoryStream 在图像加载之前仍然会被释放。除非调用 EndInit() 加载图像。这是这种情况吗? - Mohammad Dehghan
2
是的,BitmapCacheOption.OnLoad 正是这样工作的。在 EndInit 过程中,图像会同步加载,因此流将在图像加载之前 不会 被处理。 - Clemens
非常好。我不知道关于CacheOption的那一点。我修改了我的代码,现在它可以工作了。 - Hossein Narimani Rad
我本以为这是JWTDO,但在Windows Store应用程序中,我收到了“错误1 'Windows.UI.Xaml.Media.Imaging.BitmapImage'不包含定义为'BeginInit'的内容,也没有扩展方法'BeginInit'接受类型为'Windows.UI.Xaml.Media.Imaging.BitmapImage'的第一个参数可以找到(您是否缺少使用...” - B. Clay Shannon-B. Crow Raven
Windows Runtime和WPF是两个不同的框架。在Windows Runtime中没有BeginInit和EndInit。只需调用SetSourceAsync即可。 - Clemens

4
在第一种情况下,你在using块中定义了MemoryStream,这会导致在你离开该块时对象被处理。因此,你返回一个带有已处理(不存在的)流的BitmapImageMemoryStream不保留未管理资源,所以你可以将内存保留下来,让GC处理释放过程(但这不是一种好的实践)。

1
请参考这个答案关于不要处理MemoryStream的问题。这至少被认为是一种不好的做法。 - Clemens
@Clemens 感谢您的评论和您的好回答。 - Mohammad Dehghan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接