首页 | 新闻资讯 | 软件应用 | 图形图像 | 网络应用 | 硬件学堂 | 程序开发 | 安全中心 | 素材下载 | 作者专区 | 学院论坛
精选专题 | 精美壁纸 | 专家答疑 | Flash剧场 | Photoshop | 名词解释 | 梦幻桌面 | PS高手进阶 | QQ区 | 图书 | 黑客教材
Flash教程| 卡通制作 | AutoCAD | 3DMax实例 | PS视频教程| 网页制作 | CorelDRAW| Firework | 滤镜与实例 | 全部视频教程
当前位置:eNet硅谷动力 > 学院频道 > VC

在VC中自建操作BMP位图文件类
2004-03-15 12:07 来源:eNet论坛
【简 介】
有编程经验的程序员都知道:要使应用程序的界面美观不可避免的要使用大量位图。现在流行的可视化编程工具对位图的使用提供了很好的支持,被称为三大可视化开发工具的VB、VC、Delphi通过封装位图对象对位图使用提供了很好的支持:VB提供了两个功能很强的对象:PictureBox及Image,通过使用它们,装载、显示位图变得非常容易。Delphi中也提供了一个位图对象:TImage,它的功能与用法与VB中的Image类似。在VC中通过使用设备相关类CDC与GDI对象类CBitmap来完成位图的操作。
    
