BMP位图文件结构及VC操作

来源:互联网 发布:软件界面设计欣赏 编辑:程序博客网 时间:2024/04/30 07:09
BMP位图文件结构及VC操作    
  朱永辉        
  ----   用普通方法显示BMP位图,占内存大,速度慢,在图形缩小时,失真严重,在低颜色位数的设备   上显示高颜色位数的图形图形时失真大。本文采用视频函数显示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按钮,然后输入函数名为OnViewBima   p。在添加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方向比例不相同,如要保持相同比例,可在显示程序中加以适当调整   即可,读者可自行完成。     
    
        
 
原创粉丝点击