【问题标题】:How can I process/display large images without getting System.OutOfMemoryExceptions?如何在不出现 System.OutOfMemoryException 的情况下处理/显示大图像?
【发布时间】:2017-01-13 16:23:08
【问题描述】:

我正在尝试显示大约 9,000 x 9,000 像素的图像。图像存储在文件中。我加载图像:

BitmapImage image = new BitmapImage(new Uri(dialog.FileName));

在那句话之后我冻结了图像。从那里,图像在内部存储/作为 BitmapSource/BitmapImage 传递给程序中的方法。

我已经编写了尝试使用 MemoryStream 对象(我将其放入 using 语句和所有内容)来调整图像大小/重新缩放图像的方法。例如,一种这样的方法以以下语句开头。

        using(MemoryStream stream = new MemoryStream())
        {
            PngBitmapEncoder e = new PngBitmapEncoder(); //BmpBitmapEncoder();
            e.Frames.Add(BitmapFrame.Create(image));
            e.Save(stream);
            ...
        }

我经常会在该函数的 e.Save(stream) 行上得到 System.OutOfMemoryException()。如果我不尝试调整图像大小,我将在创建使用 Image 控件显示图像的 Window 时收到 System.OutOfMemoryException()。

                <Image Source="{Binding Image}" HorizontalAlignment="Left" VerticalAlignment="Top"
                Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" />

现在,我了解到 OutOfMemory 异常可能是模棱两可的,因为它们并不一定意味着程序已经用尽了它可以访问的 RAM 量。有时,程序会设法显示图像(尽管不久之后它会抛出 OutOfMemoryException),所以我不认为有问题的文件已损坏/具有无效格式或任何东西。

在 WPF/.NET 中处理大型图像文件是否有更好的方法?任何建议将不胜感激!

编辑:我现在更改了冻结图像的方式(我创建的是冻结副本而不是冻结原件)。

【问题讨论】:

  • 确保您的程序没有选择“首选 32 位”。如果由于池碎片而导致 OOM,那将有所帮助。还要确保你没有在任何地方泄露图像的副本。
  • 我做了一些内存分析,分析的结果并不表明有任何碎片发生。另外——我的程序必须在 32 位机器上运行,所以如果我有一个适用于 64 位机器而不是 32 位机器的工作解决方案,那么不幸的是,这还不够。有其他选择吗?
  • 为什么要创建冻结副本而不是冻结原始图像?
  • 我不确定为什么会这样。我看不出有任何理由创建冻结副本,所以我将冻结原件。很好的收获,谢谢!

标签: c# .net wpf image


【解决方案1】:

如果您实际上不需要全分辨率来显示您的图像,您可以简单地设置 BitmapImage 的DecodePixelWidthDecodePixelHeight。不要同时设置两者,以保持图像的纵横比。

var image = new BitmapImage();
image.BeginInit();
image.DecodePixelWidth = 900;
image.UriSource = new Uri(dialog.FileName);
image.EndInit();
image.Freeze();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-17
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-04-08
    • 2023-03-16
    • 1970-01-01
    • 2014-04-17
    相关资源
    最近更新 更多