因为BMP文件是从下到上(以像素为单位)写的,所以我需要反向读取BMP文件(并删除54字节的头文件)。到目前为止我的代码:
public string createNoHeaderBMP(string curBMP) //copies everything but the header from the curBMP to the tempBMP
{
string tempBMP = "C:\\TEMP.bmp";
Stream inStream = File.OpenRead(curBMP);
BinaryReader br = new BinaryReader(inStream);
byte[] fullBMP = new byte[(width * height * 3) + 138];
byte[] buffer = new Byte[1];
long bytesRead;
long totalBytes = 0;
while ((bytesRead = br.Read(buffer, 0, 1)) > 0)
{
fullBMP[fullBMP.Length - 1 - totalBytes] = buffer[0];
totalBytes++;
}
FileStream fs = new FileStream(tempBMP, FileMode.Create, FileAccess.Write);
fs.Write(fullBMP, 54, fullBMP.Length - 54);
fs.Close();
fs.Dispose();
return tempBMP;
}
由于某种原因,它无法完全完成工作,这导致右侧部分放置在左侧的图像。为什么不完全颠倒文件?此外,这些BMP文件非常大(600MB),因此我不能使用简单的内存流并执行搜索和交换操作,因为我将获得“Out of Memory”异常。
答案 0 :(得分:1)
我没有检查过BMP规范,我对此一无所知。我只是假设你说的是真的。
大多数显示位图的程序只是读取标题以找出图像的大小,然后从上到下读取数据,从而从底部到顶部绘制位图。你也可以在大多数文件中寻找。因此,您可以使用inStream
并在其中进行搜索,而无需将整个文件存储在内存中。
然后,如果你可以分配600 MiB的字节数组(即内存中的600 MiB结构),那么你肯定可以分配一个占用600 MiB内存空间的MemoryStream
。或者,如果您获得OutOfMemoryException
,那么无论您使用byte[]
还是MemoryStream
,都可以获得fullBMP
。后者更容易使用。
除非你意识到你已经将每个像素的颜色从R-G-B格式(或目前的任何格式)转换为B-G-R,否则你只想扭转一切的想法都会失败。而且我不确定BMP扫描线的方向,但如果它们从左向右运行,那么反转的位图将使图像水平翻转。
左侧显示右侧部分图像的原因是因为您不能只反转位图的字节并期望它正确显示。此外,绘制时可能会出现扫描线长度错误。
另外,您说标头是54个字节,但您在const
中向数组大小添加了138个字节。检查你的常数:他们保证永远不会改变,然后让他们{{1}}。愿他们改变吗?然后从位图中读取它们。
答案 1 :(得分:0)
我发布了一个答案 here,用于反转大文件而不将其存储在 RAM 中。
你可以用它来做这样的事情(可能需要调整以获得丹尼尔提到的正确位图):
using (var inputFile = File.OpenRead("input.bmp"))
using (var inputFileReversed = new ReverseStream(inputFile))
using (var outputFile = File.Open("output.bmp", FileMode.Create, FileAccess.Write))
{
inputFile.Seek(headerSize, SeekOrigin.Begin); //skip the header
inputFileReversed.CopyTo(outputFile);
}