虽然现在网上已经有很多位图读取、保存的文章,很多写的都很详细,提供的源代码功能也很强大,但是我仍然要自己重写一个位图加载程序。主要是因为这些大牛们的文章写的太深奥了,代码功能太强大了,以至于像我这样的菜鸟读不懂。所以,我要力求简洁。省略掉一些细节,比方说调色板。为了能够方便容易操作,我的程序只支持24位以上的位图文件加载。
首先,了解下位图文件的结构。24位以上的位图文件包含3个部分:位图文件头(BITMAPFILEHEADER)、位图信息头(BITMAPINFOHEADER)、位图数据。
下面是MSDN中两个信息头的具体定义:
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //图像类型:必须是‘BM’(BM的16进制编码为:0x4d42)
DWORD bfSize; //位图文件大小。
WORD bfReserved1; //保留值。必须为0
WORD bfReserved2; //保留值。必须为0
DWORD bfOffBits; //从文件开头到像素数据的偏移量。
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; //当前结构体的大小。
LONG biWidth; //位图的宽度。单位是像素
LONG biHeight; //位图高度。单位是像素
WORD biPlanes; //位图平面个数。必须是1
WORD biBitCount //位图的位数,也就是位图深度。可以是1、4、8、16、24、32。16位以下的位图文件含有调色板信息。
DWORD biCompression; //压缩方式。位图没有压缩,赋予BI_RGB参数(也就是0)。
DWORD biSizeImage; //位图数据占用的字节数。可以设置为默认值0。
LONG biXPelsPerMeter; //指定目标设备水平分辨率,单位是每米的像素个数。可设置为0
LONG biYPelsPerMeter; //指定目标设备垂直分辨率,同上。
DWORD biClrUsed; //指定本图像实际用到的像素。可设置为0
DWORD biClrImportant; //指定本图像重要的颜色个数。可设置为0,表示所有颜色都重要。
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
位图按行存贮,位图的宽度不等于位图的行字节数。每个像素占用 biBitCount/8 个字节,且每行占用的字节数必须是4字节的整数倍!例如:101*101*24的位图,行占用字节数为:101*3=303,而303%4!=0,所以行占用字节数需修改为304,此时位图数据的实际大小为304*101,上面的biSizeImage就可设置为304*101。
下面是保存位图文件的结构体填充例:
BITMAPFILEHEADER bmheader;
memset(&bmheader,0,sizeof(bmheader));
bmheader.bfType=0x4d42; //图像格式。必须为'BM'格式。
bmheader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); //从文件开头到数据的偏移量
bmheader.bfSize = m_nWidthBytes*m_nHeight + bmheader.bfOffBits;//文件大小
BITMAPINFOHEADER bmInfo;
memset(&bmInfo,0,sizeof(bmInfo));
bmInfo.biSize =