Visual C++的CBitmap类的功能是比较弱的,它只能显示出在资源中的图标、位图、光标以及图元文件的内容,而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP、GIF、JPEG等)。如果想要在对话框或其他窗口中显示外部图像文件则只能借助于第三方提供的控件或代码,未免过于繁琐.
   现在,.net引入了一个功能非常强大的新类 ----- CImage.有了CImage类,Visual C++在图像方面的缺憾将一去不复返。CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换。例如通过简单的几句,就可以实现CImage类和CBitmap类实例的:
HBITMAP hBitmap=image.Detach();
CBitmap bmp;
bmp.Attach(hBitmap);
这样一来,就又回归到以前操纵CBitmap的方式了.CImage本身封装了DIB(设备无关位图)的功能,因而能够处理每个位图像素。
它具有下列最酷特性:
  1、AlphaBlend支持像素级的颜色混合,从而实现透明和半透明的效果。
  2、PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中,而且还可能使用位屏蔽操作。
  3、TransparentBlt在目标区域中产生透明图像,SetTransparentColor用来设置某种颜色是透明色。
  4、MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果。
由于CImage在不同的Windows操作系统中其某些性能是不一样的,因此在使用时要特别注意。例如,CImage::PlgBlt和 CImage::MaskBlt只能在 Windows NT 4.0 或更高版本中使用,但不能运行在Windows 95/98 应用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000运行程序还必须将stdafx.h文件中的WINVER和_WIN32_WINNT的预定义修改成0x0500才能正常使用。
使用CImage的一般方法

  使用CImage的一般方法是这样的过程:

  (1) 打开应用程序的stdafx.h文件添加CImage类的包含文件:

#include <atlimage.h>

  (2) 定义一个CImage类对象,然后调用CImage::Load方法装载一个外部图像文件。

  (3) 调用CImage::Draw方法绘制图像。Draw方法具有如下定义:
 
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight, int xSrc, int ySrc,
int nSrcWidth, int nSrcHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc );
BOOL Draw( HDC hDestDC, int xDest, int yDest );
BOOL Draw( HDC hDestDC, const POINT& pointDest );
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest );

  其中,hDestDC用来指定绘制的目标设备环境句柄,(xDest, yDest)和pointDest用来指定图像显示的位置,这个位置和源图像的左上角点相对应。nDestWidth和nDestHeight分别指定图像要显示的高度和宽度,xSrc、ySrc、nSrcWidth和nSrcHeight用来指定要显示的源图像的某个部分所在的位置和大小。 rectDest和rectSrc分别用来指定目标设备环境上和源图像所要显示的某个部分的位置和大小。

  需要说明的是,Draw方法综合了StretchBlt、TransparentBlt和AlphaBlend函数的功能。默认时,Draw的功能和 StretchBlt相同。但当图像含有透明色或Alpha通道时,它的功能又和TransparentBlt、AlphaBlend相同。因此,在一般情况下,我们都应该尽量调用CImage::Draw方法来绘制图像。

  例如,下面的示例Ex_Image是实现这样的功能:当选择"文件"ò"打开"菜单命令后,弹出一个文件打开对话框。当选定一个图像文件后,就会在窗口客户区中显示该图像文件内容。这个示例的具体步骤如下:

  (1) 创建一个默认的单文档程序项目Ex_Image。

  (2) 打开stdafx.h文件中添加CImage类的包含文件atlimage.h。

  (3) 在CEx_ImageView类添加ID_FILE_OPEN的COMMAND事件映射程序,并添加下列代码:
 
void CEx_ImageView::OnFileOpen()
{
 CString strFilter;
 CSimpleArray<GUID> aguidFileTypes;
 HRESULT hResult;

 // 获取CImage支持的图像文件的过滤字符串
 hResult = m_Image.GetExporterFilterString(strFilter,aguidFileTypes,
_T( "All Image Files") );
 if (FAILED(hResult)) {
  MessageBox("GetExporterFilter调用失败!");
  return;
 }
 CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter);
 if(IDOK != dlg.DoModal())
  return;

 m_Image.Destroy();
 // 将外部图像文件装载到CImage对象中
 hResult = m_Image.Load(dlg.GetFileName());
 if (FAILED(hResult)) {
  MessageBox("调用图像文件失败!");
  return;
 }

 // 设置主窗口标题栏内容
 CString str;
 str.LoadString(AFX_IDS_APP_TITLE);
 AfxGetMainWnd()->SetWindowText(str + " - " +dlg.GetFileName());

 Invalidate(); // 强制调用OnDraw
}

  (4) 定位到CEx_ImageView::OnDraw函数处,添加下列代码:
 
void CEx_ImageView::OnDraw(CDC* pDC)
{
 CEx_ImageDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 if (!m_Image.IsNull()) {
  m_Image.Draw(pDC->m_hDC,0,0);
 }
}

  (5) 打开Ex_ImageView.h文件,添加一个公共的成员数据m_Image:
 
