BMP文件结构解析

来源:互联网 发布:软件搬家 编辑:程序博客网 时间:2024/05/19 13:43

一、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  mPos.x=  0;
if(  mPos.y  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-  > 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  mPos.x=  0;
if(  mPos.y  mPos.y=  0;

//  显示真彩位图
DrawDibRealize(  m_hDrawDib,  dc.GetSafeHdc(),  TRUE);

if(  mFullViewTog  ==  0)
{
Wid.x=  mDispR.Width();
Wid.y=  mDispR.Height();
//  1:1  显示时,  不能大于图形大小
if(  Wid.x  mpBitmapInfo-  > biWidth  )
Wid.x  mpBitmapInfo-  > biWidth;
if(  Wid.y  mpBitmapInfo-  > biHeight)
Wid.y  mpBitmapInfo-  > biHeight;

DrawDibDraw(  m_hDrawDib,  dc.GetSafeHdc()
0,  0,  Wid.x,  Wid.y,
mpBitmapInfo,  (LPVOID)  (mpBitsSrc+bfoffBits),
mPos.x,  mPos.y,  Wid.x,  Wid.y,  DDF_BACKGROUNDPAL);
else  {
DrawDibDraw(  m_hDrawDib,  dc.GetSafeHdc(),
0,  0,  mDispR.Width(),  mDispR.Height(),
mpBitmapInfo,  (LPVOID)  (mpBitsSrc+bfoffBits),
0,  0,  mpBitmapInfo-  > biWidth,  mpBitmapInfo-  > biHeight,
DDF_BACKGROUNDPAL);
}
}
return;
}

五、使用CViewBimap类显示BMP位图
  1.  在Visual  C++5.0中新建一个名称为mymap工程文件,类型为MFC  AppWizard[exe]。在编译运行通过后,在WorkSpace(如被关闭,用Alt_0打开)点击ResourceView,点击Menu左侧的+符号展开Menu条目,双击IDR_MAINFRAME条目,进入菜单资源编辑,在 '“查看(V)”下拉式菜单(英文版为View下拉式菜单)的尾部添加“ViewBitmap”条目,其ID为ID_VIEW_BITMAP。

2.  在Visual  C++5.0中点击下拉式菜单Project-  > Add  To  project- > Files...,将Bitmap0.h和Bitmap0.cpp添加到工程文件中。

3.  在Visual  C++5.0中按Ctrl_W进入MFC  ClassWizard,选择类名称为CMainFrame,ObjectIDs: ID_VIEW_BITMAP,Messages选择Command,然后点击Add  Fucction按钮,然后输入函数名为OnViewBimap。在添加OnViewBimap后,在Member functions:  中点击OnViewBimap条目,点击Edit  Code按钮编辑程序代码。代码如下:

void  CMainFrame::OnViewBitmap()
{
//  TODO:  Add  your  command  handler  code  here
CViewBitmap  *pViewBitmap=  NULL;

pViewBitmap=  new  CViewBitmap(  "BITMAP.BMP ",  this);
pViewBitmap-  > ShowWindow(  TRUE);
}

并在该程序的头部添加#include  "bitmap0.h ",然后编译运行。

4.  找一个大一点的真彩色的BMP位图,将它拷贝到BITMAP.BMP中。

5.  运行时,点击下拉式菜单“查看(V)-  > ViewBitmap”(英文版为View-  ViewBitmap)即可显示BITMAP.BMP位图。

六、CViewBimap类功能说明

1.  在客户区中带有水平和垂直滚动条。在位图大小大于显示客户区时,可以使用滚动条;在位图大小小于显示客户区或全屏显示时,滚动条无效。

2.  在客户区中底部带有状态条。状态条中的第一格为位图信息,第二格为位图显示方法,可以是使用普通函数或使用视频函数。在第二格区域内点击鼠标,可在两者之间接换。第三格为位图显示比例,可以是1;1显示或全屏显示。在第三格区域内点击鼠标,可在两者之间接换。在全屏显示时,如果位图比客户区小,则对位图放大; 如果位图比客户区大,则对位图缩小。

3.  支持文件拖放功能。可以从资源管理器中拖动一个位图文件到客户区,就可以显示该位图。

  程序调试通过后,可以找一个较大的真彩色位图或调整客户区比位图小,在全屏显示方式下,比较使用普通函数与使用视频函数的差别。可以看出,位图放大时两者差别不大,但在位图缩小时,两者差别明显; 使用视频函数时位图失真小,显示速度快。
  还可以从控制面板中将屏幕显示方式从真彩色显示模式切换到256色显示模式,再比较使用普通函数与使用视频函数显示同一个真彩色位图的差别。现在可以体会到使用视频函数的优越性了吧。
  在全屏显示时,位图的xy方向比例不相同,如要保持相同比例,可在显示程序中加以适当调整即可,读者可自行完成。

0 0
原创粉丝点击