BMP位图的基本概念
一、BMP文件结构   
    
  1.   BMP文件组成     
  BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。     
  2.   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-   >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;   
    
  //   显示真彩位图   
  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方向比例不相同,如要保持相同比例,可在显示程序中加以适当调整即可,读者可自行完成。   
在Windows系统中,以BMP   为扩展名的文件都是DIB文件,保存于磁盘中的DIB文件由4部分所组成:位图文件头、位图信息头、颜色表项和位图图象数据。管理位图文件头、位图信息头、颜色表项的3个结构分别为   BITMAPFILEHEADER,BITMAPINFOHEADER,和RGBQUAD,其中RGBQUAD和BITMAPINFOHEADER结构又可以通过BITMAPINFO来组合。图1-1   展示了DIB文件的数据组织         
    ¬   
  BITMAPFILEHEADER结构的定义如下   
    typedef     struct     tag   BITMAPFILEHEADER{   
  WORD bfType;   
  DWORD bfSize;   
  WORD bfReserved1;   
  WORD bfReserved2;   
  DWORD bfOffBits;   
  }BITMAPFILEHEADER;   
  其中bfType说明文件为一个位图文件,表示位图的ASCII码为BM,其16进制表示为0x4D42。bfSize   表示以字节为单位的文件大小。bfReserved1和bfReserved2一般不采用,其值均为0。BfOffBits表示从位图文件头开始到位图数据段的字节总数,即字节偏移量。   
  BITMAPINFOHEADER结构的定义如下:   
  typedef     struct     tag   BITMAPINFOHEADER{   
                  DWORD biSize;   
                  DWORD biWidth;   
                  DWORD biHeight;   
                  WORD       biPlanes;   
                  WORD       biBitCount;   
      DWORD biCompression;   
  DWORD biSizeImage;   
  DWORD biXPelsPerMeter;   
  DWORD biYPelsPerMeter;   
  DWORD             biClrUsed;   
  DWORD biClrImportant;   
  }BITMAPINFODEADER;           
    其中,biSize   表示该结构的大小。biWidth   表示以像素为单位的位图宽度。biHeight表示相应的高度,biPlanes   表示目标设备的位平面数,置为1。biBitCount   表示位图每个像素的位数,可能为1、4、8、或24。iCompression   表示位图的被压缩类型。若位图未被压缩,则该值为0;若为1,则表示采用RLE(Run   Length   Encoded)8压缩;若位2,则表示采用RLE4压缩。biSizeImage   表示被压缩位图的字节数。biXPelsPerMeter   表示目标设备的水平分辨率,biYPelsPerMeter表示目标设备的垂直分辨率。biClrUsed   表示位图实际使用的颜色数。biClrImportant   指对于显示该位图比较重要的颜色索引的个数,若该值尾0,则表示所有的颜色都是重要的。   
    RGBQUAD结构的定义如下:   
      typedef     struct       tagRGBQUAD{   
  BYTE             rgbBLUE;   
  BYTE             rgbGREEN;   
  BYTE         rbgRED;   
  BYTE             rgbReserved;   
  }RGBQUAD;       
  其中,rgbBLUE、   rgbGREEN、rbgRED分别表示蓝、绿、红分量;rgbReserved的值为0。   
      BITMAPINFO结构把BITMAPINFOHEADER结构和一张颜色表结合在一起,其定义如下:   
      tyepdef       struct       tagBITMAPINFO{     
  BITMAPINFOHEADER         bmiHeader;   
  RGBQUAD                               bmiColors[1];   
  }BITMAPINFO;   
  事实上,只有1、4、8位位图才有颜色表项。24位位图没有颜色表项,位图头信息后紧跟位图数据。   
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号