2

I have several large image files that I need to convert to different image formats. I am using the following code to do this:

using (Image img =new Bitmap(inputImageName))
        {
            img.Save(outputImageName, imageFormat);
        } 

It do the conversation, but also since the images are big, it generate outofmemory exception. I read several articles about how to overcome fragmentation of LOH, but I cannot use any of them in this case.

What Can I do?

The images are around 100MByte and it happens after opening 3 or 4 images.

4

3 回答 3

3

根据这篇文章,看看不使用 GDI 的 WPF 图像处理类。以下源代码是一个很好的起点:

public static void Resize(string input, string output)
{
    using (var inputStream = File.OpenRead(input))
    {
        var photoDecoder = BitmapDecoder.Create(inputStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);

        var frame = photoDecoder.Frames[0];

        using (var ouputStream = File.Create(output))
        {
            var targetEncoder = new PngBitmapEncoder();
            targetEncoder.Frames.Add(frame);
            targetEncoder.Save(ouputStream);
        }
    }    
}
于 2013-01-18T15:22:48.403 回答
3

您需要在这里问的问题是“我必须在 .NET 和/或 C# 中执行此操作吗”

虽然我明白为什么对于很多人来说,像 C# 这样灵活的语言可能是执行许多任务的答案,但我也不得不说“当你只有一把锤子时,每个问题看起来都像钉子”

如果这是一次性转换,并且您只需将它们用于一个项目,那么我对您的建议是使用更适合该工作的独立工具。

有大量的付费应用程序,例如:

AcdSee 照片管理器

http://www.acdsee.com/

释放工具,例如

Ifran View及其图像转换功能

http://www.bleepingcomputer.com/forums/topic50519.html

如果命令行脚本是您的游戏,那么请使用 ImageMagik 等工具集:

http://www.imagemagick.org/script/index.php

Iimage Magik 还具有 .NET 绑定,因此如果您的项目需要在程序代码中动态转换这些,则可以在 .NET 项目以及许多其他项目中使用它的功能。

http://www.imagemagick.org/script/api.php

对于像这样的场景,真的没有理由重新发明轮子,这个问题已经解决了很多次,所以它真的不是你应该做出的决定。

于 2013-01-18T14:41:43.207 回答
2

它与大对象堆没有任何关系。Bitmap 类是 GDI+ 的托管包装器,而 GDI+ 是一大块非托管代码。它在非托管内存中分配像素数据缓冲区。您的代码使用的托管内存量非常小。

一个 100 兆字节的图像文件并没有说明需要多少非托管内存。它很可能是一种压缩图像格式,例如 JPEG 或 PNG。解压缩后确实需要更多的非托管内存。因此,您很容易最终需要数百兆字节。

当您在 32 位操作系统上运行代码或选择 x86 作为 EXE 的平台目标设置(VS2010 及更高版本的默认设置)时,这是一个问题。您的程序从已加载的代码块和数据之间的可用漏洞中分配虚拟内存。GDI+ 需要一块连续的内存来加载像素数据,当您的程序有很多可用的虚拟内存但它分布在许多漏洞中时,这很难实现。另一个问题是地址空间碎片,加载 DLL 或分配内存可能会将一个大洞一分为二。

有一个简单的解决方法可以解决这个问题,在 64 位操作系统上运行你的代码。它有大量可用的虚拟内存,大洞。您可以对 32 位操作系统上的当前问题采取任何措施的可能性微乎其微。您无法直接控制内存管理器。

于 2013-01-18T15:14:21.513 回答