【发布时间】:2015-02-21 17:39:58
【问题描述】:
我正在尝试编写一些 C# 代码,它将为位于磁盘上的 .bmp 命名。 为此,我一直在关注维基百科页面:BMP File Format
所以我创建了 2 个类来包含标题。 首先是文件头:
class BMPFileHeader
{
public BMPFileHeader(Byte[] headerBytes)
{
// Position
int offset = 0;
// Read 2 byes
bfType = ((char)headerBytes[0]).ToString();
bfType += ((char)headerBytes[1]).ToString();
offset = offset + 2;
// Read 4 bytes to uint32
bfSize = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
// Read 2 bytes to uint16
bfReserved1 = BitConverter.ToUInt16(headerBytes, offset);
offset = offset + sizeof(UInt16);
// Read 2 bytes to uint16
bfReserved2 = BitConverter.ToUInt16(headerBytes, offset);
offset = offset + sizeof(UInt16);
// Read 4 bytes to uint32
bfOffBits = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
}
public string bfType; // Ascii characters "BM"
public UInt32 bfSize; // The size of file in bytes
public UInt16 bfReserved1; // Unused, must be zero
public UInt16 bfReserved2; // Same ^^
public UInt32 bfOffBits; // Pixel offset [ where pixel array starts ]
}
这似乎工作得很好。所以继续下一个标题,图像标题。 :
class BMPImageHeader
{
public BMPImageHeader(Byte[] headerBytes)
{
// Position
int offset = 0;
biSize = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
biWidth = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
biHeight = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
biPlanes = BitConverter.ToUInt16(headerBytes, offset);
offset = offset + sizeof(UInt16);
biBitCount = BitConverter.ToUInt16(headerBytes, offset);
offset = offset + sizeof(UInt16);
biCompression = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
biSizeImage = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
XPelsPerMeter = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
YPelsPerMeter = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
biClrUsed = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
biClrImportant = BitConverter.ToUInt32(headerBytes, offset);
offset = offset + sizeof(UInt32);
}
public UInt32 biSize; // Size of header, must be least 40
public UInt32 biWidth; // Image width in pixels
public UInt32 biHeight; // Image height in pixels
public UInt16 biPlanes; // Must be 1
public UInt16 biBitCount; // Bits per pixels.. 1..4..8..16..32
public UInt32 biCompression; // 0 No compression
public UInt32 biSizeImage; // Image size, may be zer for uncompressed
public UInt32 XPelsPerMeter; // Preferred resolution in pixels per meter
public UInt32 YPelsPerMeter; // Same ^^
public UInt32 biClrUsed; // Number color map entries
public UInt32 biClrImportant; // Number of significant colors
}
这似乎也有效..所以现在我有一些重要的信息可以显示 放那张照片。
biBitCount = bits per pixel
biHeight = height in pixel
biWidth = width in pixel
bfOffBit = Pixel array offset
所以作为一个聪明人,我认为我是。 我会开始将它们复制到我创建的包含 3 个字节的 struct 2D 数组中。红色、绿色和蓝色。 因此,将文件的所有其余部分读入缓冲区。并一次通过该缓冲区 3 个字节,并添加一个由这 3 个字节组成的像素。
public ImageManipulation(string _name, string _imageLocation)
{
// Set name
Name = _name;
// Initialize classes
//fHeader = new BMPFileHeader();
//iHeader = new BMPImageHeader();
if (File.Exists(_imageLocation))
{
int offset = 0;
Byte[] fsBuffer;
FileStream fs = File.Open(_imageLocation, FileMode.Open, FileAccess.Read);
// Start by reading file header..
fsBuffer = new Byte[14]; // size 40 bytes
fs.Read(fsBuffer, 0, 14);
fHeader = new BMPFileHeader(fsBuffer);
// Then image header, 40 bytes
fsBuffer = new Byte[40];
fs.Read(fsBuffer, 0, 40);
iHeader = new BMPImageHeader(fsBuffer);
// Apply pixels
Pixels = new RGBPixel[iHeader.biHeight, iHeader.biWidth];
// How many bytes per pixel
int bpi = iHeader.biBitCount/8;
// Read pixel array
long totalBytes = iHeader.biWidth*iHeader.biHeight*bpi;
if (totalBytes == iHeader.biSizeImage) ;
if (iHeader.biSizeImage == ( fHeader.bfSize - (iHeader.biSize + 14))) ;
// Create butter, read data
fsBuffer = new Byte[iHeader.biWidth*iHeader.biHeight*bpi];
fs.Read(fsBuffer, 0, (int)fHeader.bfOffBits);
int RowSize = ((iHeader.biBitCount *(int) iHeader.biWidth + 31) / 32) * 4;
int x, y;
x = y = 0;
long i;
int lcounter = 0;
// This reads 3 bytes a time
for (i = 0; i < totalBytes; i = i + 3)
{
// Read 3 bytes
Pixels[ (iHeader.biHeight-1) - y, x].RED = fsBuffer[i];
Pixels[ (iHeader.biHeight-1) - y, x].GREEN = fsBuffer[i + 1];
Pixels[ (iHeader.biHeight-1) - y, x].BLUE = fsBuffer[i + 2];
// Update position in array
x++;
if (x == iHeader.biWidth)
{
y++;
x = 0;
}
}
}
}
我在运行和编译这段代码时没有遇到任何错误,但是我之后使用 Bitmap.setPixel() 创建的图像几乎只是黑色的。所以我读错了像素,但我无法确定为什么?
我用来测试的图片是
我得到的是:
谢谢 任何帮助表示赞赏
【问题讨论】: