2011-11-23 34 views
9

我目前正在处理非常大的图像,这些图像基本上是通过拼接许多较小的图像(例如全景或照片马赛克软件)生成的。为了避免内存不足的情况(内存中只有如何排列较小图像的“映射”),我写了一些代码,将这些图像逐行保存为使用BinaryWriter和LockBits的位图。到现在为止还挺好。c#将非常大的位图保存为JPEG(或任何其他压缩格式)

现在的问题是,我想将这些图像另存为Jpegs(或PNG)。由于我对c#很新,我现在只能想到两种方法:

1)类似于位图保存过程。生成一些jpeg头文件并逐行保存大图片,之前以某种方式压缩它们。我不知道如何执行压缩。

2)将已保存的位图流式传输到内存中,并将其保存为编码的jpeg。

由于第二种方法似乎更容易,我想是这样的:

FileStream fsr = 
    new FileStream("input.bmp", FileMode.Open, FileAccess.Read); 
FileStream fsw = 
    new FileStream("output.jpg", FileMode.CreateNew, FileAccess.Write); 

EncoderParameters encoderParameters = new EncoderParameters(1); 
encoderParameters.Param[0] = 
    new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L); 

Bitmap bmp = new Bitmap(fsr); 
bmp.Save(fsw, GetEncoder(ImageFormat.Jpeg), encoderParameters); 
bmp.Dispose(); 

的问题是现在的救法会先尝试完全加载位图到内存中,造成了内存不足例外。

对于如何解决或规避此问题的任何建议,我都非常乐意!

+1

OutOfMemoryException在这个时代?你的位图有多大? – zmbq

+2

是的,你可以很容易地遇到内存问题,我正在调整大小约10K的图像,并经常运行到“OutOfMemoryException”中,即使我正确处置。 – DarthVader

+1

从位图OOM是非常可疑的。这个类将抛出内存异常几乎任何错误,包括错误的参数等。 –

回答

0

我怀疑你不能在.NET中这样做,但你总是可以调用C库来完成繁重的工作。我自己并没有使用它,但我建议你看看GraphicsMagick库。这是一个拥有许可证的C库,允许开源和商业用途,看起来它可以满足你的需求。

+0

谢谢,我会看看它。但我实际上更喜欢避免额外的库。 – mgulde

+0

我检查了GraphicsMagick lib,但找不到任何关于如何在块中写入jpegs(或pngs)的内容。 – mgulde

1

注意,JPEG压缩有一些重要的非平凡的缺点:

1)JPEG是有损耗的,所以你不会重新相同的图像。这可能是完全可以接受的,但是如果您需要准确地重新生成源图像,那么PNG就是要走的路。

2)JPEG在8像素边界上对齐。如果您施蒂希在一起时的大小不是8的多个图像,无论是在宽度和高度,你会得到的图像边界

考虑您的使用情况下,一些有实力的假象,我宁愿建议针迹图像在一起,在每个较小的图像上使用标准的压缩算法,如PNG或Zlib。您仍然可以将生成的压缩流存储到单个文件中。优点是你可以直接“跳”到你想要提取的小图像的位置,这将节省*很多*的内存。

缺点是,你不能“视觉预览”所有较小的图像变成一个大的图像(你需要创建一个这种用法的程序)。

+0

首先,非常感谢。 将代码更改为保存不是线形的大图像,而是以8x8px的块为单位应该没有问题。由于将其保存为jpeg而导致的轻微信息损失无关紧要。 我现在的问题是,我完全不知道如何写一个jpeg(或PNG,文件)文件块。 – mgulde

+0

如果你想坚持“大图像”的方法,我宁愿建议将它保存在8行的乐队。然后,您将在内存中获取宽度x 8像素的位图,与完整图像相比,这会降低内存需求。 – Cyan

+0

我刚刚修改了代码,现在将图像保存为8行。但仍然存在一个问题,我不知道如何将它保存为jpeg:对于bmp,我编写了一个头文件,然后只是逐个流传输ARGB字节值。我需要一些函数,它可以写一个jpeg头文件,然后 - 这就是我认为是棘手的部分 - 将这些波段编码为jpeg格式,并将其附加到现有文件块中。 – mgulde

0

(因为标题说“或任何其他压缩格式”)

TIFF格式有瓷砖和条纹的概念。两者都可以用来避免随时在内存中拥有所有大型图像。可能瓷砖会派上用场,因为你正在拼接小图像。

您可以尝试使用LibTiff.Net(免费,商业友好,开放源代码,仅用C#编写)。

有一篇文章Basic introduction to the capabilities of the library,提供了有关条形和面向瓷砖的图像IO的信息(在文章的第二部分)。

声明:我为公司工作。

+0

谢谢,我会试试看。你知道吗,jpegs,png,aso也有类似的东西吗?通常情况下,我总是会选择jpeg。 – mgulde

+0

据我所知,JPEGs没有这样的东西。不幸的是,我不知道PNG是否有这样的情况。 – Bobrovsky

相关问题