前几天花了些时间学习研究了下BMP文件结构,对BMP的文件结构有了大致的了解。本以为可以解决问题,但结果却还徒劳。在此记录下BMP文件结构,也算前几天的总结。
BMP文件准确的来说是由四个部分组成的,BMP文件头,BMP信息头,调色板和颜色数据区。
1、文件头(BITMAPFILEHEADER)
view plaincopy to clipboardprint?
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //类型,BMP为0x4D42
DWORD bfSize;//整个文件的大小,可以由BMP文件头,BMP信息头,调色板大小和数据区大小相+得出
WORD bfReserved1; //保留字,置为0
WORD bfReserved2; //保留字,置为0
DWORD bfOffBits; //整个头大小,BMP文件头,BMP信息头和调色板大小相+得到
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //类型,BMP为0x4D42
DWORD bfSize;//整个文件的大小,可以由BMP文件头,BMP信息头,调色板大小和数据区大小相+得出
WORD bfReserved1; //保留字,置为0
WORD bfReserved2; //保留字,置为0
DWORD bfOffBits; //整个头大小,BMP文件头,BMP信息头和调色板大小相+得到
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
sizeof(BITMAPFILEHEADER) = 14 Byte;
虽然根据字节对齐原则应该是16Byte,但是如果有看过这个结构定义的话,就应该知道,这个结构在定义的时候取消了自动对齐。(定义开始时候先#include然后结束后再#include)
2、信息头(BITMAPINFOHEADER)
view plaincopy to clipboardprint?
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;// 本结构所占用字节数
LONG biWidth;// 位图的宽度,以像素为单位
LONG biHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount; // 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONG biXPelsPerMeter;// 位图水平分辨率,每米像素数
LONG biYPelsPerMeter;// 位图垂直分辨率,每米像素数
DWORD biClrUsed; // 位图实际使用的颜色表中的颜色数
DWORD biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;// 本结构所占用字节数
LONG biWidth;// 位图的宽度,以像素为单位
LONG biHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount; // 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONG biXPelsPerMeter;// 位图水平分辨率,每米像素数
LONG biYPelsPerMeter;// 位图垂直分辨率,每米像素数
DWORD biClrUsed; // 位图实际使用的颜色表中的颜色数
DWORD biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
BITMAPINFOHEADER结构中,结构大小(biSize)、位图宽度(biWidth)、高度(biHeight)、位图色深(biBitCount)、压缩类型(biCompression)、位图大小(biSizeImage)都需要设置正确。
这里,计算数据区文件大小的时候感觉需要注意的。位图是按像素点来保存的,而且一般来说,数据记录顺序是在扫描行内是从左到右,扫描行之间是从下到上,即数据区是从下往上存的,保存在数据区最前部的是最后一行的像素颜色数据,而在最后的是第一行像素颜色值。根据规定,每行数据要4字节对齐,即不是4字节倍数的要补足四字节。每行数据量可以根据如下公式:
DWORD DataSizePerLine = (biWidth * biBitCount + 8 * biBitCount - 1) / (8 * biBitCount); //每行实际数据量的大小
DataSizePerLine = DataSizeLine % 4 ? (DataSizeLine / 4 * 4 + 4) : DataSieLine; //4字节对齐
位图数据区总数据量为:
DWORD DataSize = DataSizeLine * biHeight;
3、调色板结构(RGBQUAD)
view plaincopy to clipboardprint?
typedef struct tagRGBQUAD {
BYTE rgbBlue; // 蓝色的亮度(值范围为0-255)
BYTE rgbGreen; // 绿色的亮度(值范围为0-255)
BYTE rgbRed; // 红色的亮度(值范围为0-255)
BYTE rgbReserved; // 保留,必须为0
} RGBQUAD;
typedef struct tagRGBQUAD {
BYTE rgbBlue; // 蓝色的亮度(值范围为0-255)
BYTE rgbGreen; // 绿色的亮度(值范围为0-255)
BYTE rgbRed; // 红色的亮度(值范围为0-255)
BYTE rgbReserved; // 保留,必须为0
} RGBQUAD;
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。
双色(biBitCount=1)、16色(biBitCount=4)、256色(biBitCount=8)使用的是调色板的颜色,数据区使用的是调色板的索引值。当为真彩色以上时(即biBitcount >= 24),位图是不用调色板的。在真彩色中都是直接使用位图数据来保存真实的颜色值,而不使用调色板的索引值。
这里用双色的举个例子。因为是双色的,所以有两个调色板项(2^1)。即RGBQUAD rgbquad[2];定义两种颜色。如果是16色(2^4)那么就有16项,即rgbquad[16];
4、位图数据BMPDATA
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
数据区域最主要的还是填充位置和值。8bit色深及以下的是使用调色板的索引值。所以当biBitCount=1时,数据区的值就只有2种,即调色板的下标。
而当biBitCount=24时候,保存的便是RGB的颜色值了,3种颜色,每种颜色各占一个字节。
位图数据区还有一个需要注意的就是上面所说的像素位置问题:数据记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。这个问题解决了,那么就可以自由填充颜色了。
阅读(886) | 评论(0) | 转发(0) |