加入收藏  设为首页

   有编程经验的程序员都知道:要使应用程序的界面美观不可避免的要使用大量位图。现在流行的可视化编程工具对位图的使用提供了很好的支持,被称为三大可视化开发工具的VB、VC、Delphi通过封装位图对象对位图使用提供了很好的支持:VB提供了两个功能很强的对象:PictureBox及Image,通过使用它们,装载、显示位图变得非常容易。Delphi中也提供了一个位图对象:TImage,它的功能与用法与VB中的Image类似。在VC中通过使用设备相关类CDC与GDI对象类CBitmap来完成位图的操作。

  

  然而在VC中使用CBitmap类必须将BMP位图装入资源中,然后通过类 CBitmap的成员函数使用它,在通过CDC类的成员函数操作它。这样做有两点缺陷:将位图装入资源导致可执行文件增大,不利于软件发行;只能使用资源中有限的位图,无法选取其它位图。而且BMP位图文件是以DIB(设备无关位图)方式保存,BMP位图装入资源后被转换为DDB(设备相关位图),类CBitmap就是对一系列DDB操作的API函数进行了封装,使用起来有一定的局限性,不如DIB可以独立于平台特性。

  

  要弥补使用资源位图的两点不足,就必须直接使用BMP位图文件。VC的示例中提供了一种方法读取并显示BMP位图文件,但使用起来相当的麻烦。首先使用API函数GlobalAlloc分配内存并创建HDIB位图句柄,所有操作只能直接读写内存,然后通过StrechDIBits及SetDIBsToDevice函数来显示于屏幕上,操作起来费时费力。

  

  因此笔者通过研究类CBitmap的封装与DIB结构,使用Win32中提供的新函数,建立了一个专用于操作BMP文件的类,而且完全仿照类CBitmap的实现:从类CGdiObject派生,新类的所有接口与类CBitmap 的部分接口完全相同。这样对于习惯使用CBitmap类接口用法的程序员来说两者的接口在使用上没有什么分别。

  

  首先我们先简单介绍一下DIB的结构。DIB位图既可以存在于内存,也可以以文件形式保存在磁盘上(BMP文件)。所有DIB都包含两部分信息:位图信息(BITMAPINFO),包括位图信息头和颜色表;位图数据。对于内存中DIB的只要有上述两部分就行,而对于DIB文件则还要加上位图文件头。

  

  其次,Win32中提供了一个新函数CreateDIBSection,通过它可以创建一个存储DIB位的内存区域,既可以执行相应的GDI操作,又可以直接通过指向DIB位区域的指针方位DIB位区域。这是一个非常有用的函数,通过它我们可以用DIB替代DDB。

  

  在了解了相应的知识后,我们可以自己由类CGdiObject派生一个操作BMP文件的类:CBitmapFile。

  

  在自己编写类时有两点值得注意:

  

  在BitmapFile.h文件中定义类CBitmapFile,首先必须声明类CBitmapFile是从类CGdiObject中公有派生。然后在类中首先使用宏DECLARE_DYNAMIC(CBitmapFile)表明新类的最高父类是类CObject,是符合MFC的类库规范。紧接着宏DECLARE_DYNAMIC的是声明静态函数FromHandle,这两个声明必须放在类定义的最前面。

  在BitmapFile.cpp文件中类的成员函数的实现前加上IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject);表明类CBitmapFile直接派生于类CGdiObject。

  在类CBitmapFile的声明中有三个函数与类Cbitmap中的定义稍有不同:

  

  在类CbitmapFile中LoadBitmap函数的参数是LPCTSTR型,保存的是BMP文件的文件名。

  在类CbitmapFile中CreateBitmap函数的参数中少了参数nPlanes,在函数内部默认为1。

  在类CbitmapFile中CreateBitmapIndirect函数的参数中多了参数lpBits,它指向指定位图DIB位的内存区域。

  在成员函数中最重要的是函数CreateBitmapIndirect和函数LoadBitmap:

  

  在函数CreateBitmapIndirect中使用函数CreateDIBSection创建了一个以兼容DC为基础的HBITMAP句柄,并用继承自类CGdiObject 的函数Attach把它与类CGdiObject的句柄m_hObject关联起来。然后将指定位图的DIB位图数据拷贝到由函数CreateDIBSection创建的DIB位的内存区域。

  在函数LoadBitmap中首先从指定文件名的文件中读取以结构BITMAPFILEHEADER为大小的数据块,然后由文件头标志判断文件是否为BMP位图文件,然后由BITMAPFILEHEADER中bfSize保存的文件大小与文件的真实大小比较文件是否有损坏,再由BITMAPFILEHEADER中bfOffBits与BITMAPFILEHEADER结构大小相减计算出位图信息头和颜色表一共的大小,动态申请一块空间保存位图信息头和颜色表信息,再由BITMAPFILEHEADER中bfSize与bfOffBits相减计算出DIB位图数据的大小,动态申请一块空间保存DIB位图数据,最后调用成员函数CreateBitmapIndirect来创建DIB位图。

  在应用程序的OnPaint()事件中绘制DIB位图的方法与使用类CBitmap时绘制位图的方法完全相同,但有一点要注意的是由于CDC类没有提供返回新类CBitmapFile指针类型的将DIB位图选入内存的SelectObject函数,所以在使用SelectObject时要将返回类型强制转换为CbitmapFile *类型。

  

  至此,关于新类CBitmapFile编写中的一些要点和使用时一些要注意的问题就介绍这么多了。

  

  附源文件

  

  //

  

  // 文件描述:定义类CBitmapFile,此类是用于读取BMP文件,涉及读取、

  

  // 建立及一系列常用的操作。

  

  // 文件名: BitmapFile.h

  

  // 时间: 1999-2-11

  

  // 作者: 贾暾

  

  //

  

  #ifndef _CBITMAPFILE_H_

  

  #define _CBITMAPFILE_H_

  

  class CBitmapFile : public CGdiObject

  

  {

  

  DECLARE_DYNAMIC(CBitmapFile)

  

  public:

  

  static CBitmapFile* PASCAL FromHandle(HBITMAP hBitmap);

  

  // Constructors

  

  CBitmapFile();

  

  BOOL LoadBitmap(LPCTSTR lpszFileName);

  

  BOOL CreateBitmap(int nWidth, int nHeight, UINT nBitCount, const void* lpBits);

  

  BOOL CreateBitmapIndirect(LPBITMAPINFO lpBitmapInfo, const void* lpBits);

  

  // Attributes

  

  operator HBITMAP() const;

  

  int GetBitmap(BITMAP* pBitMap);

  

  protected:

  

  // Attributes

  

  int GetColorNumber(WORD wBitCount);

  

  public:

  

  // Operations

  

  DWORD SetBitmapBits(DWORD dwCount, const void* lpBits);

  

  DWORD GetBitmapBits(DWORD dwCount, LPVOID lpBits);

  

  // Implementation

  

  public:

  

  virtual ~CBitmapFile();

  

  };

  

  #endif

  

  //

  

  // 文件描述:类CBitmapFile内成员函数的实现

  

  // 文件名: BitmapFile.cpp

  

  // 时间: 1999-2-11

  

  // 作者: 贾暾

  

  //

  

  #include "BitmapFile.h"

  

  #include

  

  IMPLEMENT_DYNAMIC(CBitmapFile,CGdiObject);

  

  CBitmapFile* PASCAL CBitmapFile::FromHandle(HBITMAP hBitmap)

  

  {

  

  return (CBitmapFile*) CGdiObject::FromHandle(hBitmap);

  

  }

  

  CBitmapFile::CBitmapFile()

  

  {

  

  }

  

  BOOL CBitmapFile::LoadBitmap(LPCTSTR lpszFileName)

  

  {

  

  CFile file;

  

  if(!file.Open(lpszFileName,CFile::modeRead CFile::shareDenyWrite))

  

  {

  

  MessageBox(NULL,"BMP file open error!","warning",MB_OK);

  

  return FALSE;

  

  }

  

  BITMAPFILEHEADER bfhHeader;

  

  file.Read(amp;bfhHeader,sizeof(BITMAPFILEHEADER));

  

  if(bfhHeader.bfType!=((WORD) ('M'<<8) 'B'))

  

  {

  

  MessageBox(NULL,"The file is not a BMP file!","warning",MB_OK);

  

  return FALSE;

  

  }

  

  if(bfhHeader.bfSize!=file.GetLength())

  

  {

  

  MessageBox(NULL,"The BMP file header error!","warning",MB_OK);

  

  return FALSE;

  

  }

  

  UINT uBmpInfoLen=(UINT) bfhHeader.bfOffBits-sizeof(BITMAPFILEHEADER);

  

  LPBITMAPINFO lpBitmap=(LPBITMAPINFO) new BYTE[uBmpInfoLen];

  

  file.Read((LPVOID) lpBitmap,uBmpInfoLen);

  

  if((* (LPDWORD)(lpBitmap))!=sizeof(BITMAPINFOHEADER))

  

  {

  

  MessageBox(NULL,"The BMP is not Windows 3.0 format!","warning",MB_OK);

  

  return FALSE;

  

  }

  

  DWORD dwBitlen=bfhHeader.bfSize - bfhHeader.bfOffBits;

  

  LPVOID lpBits=new BYTE[dwBitlen];

  

  file.ReadHuge(lpBits,dwBitlen);

  

  file.Close();

  

  BOOL bSuccess=CreateBitmapIndirect(lpBitmap, lpBits);

  

  delete lpBitmap;

  

  delete lpBits;

  

  if(!bSuccess)

  

  return FALSE;

  

  return TRUE;

  

  }

  

  BOOL CBitmapFile::CreateBitmap(int nWidth, int nHeight, UINT nBitCount,

  

  const void* lpSrcBits)

  

  {

  

  ASSERT(nBitCount==1  nBitCount==4  nBitCount==8

  

    nBitCount==16  nBitCount==24  nBitCount==32);

  

  LPBITMAPINFO lpBitmap;

  

  lpBitmap=(BITMAPINFO*) new BYTE[sizeof(BITMAPINFOHEADER) +

  

  GetColorNumber(nBitCount) * sizeof(RGBQUAD)];

  

  lpBitmap->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

  

  lpBitmap->bmiHeader.biWidth=nWidth;

  

  lpBitmap->bmiHeader.biHeight=nHeight;

  

  lpBitmap->bmiHeader.biBitCount=nBitCount;

  

  lpBitmap->bmiHeader.biPlanes=1;

  

  lpBitmap->bmiHeader.biCompression=BI_RGB;

  

  lpBitmap->bmiHeader.biSizeImage=0;

  

  lpBitmap->bmiHeader.biClrUsed=0;

  

  BOOL bSuccess=CreateBitmapIndirect(lpBitmap, lpSrcBits);

  

  delete lpBitmap;

  

  if(!bSuccess)

  

  return FALSE;

  

  return TRUE;

  

  }

  

  BOOL CBitmapFile::CreateBitmapIndirect(LPBITMAPINFO lpBitmapInfo, const void* lpSrcBits)

  

  {

  

  DeleteObject();

  

  LPVOID lpBits;

  

  CDC *dc=new CDC;

  

  dc->CreateCompatibleDC(NULL);

  

  HBITMAP hBitmap=::CreateDIBSection(dc->m_hDC,lpBitmapInfo,DIB_RGB_COLORS,

  

  amp;lpBits,NULL,0);

  

  ASSERT(hBitmap!=NULL);

  

  delete dc;

  

  Attach(hBitmap);

  

  BITMAP bmp;

  

  GetBitmap(amp;bmp);

  

  DWORD dwCount=(DWORD) bmp.bmWidthBytes * bmp.bmHeight;

  

  if(SetBitmapBits(dwCount,lpSrcBits)!=dwCount)

  

  {

  

  MessageBox(NULL,"DIB build error!","warning",MB_OK);

  

  return FALSE;

  

  }

  

  return TRUE;

  

  }

  

  CBitmapFile::operator HBITMAP() const

  

  {

  

  return (HBITMAP)(this == NULL ? NULL : m_hObject);

  

  }

  

  int CBitmapFile::GetBitmap(BITMAP* pBitMap)

  

  {

  

  ASSERT(m_hObject != NULL);

  

  return ::GetObject(m_hObject, sizeof(BITMAP), pBitMap);

  

  }

  

  int CBitmapFile::GetColorNumber(WORD wBitCount)

  

  {

  

  ASSERT(wBitCount==1  wBitCount==4  wBitCount==8

  

    wBitCount==16  wBitCount==24  wBitCount==32);

  

  switch(wBitCount)

  

  {

  

  case 1:

  

  return 2;

  

  case 4:

  

  return 16;

  

  case 8:

  

  return 256;

  

  default:

  

  return 0;

  

  }

  

  }

  

  DWORD CBitmapFile::SetBitmapBits(DWORD dwCount, const void* lpBits)

  

  {

  

  if(lpBits!=NULL)

  

  {

  

  BITMAP bmp;

  

  GetBitmap(amp;bmp);

  

  memcpy(bmp.bmBits,lpBits,dwCount);

  

  return dwCount;

  

  }

  

  else

  

  return 0;

  

  }

  

  DWORD CBitmapFile::GetBitmapBits(DWORD dwCount, LPVOID lpBits)

  

  {

  

  if(lpBits!=NULL)

  

  {

  

  BITMAP bmp;

  

  GetBitmap(amp;bmp);

  

  memcpy(lpBits,bmp.bmBits,dwCount);

  

  return dwCount;

  

  }

  

  else

  

  return 0;

  

  }

  

  CBitmapFile::~CBitmapFile()

  

  {

  

  CGdiObject::DeleteObject();

  

  }

  
