| |
Windows下BMP文件的读取及显示 |
|
时间: 2006-02-05 来自:blog |
 |
|
前言
BMP文件的读取及显示是一个难度不大而又相当重要的工作。对BMP文件格式已都有详细介绍,本文主要致力于非压缩BMP读取及显示的实践工作,实现了8位及24位BMP文件的读取,并列出解析过程中所遇到的难点。
bmp文件格式简介:
1、8位的bmp文件主要有以下三部分依次组成:
头部信息.
调色板信息.(按b ,g ,r, reversed 的顺序存放各调色板的颜色信息,共256个)
主数据区(存放各个像素对应的调色板的序号)
2、24位的bmp文件主要有以下两部分依次组成.
头部信息.
主数据区(按b ,g ,r 的顺序存放各像素的信息)
3、相关的结构体:
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; | 3.2、调色板数据结构体: (8位中使用)
typedef struct { BYTE b; BYTE g; BYTE r; BYTE reserved; }paletteRGB; | 3.3、主数据区BGR颜色结构: (24位中使用)
typedef struct { BYTE b; BYTE g; BYTE r; }structRGB; | 解析工作:
1、SetPixel函数
在windows vc编译环境下,使用sdk编程方式,画像素点的函数为:
| COLORREF SetPixel( int x, int y, COLORREF crColor ); | 其中,COLORREF类型的颜色值是这样定义的:
或等价于 crColor=b*65536+g*256+r;
2、Windows环境下扫描行的字节数:
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充.这一点相当重要,忽视这点将导致错误发生.
我的解决方案如下:
externWidth=(mBMFileInfo.bmWidth*mBMFileInfo.bmBitCount)/8;
//计算每行实际的字节宽度
if(externWidth%4!=0)//计算应补足的字节数. externWidth=4-externWidth%4; else externWidth=0; | 核心代码:
这里只列出核以的代码段,详细代码请参阅源码:
//头部解析
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) xternWidth=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+((unsignedlong)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); reak; } }
//显示程序段: 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]); } } | 实验结论:
本文对Windows下非压缩8位及24位位图的解析进行了有益的总结并加以实践,有较强的针对性.可以对需要参考的人士起到一定的帮助作用。
|
|
|
|
|
|
|
|