转自:http://blog.csdn.net/EmilMatthew/article/details/591814
Windows下BMP文件的读取及显示
EmilMatthew(EmilMatthew@126.com)
摘要:
实现了Windows下,8位及24位BMP文件的读取及显示.
关键词: bmp文件,文件格式
Parse and show bmp file on windows platform
EmilMatthew(EmilMatthew@126.com)
Abstract:
Parse and show out 8 bits and 24 bits bmp file under windows platform.
Key Words: bmp File, File structure
1前言:
BMP文件的读取及显示是一个难度不大而又相当重要的工作。[1],[2]对BMP文件格式已都有详细介绍,本文主要致力于非压缩BMP读取及显示的实践工作,实现了8位及24位BMP文件的读取,并列出解析过程中所遇到的难点。
2bmp文件格式简介: (详见[1],[2])
2.1 8位的bmp文件主要有以下三部分依次组成:
头部信息.
调色板信息.(按b ,g ,r, reversed 的顺序存放各调色板的颜色信息,共256个)
主数据区(存放各个像素对应的调色板的序号)
2.2 24位的bmp文件主要有以下两部分依次组成.
头部信息.
主数据区(按b ,g ,r 的顺序存放各像素的信息)
2.3相关的结构体:
2.3.1头部信息结构体:
a)位图文件头
typedef struct tagBITMAPFILEHEADER { // bmfh
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
其中的bfType值应该是“BM”(0x4d42),标志该文件是位图文件。bfSize的值是位图文件的大小
b)位图信息头
typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD biSize;
LONG biWidth; //以像素为单位的图像宽度
LONG biHeight;// 以像素为单位的图像长度
WORD biPlanes;
WORD biBitCount;// 每个像素的位数
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
2.3.2调色板数据结构体: (8位中使用)
typedef struct
{
BYTE b;
BYTE g;
BYTE r;
BYTE reserved;
}paletteRGB;
2.3.3 主数据区BGR颜色结构: (24位中使用)
typedef struct
{
BYTE b;
BYTE g;
BYTE r;
}structRGB;
3解析工作:
3.1SetPixel函数
在windows vc编译环境下,使用sdk编程方式,画像素点的函数为:
COLORREF SetPixel( int x, int y, COLORREF crColor );
其中,COLORREF类型的颜色值是这样定义的:
crColor=b<<16+g<<8+r;
或等价于 crColor=b*65536+g*256+r;
3.2 Windows环境下扫描行的字节数:
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充.这一点相当重要,忽视这点将导致错误发生.
我的解决方案如下:
externWidth=(mBMFileInfo.bmWidth*mBMFileInfo.bmBitCount)/8;
//计算每行实际的字节宽度
if(externWidth%4!=0)//计算应补足的字节数.
externWidth=4-externWidth%4;
else
externWidth=0;
3.3 BMP数据矩阵的存放方式:
应注意,在BMP文件中,数据矩阵的存放方式都是按照(对应于原图)行按从下到上,列按从左到右的顺序进行存放。
4核心代码:
这里只列出核以的代码段,详细代码请参阅源码:
//头部解析
void BMParse::showHeadInfo()
{
assertF(mInputFile!=NULL,"in showHeadInfo,mInputFile is null/n");
fread(&mBMFileStr,sizeof(BMPFileStr),1,mInputFile);
fread(&mBMFileInfo,sizeof(BMPFileInfo),1,mInputFile);
//adjusting
mWinBMPFileStr.bfType=mBMFileStr.bfType;
mWinBMPFileStr.bfSize=mBMFileStr.bfSize1+mBMFileStr.bfSize2*65536;
mWinBMPFileStr.reserved1=mBMFileStr.reserved1;
mWinBMPFileStr.reserved2=mBMFileStr.reserved2;
mWinBMPFileStr.bfOffset=mBMFileStr.bfOffset1+mBMFileStr.bfOffset2*65536;
return;
}
//颜色区(8位的带调色板)解析:
void BMParse::parseBMPMatrix()
{
if(mWinBMPFileStr.bfType!=19778)
{
cout<<"This is not a bmp file"<<endl;
return;
}
if(mBMFileInfo.bmCompression!=0)
{
cout<<"File is compressed"<<endl;
return;
}
int i,j;
structRGB tmpRGB;
BYTE tmpData;
int externWidth;
bmpMatrix=(unsigned long**)malloc(sizeof(unsigned long*)*mBMFileInfo.bmHeight);
for(i=0;i<mBMFileInfo.bmHeight;i++)
bmpMatrix[i]=(unsigned long*)malloc(sizeof(unsigned long)*mBMFileInfo.bmWidth);
//bmp file structure in windows,keep %4==0 in row byte num.
externWidth=(mBMFileInfo.bmWidth*mBMFileInfo.bmBitCount)/8;
if(externWidth%4!=0)
externWidth=4-externWidth%4;
else
externWidth=0;
switch(mBMFileInfo.bmBitCount)
{
case 8: paletteArr=(paletteRGB*)malloc(sizeof(paletteRGB)*256);
for(i=0;i<256;i++)
{
fread(&paletteArr[i],sizeof(paletteRGB),1,mInputFile);
}
fseek(mInputFile,1078, SEEK_SET);
for(j=mBMFileInfo.bmHeight-1;j>=0;j--)
{
for(i=0;i<mBMFileInfo.bmWidth;i++)
{
fread(&tmpData,sizeof(BYTE),1,mInputFile);
bmpMatrix[j][i]=((unsigned long)paletteArr[tmpData].b)*65536+((unsigned long)paletteArr[tmpData].g)*256+(unsigned long)paletteArr[tmpData].r;
}
/*补齐位调整*/
for(i=0;i<externWidth;i++)
fread(&tmpData,sizeof(BYTE),1,mInputFile);
}
break;
case 16:
printf("not finished/n");
break;
case 24:
for(j=mBMFileInfo.bmHeight-1;j>=0;j--)
{
for(i=0;i<mBMFileInfo.bmWidth;i++)
{
fread(&tmpRGB,sizeof(structRGB),1,mInputFile);
bmpMatrix[j][i]=((unsigned long)tmpRGB.b)*65536+((unsigned long)tmpRGB.g)*256+(unsigned long)tmpRGB.r;
}
/*补齐位调整*/
for(i=0;i<externWidth;i++)
fread(&tmpData,sizeof(BYTE),1,mInputFile);
}
break;
default: printf("bmBitCount:%d not finished/n",mBMFileInfo.bmBitCount);
break;
}
}
//显示程序段:
void BMParse::showBMP(HDC inHdc)
{
int i,j;
for(j=0;j<mBMFileInfo.bmHeight;j++)
for(i=0;i<mBMFileInfo.bmWidth;i++)
{
SetPixel(inHdc,i,j,bmpMatrix[j][i]);
}
}
5实验结论:
本文对Windows下非压缩8位及24位位图的解析进行了有益的总结并加以实践,有较强的针对性.可以对需要参考的人士起到一定的帮助作用。
参考文献:
[1]http://www.vckbase.com/document/viewdoc/?id=674
[2]http://topic.csdn.net/t/20030819/09/2162276.html
[3]浦滨,C游戏编程,北京希望电子出版社,2002.
[4]朱学芳、智文广,计算机图像处理导论,科学技术文献出版社,2002.
完成日:06/02/04
附录:
1本文最佳浏览定位:
http://www.emilmatthew.zk.cn/EmilPapers/06_08BMParse/index.htm
2测试程序下载:
http://emilmatthew.51.net/EmilPapers/06_08BMParse/code1.rar
3DOC文档下载:
http://emilmatthew.51.net/EmilPapers/06_08BMParse/doc.rar
若直接点击无法下载(或浏览),请将下载(或浏览)的超链接粘接至浏览器地( 推荐MYIE或GREENBORWSER)址栏后按回车.若不出意外,此时应能下载.