我目前正在处理非常大的图像,这些图像基本上是由许多较小的图像(例如全景或照片马赛克软件)拼接在一起生成的。为了避免内存不足的异常(在内存中只是如何排列较小图像的"映射"),我编写了一些代码,使用BinaryWriter和LockBits将这些图像逐行保存为位图。到目前为止,一切顺利。
现在的问题是,我想保存这些图像为jpeg(或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方法试图首先将位图完全加载到内存中,从而导致内存不足异常。
如果有任何关于如何解决或规避这个问题的建议,我将非常高兴!请注意,JPEG压缩有一些重要的不容忽视的缺点:
1) JPEG是有损的,所以你不会重新生成相同的图像。这可能是完全可以接受的,但如果您需要准确地重新生成源图像,那么PNG是一种选择。
2) JPEG在8像素的边界上对齐。如果你把宽度或高度不是8的倍数的图像拼接在一起,你会在图像边界处得到一些强烈的伪影
考虑到您的用例,我宁愿建议而不是将图像拼接在一起,并在每个较小的图像上使用标准压缩算法,如PNG或Zlib。您仍然可以将生成的压缩流存储到单个文件中。这样做的好处是,你可以直接"跳转"到你想要提取的小图像的位置,这将节省大量的内存。
缺点是您不能"直观地预览"所有较小的图像到一个大的单个图像(您需要为此创建一个程序)。
我怀疑您不能在。net中做到这一点,但是您总是可以调用C库来完成繁重的工作。我自己没有使用过它,但我建议您查看GraphicsMagick库。这是一个有许可的C库,允许开源和商业用途,看起来它可能会做你需要的。
(由于标题显示"或任何其他压缩格式")
TIFF格式有tile和stripes的概念。两者都可以用来避免在任何时候将所有大图像都存储在内存中。也许瓷砖会派上用场,因为你是拼接小图像。
你可以试试LibTiff。Net(免费的,商业友好的,开源的,只用c#编写的)来完成这个任务。
有一篇文章基本介绍了库的功能,其中包含关于面向条形和平铺的图像IO的信息(在本文的第二部分)。
免责声明:我为公司工作。