BMP文件结构解析

一、BMP文件结构

BMP文件组成
BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。 
BMP文件头
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。 
其结构定义如下:
typedef  struct  tagBITMAPFILEHEADER
{
WORDbfType;  //  位图文件的类型,必须为BM
DWORD  bfSize;  //  位图文件的大小,以字节为单位 
WORDbfReserved1;  //  位图文件保留字,必须为0
WORDbfReserved2;  //  位图文件保留字,必须为0
DWORD  bfOffBits;  //  位图数据的起始位置,以相对于位图
//  文件头的偏移量表示,以字节为单位
}  BITMAPFILEHEADER;


3.  位图信息头


BMP位图信息头数据用于说明位图的尺寸等信息。
typedef  struct  tagBITMAPINFOHEADER{
DWORD  biSize;  //  本结构所占用字节数
LONGbiWidth;  //  位图的宽度,以像素为单位
LONGbiHeight;  //  位图的高度,以像素为单位
WORD  biPlanes;  //  目标设备的级别,必须为1
WORD  biBitCount//  每个像素所需的位数,必须是1(双色),
//  4(16色),8(256色)或24(真彩色)之一
DWORD  biCompression;  //  位图压缩类型,必须是  0(不压缩),
//  1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD  biSizeImage;  //  位图的大小,以字节为单位
LONGbiXPelsPerMeter;  //  位图水平分辨率,每米像素数
LONGbiYPelsPerMeter;  //  位图垂直分辨率,每米像素数
DWORD  biClrUsed;//  位图实际使用的颜色表中的颜色数
DWORD  biClrImportant;//  位图显示过程中重要的颜色数
}  BITMAPINFOHEADER;


4.  颜色表

  颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
typedef  struct  tagRGBQUAD  {
BYTErgbBlue;//  蓝色的亮度(值范围为0-255)
BYTErgbGreen;  //  绿色的亮度(值范围为0-255)
BYTErgbRed;  //  红色的亮度(值范围为0-255)
BYTErgbReserved;//  保留,必须为0
}  RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef  struct  tagBITMAPINFO  {
BITMAPINFOHEADER  bmiHeader;  //  位图信息头
RGBQUAD  bmiColors[1];  //  颜色表
}  BITMAPINFO;


5.  位图数据
  位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是
4的倍数(即以long为单位),不足的以0填充,
一个扫描行所占的字节数计算方法:
DataSizePerLine=  (biWidth*  biBitCount+31)/8; 
//  一个扫描行所占的字节数
DataSizePerLine=  DataSizePerLine/4*4;  //  字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize=  DataSizePerLine*  biHeight;


二、BMP位图一般显示方法

1.  申请内存空间用于存放位图文件
  GlobalAlloc(GHND,FileLength);

2.  位图文件读入所申请内存空间中
    LoadFileToMemory(  mpBitsSrc,mFileName);

3.  在OnPaint等函数中用创建显示用位图
  用CreateDIBitmap()创建显示用位图,用CreateCompatibleDC()创建兼容DC,
  用SelectBitmap()选择显示位图。

4.  用BitBlt或StretchBlt等函数显示位图

5.  用DeleteObject()删除所创建的位图

  以上方法的缺点是:  1)显示速度慢;  2)  内存占用大;  3)  位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决);  4)  在低颜色位数的设备上(如256显示模式)显示高颜色位数的图形(如真彩色)图形失真严重。

三、BMP位图缩放显示
    用DrawDib视频函数来显示位图,内存占用少,速度快,而且还可以对图形进行淡化(Dithering)处理。淡化处理是一种图形算法,可以用来在一个支持比图像所用颜色要少的设备上显示彩色图像。BMP位图显示方法如下:

1.  打开视频函数DrawDibOpen(),一般放在在构造函数中

2.  申请内存空间用于存放位图文件
  GlobalAlloc(GHND,FileLength);

3.  位图文件读入所申请内存空间中---- 
  LoadFileToMemory(  mpBitsSrc,mFileName);

4.  在OnPaint等函数中用DrawDibRealize(),DrawDibDraw()显示位图