public:
CImage m_Image;

  (6) 编译并运行。单击"打开"工具按钮,在弹出的对话框中指定一个图像文件后,单击"打开"按钮,其结果如图7.21所示。

将图片用其它格式保存

  CImage::Save方法能将一个图像文件按另一种格式来保存,它的原型如下:

HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL);
  其中,pszFileName用来指定一个文件名,guidFileType用来指定要保存的图像文件格式,当为GUID_NULL时,其文件格式由文件的扩展名来决定,这也是该函数的默认值。它还可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。

  例如,下面的过程是在Ex_Image示例基础上进行的,我们在CEx_ImageView类添加ID_FILE_SAVE_AS的COMMAND事件映射程序,并添加下列代码:

void CEx_ImageView::OnFileSaveAs()
{
 if (m_Image.IsNull()) {
  MessageBox("你还没有打开一个要保存的图像文件!");
  return;
 }

 CString strFilter;
 strFilter = "位图文件|*.bmp|JPEG 图像文件|*.jpg| \
GIF 图像文件|*.gif|PNG 图像文件|*.png||";
 CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
 if ( IDOK != dlg.DoModal())
  return;

 // 如果用户没有指定文件扩展名,则为其添加一个
 CString strFileName;
 CString strExtension;

 strFileName = dlg.m_ofn.lpstrFile;
 if (dlg.m_ofn.nFileExtension == 0)
 {
  switch (dlg.m_ofn.nFilterIndex)
  {
   case 1:
    strExtension = "bmp"; break;
   case 2:
    strExtension = "jpg"; break;
   case 3:
    strExtension = "gif"; break;
   case 4:
    strExtension = "png"; break;
   default:
    break;
  }
  strFileName = strFileName + '.' + strExtension;
 }

 // 图像保存
 HRESULT hResult = m_Image.Save(strFileName);
 if (FAILED(hResult))
  MessageBox("保存图像文件失败!");
将图片用其它格式保存

  CImage::Save方法能将一个图像文件按另一种格式来保存,它的原型如下:

HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL);
  其中,pszFileName用来指定一个文件名,guidFileType用来指定要保存的图像文件格式,当为GUID_NULL时,其文件格式由文件的扩展名来决定,这也是该函数的默认值。它还可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。

  例如,下面的过程是在Ex_Image示例基础上进行的,我们在CEx_ImageView类添加ID_FILE_SAVE_AS的COMMAND事件映射程序,并添加下列代码:

void CEx_ImageView::OnFileSaveAs()
{
 if (m_Image.IsNull()) {
  MessageBox("你还没有打开一个要保存的图像文件!");
  return;
 }

 CString strFilter;
 strFilter = "位图文件|*.bmp|JPEG 图像文件|*.jpg| \
GIF 图像文件|*.gif|PNG 图像文件|*.png||";
 CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
 if ( IDOK != dlg.DoModal())
  return;

 // 如果用户没有指定文件扩展名,则为其添加一个
 CString strFileName;
 CString strExtension;

 strFileName = dlg.m_ofn.lpstrFile;
 if (dlg.m_ofn.nFileExtension == 0)
 {
  switch (dlg.m_ofn.nFilterIndex)
  {
   case 1:
    strExtension = "bmp"; break;
   case 2:
    strExtension = "jpg"; break;
   case 3:
    strExtension = "gif"; break;
   case 4:
    strExtension = "png"; break;
   default:
    break;
  }
  strFileName = strFileName + '.' + strExtension;
 }

 // 图像保存
 HRESULT hResult = m_Image.Save(strFileName);
 if (FAILED(hResult))
  MessageBox("保存图像文件失败!");
变成黑白图片

  由于许多图像文件使用颜色表来发挥显示设备的色彩显示能力,因而将一张彩色图片变成黑色图片时需要调用CImage::IsIndexed来判断是否使用颜色表,若是则修改颜色表,否则直接将像素进行颜色设置。例如下面的代码:

void CEx_ImageView::MakeBlackAndwhite(CImage* image)
{
 if (image->IsNull()) return;

 if (!image->IsIndexed()) {
  // 直接修改像素颜色
  COLORREF pixel;
  int maxY = image->GetHeight(), maxX = image->GetWidth();
  byte r,g,b,avg;
  for (int x=0; x<maxX; x++) {
   for (int y=0; y<maxY; y++) {
    pixel = image->GetPixel(x,y);
    r = GetRValue(pixel);
    g = GetGValue(pixel);
    b = GetBValue(pixel);
    avg = (int)((r + g + b)/3);
    image->SetPixelRGB(x,y,avg,avg,avg);
   }
  }
 } else {
  // 获取并修改颜色表
  int MaxColors = image->GetMaxColorTableEntries();
  RGBQUAD* ColorTable;
  ColorTable = new RGBQUAD[MaxColors];
  image->GetColorTable(0,MaxColors,ColorTable);
  for (int i=0; i<MaxColors; i++)
  {
   int avg = (ColorTable[i].rgbBlue + ColorTable[i].rgbGreen + ColorTable[i].rgbRed)/3;
   ColorTable[i].rgbBlue = avg;
   ColorTable[i].rgbGreen = avg;
   ColorTable[i].rgbRed = avg;
  }
  image->SetColorTable(0,MaxColors,ColorTable);
  delete(ColorTable);
 }
}
  至此,我们介绍了GDI+和CImage的一般使用方法和技巧。当然,它们本身还有许多更深入的方法,由于篇幅所限,这里不再一一讨论。

一个比CBitmap更优秀的类 -- CImage类的更多相关文章

  1. 介绍一个强大的画图类 CImage(转)

    我们知道,Visual C++的CBitmap类和静态图片控件的功能是比较弱的,它只能显示出在资源中的图标.位图.光标以及图元文件的内容,而不像VB中的Image控件可以显示出绝大多数的外部图像文件( ...

  2. CImage类的介绍与使用

    CImage类的介绍与使用 程序代码下载处:http://download.csdn.net/source/2098910 下载处:http://hi.baidu.com/wangleitongxin ...

  3. GDI 总结三: CImage类使用

    前言          CImage类是基于GDI+的.可是这里为什么要讲归于GDI? 主要是基于这种考虑: 在GDI+环境中,我们能够直接使用GDI+ ,没多少必要再使用CImage类 可是,假设再 ...

  4. CImage类

    CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素.这里介绍GDI+和CImage的一般使用方法和技巧. TAG: GDI  CImage  后处理   我们知道,Vi ...

  5. CImage类的使用介绍!

    链接参考:http://www.cnblogs.com/juncheng/articles/1600730.html CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG.GIF. ...

  6. 【VS开发】GDI+ 用CImage类来显示PNG、JPG等图片

    系统环境:Windows 7 软件环境:Visual Studio 2008 SP1 本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也 ...

  7. 供CImage类显示的半透明PNG文件处理方法

    原文链接: http://blog.sina.com.cn/s/blog_4070692f010003gy.html   前补:没想到这个帖子好像挺多人看哪……看来大家都被这个png郁闷的够呛.显示p ...

  8. c++ MFC图像处理CImage类常用操作代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html MFC图像处理CImage类常用操作 CImage类头文件为#inclu ...

  9. 用CImage类来显示PNG、JPG等图片

    系统环境:Windows 7软件环境:Visual Studio 2008 SP1本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也是A ...

随机推荐

  1. Blender如何设置中文界面

    废话不多说,上图 bingo!!

  2. Java实现 蓝桥杯算法提高 求最大值

    算法提高 求最大值 时间限制:1.0s 内存限制:256.0MB 问题描述 给n个有序整数对ai bi,你需要选择一些整数对 使得所有你选定的数的ai+bi的和最大.并且要求你选定的数对的ai之和非负 ...

  3. Java实现第九届蓝桥杯复数幂

    复数幂 题目描述 设i为虚数单位.对于任意正整数n,(2+3i)^n 的实部和虚部都是整数. 求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示. ...

  4. java实现第五届蓝桥杯排列序数

    排列序数 如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号: abcd 0 abdc 1 acbd 2 acdb 3 adbc 4 adcb 5 bac ...

  5. 09 . Nginx配置LNMP和LNMT架构

    安装LNMP架构 环境清单 list CentOS7.3 proxysql-2.0.12-1-centos7.x86_64.rpm mysql-5.7.23-1.el7.x86_64.rpm-bund ...

  6. Spring-AOP之工作实践(二)

    案例二.前端页面权限控制 对controllor控制器中的某写方法进行增强,如实现页面的按钮权限控制. /** * 保存session的容器 */ public class SessionContex ...

  7. 源码分析 | 手写mybait-spring核心功能(干货好文一次学会工厂bean、类代理、bean注册的使用)

    作者:小傅哥 博客:https://bugstack.cn - 汇总系列原创专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言介绍 一个知识点的学习过程基本分为:运行helloworld ...

  8. PyQt5 对话框示例

    import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * class Example(QMainWindow): def _ ...

  9. (六)logback.xml 配置详解

    原文链接:https://www.cnblogs.com/taiyonghai/p/9290641.html,https://blog.csdn.net/A615883576/article/deta ...

  10. 通信中的错误代码 (repost from https://blog.csdn.net/zzhuan_1/article/details/80066716)

    • 100 - 继续.• 101 - 切换协议.• 110 重新启动标记答复.• 120 服务已就绪,在 nnn 分钟后开始.• 125 数据连接已打开,正在开始传输.• 150 文件状态正常,准备打 ...