2

我需要将一些 BMP 图像附加在一起。您可能知道,BMP 图像有一个 54 字节的标题。我将自己的新标头写入一个新文件,然后我需要遍历 BMP 文件列表并将它们相互附加,但我需要跳过每个文件的前 54 个字节。

这是一个千兆像素的图像拼接项目。我会使用已经存在的软件,除了图像中没有重叠(但我知道平铺布局)。我需要能够将一些非常大的 BMP 文件 (192,000x1080) 作为行并将它们附加到另一个下方以创建最终图像,即 20.7 千兆像素。虽然我有 32GB 的内存,但最终的 20.7 千兆像素图像将是 62.2GB(然后我将转换为 PNG)。

鉴于这些巨大的内存需求,我如何在不使用所有内存的情况下读取每个 BMP 并将它们附加到最终文件?如果可能,我想使用字节数组;因为这些是未压缩的 BMP,它们可以像那样读取并保存到另一个文件,而无需使用任何 GDI 对象。

4

3 回答 3

4

您可以写入文件中的任意位置。以机智:

using(var s = new FileStream("myBigImage.bmp", FileMode.Create, FileAccess.Write)) {
    //assume that you write out the header here
    foreach(var tileFile in tiles) {
        byte[] imgData = /*read image data into a byte[]*/;
        long y = /*obtain the correct y offset*/;

        s.Position = y * pixelWidth * imageWidth + 58;
        s.Write(imgData, 0, imgData.Length);

    }
}

基本上,您可以在文件中跳转以填写您想要的任何位置。Position是一个 long 值,因此您不必担心碰到 32 位整数的限制。

幸运的是,因为您的图像基本上只是一堆高大的瓷砖,所以您不必担心处理每一行。在这种情况下,为了减少内存,您必须单独写出每个图块的行。

于 2013-03-27T13:01:57.507 回答
1

您不需要将所有生成的文件数据保存在内存中。只需打开一个 FileStream 并将数据写入文件。即使您写入千兆字节的数据,FileStream 也不会使用太多内存。

于 2013-03-27T13:01:57.910 回答
0

如果我之后的任何人感兴趣,这就是我发现的工作:

for (int i = 0; i < reverseImageFiles.Length; i++)
        {
            string curBMP = reverseImageFiles[i];

            using(Stream inStream = File.OpenRead(curBMP))
            using (Stream writeStream = new FileStream(outputBMP,FileMode.Append,FileAccess.Write,FileShare.None))
            {
                BinaryReader reader = new BinaryReader(inStream);
                BinaryWriter writer = new BinaryWriter(writeStream);

                byte[] buffer = new Byte[134217728];
                int bytesRead;
                int totalBytes = 0;

                while ((bytesRead = inStream.Read(buffer, 0, 134217728)) > 0)
                {
                    totalBytes += bytesRead;

                    if (totalBytes <= 134217729)  //if it's the first round of reading to the buffer, you need to get rid of 54-byte BMP header
                    {
                        writeStream.Write(buffer, 54, bytesRead - 54);
                    }
                    else
                    {
                        writeStream.Write(buffer, 0, bytesRead);
                    }
                }

            }
        }

两件事情:

特别是对于 BMP,我发现您需要在追加时反转文件列表。例如,如果要追加的三个文件分别标记为 001.bmp、002.bmp、003.bmp,其中 001.bmp 应该在顶部,则实际上需要从 003.bmp 开始并向下工作。显然 BMP 是向后编码的。

如您所见,我使用了 128MB 的缓冲区。如果我想减少硬盘搜索,使用不同的大小会更好吗? 我的驱动器最近进行了碎片整理。感谢所有的帮助!

于 2013-03-28T08:43:11.620 回答