【问题标题】:Image.GetThumbnailImage throws OutOfMemoryExceptionImage.GetThumbnailImage 抛出 OutOfMemoryException
【发布时间】:2015-03-30 07:45:16
【问题描述】:

以下 C# 3.5 代码在 GetThumbnailImage 中引发异常:

Image img = null;
Image scaledImg = null;

byte[] imageData = File.ReadAllBytes("11001.jpg");
MemoryStream stream = new MemoryStream(imageData);
img = Image.FromStream(stream);
stream.Close();
stream.Dispose();

scaledImg = img.GetThumbnailImage(64, 64, null, IntPtr.Zero);

问题在于流的处理。如果我删除 Close() 和 Dispose() 语句,一切正常。有谁知道为什么会抛出这个异常?使用回调而不是 null 作为参数不会改变行为。

我不需要解决方案,我可以使用 new Bitmap(img, new Size(width, height) 进行缩放。这可能更好,应该从一开始就使用。

编辑:对不起,我忘了提到这个异常只发生在 WindowsXP 中。 Win7 和 Win8 似乎可以很好地处理上面的代码。

【问题讨论】:

  • 只调用一次 => Dispose auto 关闭并释放句柄。
  • 或者直接使用using
  • 我假设你没有使用Image.FromFile,因为真正的代码有点复杂,对吧?
  • 真正的代码使用资源,而不是文件。并且图像的加载和调整大小在不同的部分,因此在调整大小后延迟处置是不可能的。

标签: c# winforms


【解决方案1】:

GetThumbnailImage 是本机方法,使用您在创建Image 时传递的相同流。只有 .NET 方法使用流中的实际数据(在从流中创建图像时,它作为最后一件事加载)。

这是一个非常典型的泄漏抽象。你以为你有一个 Image 对象已经加载了它的数据,但数据只加载到 .NET 部分。任何直接使用 GDI+ 图像句柄的方法仍然需要流是实时的。

同一问题的另一个示例是尝试以不同格式保存图像时。当您尝试使用相同的格式保存时,.NET 只是将其在内存中的字节数据保存,很简单。如果它不同相同,它将使用 GDI+ 方法SaveImageToFile,这再次要求保留原始流。

如果您不介意让流处于活动状态,您可以在对从该流生成的图像执行所有操作之后移动 Dispose

using (var stream = new MemoryStream(imageData))
{
  var img = Image.FromStream(stream);
  var scaledImg = img.GetThumbnailImage(64, 64, null, IntPtr.Zero);

  scaledImg.Save(...);
}

如果你介意,你可以做的最简单的事情是:

var bmp = new Bitmap(Image.FromStream(stream));

Bitmap 构造函数将复制图像数据,您不再需要保留流。

【讨论】:

    【解决方案2】:

    我认为GetThumbnailImage 使用流来完成它的工作,所以它需要打开它。你可以这样做:

    Image img = null;
    Image scaledImg = null;
    
    byte[] imageData = File.ReadAllBytes("11001.jpg");
    using(MemoryStream stream = new MemoryStream(imageData))
    {
    img = Image.FromStream(stream);
    scaledImg = img.GetThumbnailImage(64, 64, null, IntPtr.Zero);
    }
    

    (using 关闭并释放 MemoryStream 但它也处理异常情况以避免内存泄漏)

    【讨论】:

      【解决方案3】:

      Image 对象使用惰性求值。由于您已经关闭了流,当它实际尝试读取图像以获取缩略图时,它不再存在。因此出现错误。

      【讨论】:

        猜你喜欢
        • 2015-02-28
        • 2014-09-20
        • 1970-01-01
        • 2013-03-08
        • 2016-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多