Image.FromFile 是否因图像格式无效而引发 OutOfMemoryException ?

发布于 2024-08-28 07:11:29 字数 535 浏览 5 评论 0原文

我正在编写捕获此 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 吗?

I am writing code that catches this OutOfMemoryException and throws a new, more intuitive exception:

/// ...
/// <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 );
    }
}

Is this code acceptable to its user, or is OutOfMemoryException intentionally being thrown for a particular reason?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

眼眸里的快感 2024-09-04 07:11:29

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

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

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

No, it is history. GDI+ was written quite a while before .NET ever came around. The SDK wrapper for it was written in C++. Exceptions are iffy in C++, not everybody buys into them. Google doesn't for example. So to keep it compatible it reports problems with error codes. That just never scales well, library programmers make it a goal to intentionally limit the number of possible error codes, it lessen the burden on the client programmer having to report them.

GDI+ has this problem in spades, it defines only 20 error codes. That is not much for such a large chunk of code with so many external dependencies. Which in itself is a problem, there are a gazillion ways to mess up an image file. No way that a library's error reporting can be fine-grained enough to cover them all. The fact that these error codes were picked long before .NET defined standard Exception derived types certainly didn't help.

The Status::OutOfMemory error code got overloaded to mean different things. Sometimes it really does mean out of memory, it can't allocate enough space to store the bitmap bits. Sadly, an image file format problem is reported by the same error code. The friction here is that it cannot possibly decide if the width * height * pixels it read from the image file is a problem because there isn't enough storage available for the bitmap. Or if the data in the image file is junk. It assumes that image file is not junk, fair call, that's another program's problem. So OOM is what it reports.

For completeness, these are the error codes:

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)
};
旧夏天 2024-09-04 07:11:29

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

公平地说,我认为这是他们可能在这里做出的异常类型最糟糕的选择。当您打开一个文件,并且它恰好很大,并且您收到 OutOfMemoryException 时,可以合理地假设您实际上内存不足,并且暂时找错了树(还有更多比 StackOverflow 上关于此的一个问题)。

Well, it's a good example of how an exception doesn't always mean what it says. This particular case (OutOfMemoryException for an invalid file) dates back to .Net 1.0, which had a more limited set of exception types from which the programmers of this library could choose. I assume it hasn't been changed since then to maintain backwards compatibility (a.k.a. "throwing good money after bad").

To be fair, I think it was about the worst possible choice for exception type they could have made here. When you open a file, and it happens to be big, and you get an OutOfMemoryException, it's logical to assume that you're actually out of memory and go barking up the wrong tree for awhile (there's more than one question on StackOverflow about this).

坚持沉默 2024-09-04 07:11:29

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

If it's because the file is invalid, it's probably just trying to guess how big a buffer it needs based on some bytes in what it thinks is the header. Document your intent clearly with a test and you should be fine.

只想待在家 2024-09-04 07:11:29

这是一个具有误导性的例外。微软

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

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

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

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

(位图源自图像)

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

It's a misleading exception. Microsoft says:

You receive a "System.OutOfMemoryException" error message when you try to use the Bitmap.FromFile method in the .NET Framework 1.0

This problem may occur when you use the Bitmap.FromFile method and one of the following conditions is true:

  • The image file is corrupted.
  • The image file is incomplete.

Note You may experience this problem if your application is trying to use the Bitmap.FromFile method on a file stream that is not finished writing to a file.
* The image file does not have a valid image format or GDI+ does not support the pixel format of the file.
* The program does not have permissions to access the image file.
* The BackgroundImage property is set directly from the Bitmap.FromFile method.

(Bitmap descends from Image)

Of course, it's also possible to get this exception when you try to load an image which is too big. So you need to consider that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文