关键字:  
您对这篇文章的看法是:    喜欢 反感 支持 反对 加油 鄙视 学习 打击 佩服 漂亮 路过 发表评论
视频教程】 【专题汇总】 【不懂就问我关闭窗口

360安全卫士 V5.1.1正式版发布!
Photoshop给模特美腿加上质感肤色
了解差距 国外27款创意名片设计赏
认清五种被忽视的黑客攻击方式
QQ音乐播放器2009正式版今天发布!
相关文章
 本栏目最新文章
·VC各类之间的调用函数总结
·VC中特殊字体的实现方法讲解
·VC++中进程与多进程管理的方法
·用VC 6.0实现串行通信的三种方法
·VC++实现回收站的文件存取
 精彩回放
·3DSMAX打造书本翻开效果
·共享上网技巧应用四则
·陪酒女浸泡在酒里的青春
·美女的性感靓丽婚纱设计
·妖冶身姿 死或生3壁纸
·剿灭Win XP下的29个烦恼
·黑客必备 NET命令大全
·用PS制作精致绝伦的红酒
 精彩推荐
 今日软件下载
杀毒软件免费随便用
瑞星全功能安全软件2009 基于“云安全”策略和“智能主动防御”技术开发.
www.rising.com.cn
 往日推荐
·推荐“美图秀秀”就能赚Q币
·五大搜索引擎横向评测
·防御计算机病毒十大步骤

论坛精华
·史上最强最多 photo 
·photoshop完美扣图教 
·网络学院flash教程目 
·Photoshop下载大全 
·PhotoShop实例精选电 
·打包笔刷 附图的~~ 
热点推荐
绘制逼真金蛋
浪漫婚纱照片
Flash视频编程
Ulead GIF教程
热点关注
·Flash CS4 制作经典小游戏
·C语言程序设计视频教程
·PHP+MYSQL开发视频教程
·Flash CS4从入门到精通教程
·服装设计与效果图绘制教程
·21视频之Fireworks8网页制作
·Vray高级实例应用视频教程
·CorelDRAW14入门到高级教程
·Vray高级实例应用视频教程
全国计算机等级考试二级(VB语言)
往日推荐
网站重构设计
鹏哥C#教程
服装设计教程
PS唯美风景
焦点关注