5.  关闭视频函数DrawDibClose(),一般放在在析构函数中

  以上方法的优点是:  1)显示速度快;  2)  内存占用少;  3)  缩放显示时图形失真小,4)  在低颜色位数的设备上显示高颜色位数的图形图形时失真小;  5)  通过直接处理位图数据,可以制作简单动画。

四、CViewBimap类编程要点

1.  在CViewBimap类中添加视频函数等成员

HDRAWDIB  m_hDrawDib;  //  视频函数
HANDLEmhBitsSrc;  //  位图文件句柄(内存)
LPSTR  mpBitsSrc;  //  位图文件地址(内存)
BITMAPINFOHEADER  *mpBitmapInfo;  //  位图信息头

2.  在CViewBimap类构造函数中添加打开视频函数
  m_hDrawDib=  DrawDibOpen();

3.  在CViewBimap类析构函数中添加关闭视频函数

if(  m_hDrawDib  !=  NULL)
{
DrawDibClose(  m_hDrawDib);
m_hDrawDib  =  NULL;
}

4.  在CViewBimap类图形显示函数OnPaint中添加GraphicDraw()
voidCViewBitmap::OnPaint()
{
CPaintDC  dc(this);  //  device  context  for  painting
GraphicDraw(  );
}

voidCViewBitmap::GraphicDraw(  void  )
{
CClientDC  dc(this);  //  device  context  for  painting
BITMAPFILEHEADER  *pBitmapFileHeader;
ULONG  bfoffBits=  0;
CPoint  Wid;

//  图形文件名有效  (=0  BMP)
if(  mBitmapFileType  <  ID_BITMAP_BMP  )  return;

//  图形文件名有效  (=0  BMP)
//  准备显示真彩位图
pBitmapFileHeader=  (BITMAPFILEHEADER  *)  mpBitsSrc;
bfoffBits=  pBitmapFileHeader-> bfOffBits;

//  使用普通函数显示位图

if(  m_hDrawDib  ==  NULL  ||  mDispMethod  ==  0)
{
HBITMAP  hBitmap=::CreateDIBitmap(dc.m_hDC,
mpBitmapInfo,  CBM_INIT,  mpBitsSrc+bfoffBits,
(LPBITMAPINFO)  mpBitmapInfo,DIB_RGB_COLORS); 
//  建立位图
HDC  hMemDC=::CreateCompatibleDC(dc.m_hDC);//  建立内存
HBITMAP  hBitmapOld=  SelectBitmap(hMemDC,  hBitmap);  //  选择对象
//  成员CRect  mDispR用于指示图形显示区域的大小.
//  成员CPoint  mPos用于指示图形显示起始位置坐标.
if(  mPos.x  >  (mpBitmapInfo-  > biWidth  -  mDispR.Width()  ))
mPos.x=  mpBitmapInfo-> biWidth  -  mDispR.Width()  ;
if(  mPos.y  >  (mpBitmapInfo-  > biHeight-  mDispR.Height()))
mPos.y=  mpBitmapInfo-  > biHeight-  mDispR.Height();
if(  mPos.x  <  0  )  mPos.x=  0;
if(  mPos.y  <  0  )  mPos.y=  0;

if(  mFullViewTog  ==  0)
{
//  显示真彩位图
::BitBlt(dc.m_hDC,0,0,  mDispR.Width(),  mDispR.Height(),
hMemDC,mPos.x,mPos.y,  SRCCOPY);
}  else  {
::StretchBlt(dc.m_hDC,0,0,  mDispR.Width(),  mDispR.Height(),
hMemDC,0,0,  mpBitmapInfo-  > biWidth,  mpBitmapInfo-
> biHeight,  SRCCOPY);
}
//  结束显示真彩位图
::DeleteObject(SelectObject(hMemDC,hBitmapOld)); 
//  删  除  位  图
}  else  {

//  使用视频函数显示位图

if(  mPos.x  >  (mpBitmapInfo- 

你可能感兴趣的:(BMP文件结构解析)