如何在c#中转换大图像文件

时间:2013-01-18 14:08:48

标签: c#

我有几个大图像文件需要转换为不同的图像格式。我使用以下代码执行此操作:

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

它进行对话,但由于图像很大,它会产生outofmemory异常。我读了几篇关于如何克服LOH碎片的文章,但在这种情况下我不能使用它们。

我该怎么办?

图像大约100MByte,打开3或4张图像后会发生。

3 个答案:

答案 0 :(得分:2)

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

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

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

除了付费应用程序之外,还有很多种类:

AcdSee Photo Manager

http://www.acdsee.com/

免费提供工具,例如

Ifran查看及其图像转换功能

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

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

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

Iamage Magik也有.NET绑定,所以如果您的项目要求您在程序代码中动态转换它们,那么它的功能可以在.NET项目中以及许多其他项目中使用。

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

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

答案 1 :(得分:2)

根据this article,查看不使用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);
        }
    }    
}

答案 2 :(得分:1)

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

100兆字节的图像文件并没有说明需要多少非托管内存。它很可能是压缩的图像格式,如JPEG或PNG。在未压缩之后,这需要更多的非托管内存。所以你最终可能需要数百兆字节。

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

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