繁体   English   中英

来自 Stream 的 BitmapImage 返回 1x1px 而不是整个图像

[英]BitmapImage from Stream returns 1x1px instead of the whole image

我有一个使用StreamSource属性打开FileStream并创建BitmapImage的方法。

不知何故,在一台机器上,试图打开一个大图像 (6000x4000px) 导致该方法返回一个 1x1px 图像。

首先我以为图像是从本地网络上的共享文件夹加载的,但它存储在同一台计算机的下载文件夹中。

我看到该图像被 Windows“阻止/锁定”,因为它是从未经验证的来源下载的,所以我打开属性并将其解锁。 尝试再次加载图像导致同样的问题。

图像已完全下载。

背景资料:

出现问题的机器:

  • Windows 7 SP1。
  • 32 位。
  • 网络框架 4.6.2。
  • 4GB 内存,使用了 2.5GB。

我的机器(它按预期工作):

  • Windows 10,内部版本 15063.413。
  • 64 位。
  • 网络框架 4.7。
  • 8GB 内存,使用了 6GB。

代码:

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.

题:

  • 有没有我的代码处理不当的情况,至少这解释了为什么我得到的是 1x1px 图像而不是全尺寸图像?
  • 另外,如果它无法加载图像,为什么它不抛出Exception

可能的答案:

工作代码:

using (var stream = new FileStream(fileSource, FileMode.Open, FileAccess.Read))
{
    using (var memory = new MemoryStream())
    {
        stream.CopyTo(memory);
        memory.Position = 0;
//...

只需替换这部分代码并在设置StreamSource对象时使用memory变量而不是stream

似乎当图像文件非常大,或者由于某些其他原因无法立即读取源流时,您必须将源流复制到中间 MemoryStream,并将其分配给 BitmapImage 的StreamSource属性:

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

当图像解码失败时, BitmapImage会创建一个 1x1px 的默认图像。 您需要注册DecodeFailed事件来检测这一点。

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

在我的例子中,结果是OutOfMemoryException 事实上,只有当内存使用率很高并且由BitmapImage (使用非托管内存)实际调用的本机函数可能无法分配足够的内存时,解码才会失败。

我遇到了同样的问题,CacheOption 不在您代码中的正确位置;! 只需在 endInit() 之前添加它;

 source.CacheOption = BitmapCacheOption.OnLoad;

像这样->

                BitmapImage source = new BitmapImage();
                source.BeginInit();
                source.CacheOption = BitmapCacheOption.OnLoad;
                source.StreamSource = fs;                  
                source.EndInit();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM