Image.FromFile 是不是为无效的图像格式抛出 OutOfMemoryException 的原因?

Posted

技术标签:

【中文标题】Image.FromFile 是不是为无效的图像格式抛出 OutOfMemoryException 的原因?【英文标题】:Is there a reason Image.FromFile throws an OutOfMemoryException for an invalid image format?Image.FromFile 是否为无效的图像格式抛出 OutOfMemoryException 的原因? 【发布时间】:2011-02-06 07:32:09 【问题描述】:

我正在编写代码来捕获这个OutOfMemoryException 并抛出一个新的、更直观的异常:

/// ...
/// <exception cref="FormatException">The file does not have a valid image format.</exception>
public static Image OpenImage( string filename )

    try
    
        return Image.FromFile( filename );
    
    catch( OutOfMemoryException ex )
    
        throw new FormatException( "The file does not have a valid image format.", ex );
    

用户是否可以接受此代码,还是出于特定原因故意抛出 OutOfMemoryException

【问题讨论】:

【参考方案1】:

不,这是历史。 GDI+ 是在 .NET 出现之前很久才编写的。它的 SDK 包装器是用 C++ 编写的。例外在 C++ 中是不确定的,并不是每个人都接受它们。例如,谷歌没有。因此,为了保持兼容,它会报告错误代码的问题。这永远不会很好地扩展,库程序员将有意限制可能的错误代码的数量作为目标,它减轻了客户端程序员必须报告它们的负担。

GDI+ 有这个问题,它只定义了 20 个错误代码。对于具有如此多外部依赖项的如此大块代码来说,这并不。这本身就是一个问题,有无数种方法可以弄乱图像文件。库的错误报告不可能细化到足以涵盖所有这些。早在 .NET 定义标准异常派生类型之前就选择了这些错误代码这一事实当然没有帮助。

Status::OutOfMemory 错误代码被重载以表示不同的含义。有时它确实意味着内存不足,它无法分配足够的空间来存储位图位。可悲的是,相同的错误代码报告了图像文件格式问题。这里的摩擦是它不可能确定它从图像文件中读取的宽度 * 高度 * 像素是否有问题,因为没有足够的存储空间可用于位图。或者如果图像文件中的数据是垃圾。它假设图像文件不是垃圾,公平调用,这是另一个程序的问题。所以 OOM 就是它报告的内容。

为了完整起见,以下是错误代码:

enum Status

    Ok = 0,
    GenericError = 1,
    InvalidParameter = 2,
    OutOfMemory = 3,
    ObjectBusy = 4,
    InsufficientBuffer = 5,
    NotImplemented = 6,
    Win32Error = 7,
    WrongState = 8,
    Aborted = 9,
    FileNotFound = 10,
    ValueOverflow = 11,
    AccessDenied = 12,
    UnknownImageFormat = 13,
    FontFamilyNotFound = 14,
    FontStyleNotFound = 15,
    NotTrueTypeFont = 16,
    UnsupportedGdiplusVersion = 17,
    GdiplusNotInitialized = 18,
    PropertyNotFound = 19,
    PropertyNotSupported = 20,
#if (GDIPVER >= 0x0110)
    ProfileNotFound = 21,
#endif //(GDIPVER >= 0x0110)
;

【讨论】:

其中几乎 any 都是比OutOfMemory 更好的选择,甚至是GenericError 尤其是UnknownImageFormat 似乎适用于无法理解的格式。【参考方案2】:

嗯,这是一个很好的例子,说明异常并不总是意味着它所说的。 This particular case(OutOfMemoryException 表示无效文件)可以追溯到 .Net 1.0,它有一组更有限的异常类型,该库的程序员可以从中选择。我认为从那时起它就没有改变以保持向后兼容性(也就是“坏钱扔好钱”)。

公平地说,我认为这是他们可能在这里做出的异常类型的最糟糕的选择。当你打开一个文件,它碰巧很大,你得到一个OutOfMemoryException,假设你实际上内存不足并在错误的树上吠了一会儿是合乎逻辑的(在 *** 上有不止一个问题关于这个)。

【讨论】:

【参考方案3】:

如果是因为文件无效,它可能只是试图根据它认为是标题的一些字节来猜测它需要多大的缓冲区。通过测试清楚地记录您的意图,您应该没问题。

【讨论】:

【参考方案4】:

这是一个误导性的例外。微软says:

当您尝试在 .NET Framework 1.0 中使用 Bitmap.FromFile 方法时收到“System.OutOfMemoryException”错误消息

当您使用 Bitmap.FromFile 方法并且以下条件之一为真时,可能会出现此问题:

图像文件已损坏。 图像文件不完整。

注意如果您的应用程序尝试对未完成写入文件的文件流使用 Bitmap.FromFile 方法,您可能会遇到此问题。 * 图像文件没有有效的图像格式或 GDI+ 不支持文件的像素格式。 * 程序无权访问图像文件。 * BackgroundImage 属性直接从 Bitmap.FromFile 方法设置。

(位图从图像下降)

当然,当您尝试加载太大的图像时,也可能会出现此异常。所以你需要考虑这一点。

【讨论】:

当它在谷歌上的第一次点击时,几乎不值得添加链接。 :) @MusiGenesis:有人可能会争辩说根本不值得回答这个问题。 :)(那我为什么要这么做?我不知道)

以上是关于Image.FromFile 是不是为无效的图像格式抛出 OutOfMemoryException 的原因?的主要内容,如果未能解决你的问题,请参考以下文章

System.Drawing.Image.FromFile() 上的内存不足异常

Image.FromFile 方法锁住文件解决方法

从文件中打开图像,然后释放锁定?

除非我使用Image.FromFile,否则Image.SelectActiveFrame为何在多页TIFF的最后一帧上失败(“ GDI +中发生一般错误”)?

并行调整图像大小导致内存不足异常

如何将图像绘制为整个矩形而与背景无关