2013-03-27 57 views
2

我需要将几个BMP图像附加在一起。您可能知道,BMP图像具有一个54字节的标题。我会将自己的新头文件写入一个新文件,然后我需要遍历BMP文件列表并将它们附加到对方,但我需要跳过每个文件的前54个字节。读取文件A并追加到文件B,跳过一些字节

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

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

+2

>如何读取每个BMP并将它们追加到最终文件而不使用我所有的内存? 流式传输文件。 – Romoku 2013-03-27 12:55:29

回答

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是一个很长的值,所以你不必担心碰到32位整数的限制。

幸运的是,因为你的图片基本上只是一大堆瓷砖,所以你不必担心处理每一行。在这种情况下,为了保持内存不变,你必须单独写出每个瓦片的线条。

+0

我的回答有帮助吗?如果是这样,一个接受的答案将不胜感激! – 2013-10-22 21:34:53

1

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

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缓冲区。如果我想降低硬盘驱动器的搜索速度,使用不同的大小会更好吗?我的驱动器最近进行了整理。感谢所有的帮助!