c#将非常大的位图保存为jpegs(或任何其他压缩格式)

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

现在问题是我想将这些图像保存为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(); 

现在的问题是save-method尝试首先将位图完全加载到内存中,从而导致内存不足exception。

如果有任何关于如何解决或避免这个问题的建议,我会非常高兴!

请注意,JPEG压缩具有一些重要的重要缺点:

1)JPEG是有损的,因此您不会重新生成相同的图像。 这可能是完全可以接受的,但如果您需要精确地重新生成源图像,那么PNG就是您的选择。

2)JPEG在8像素边界上对齐。 如果您将尺寸不是8的倍数的图像放在一起,无论是宽度还是高度,您都会在图像边界处获得一些强烈的人工制品

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

缺点是您不能将所有较小的图像“可视地预览”为一个大的图像(您需要为此用法创建一个程序)。

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

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

TIFF格式具有瓦片和条纹的概念。 两者都可以用来避免在任何时候在内存中拥有所有大图像。 因为你正在缝合小图像,所以瓷砖会派上用场。

您可以尝试使用LibTiff.Net (免费,商业友好,开源,仅使用C#编写)来完成任务。

有一篇文章基本介绍了库的function,其中包含有关条带和磁贴的图像IO的信息(在本文的第二部分)。

免责声明:我为公司工作。