前言

         CImage类是基于GDI+的。可是这里为什么要讲归于GDI?

主要是基于这种考虑: 在GDI+环境中,我们能够直接使用GDI+ ,没多少必要再使用CImage类

可是,假设再GDI环境中,我们要想使用GDI+,有点麻烦。还得增加头文件。增加启动GDI+的代码和关闭GDI+的代码,显得太罗嗦了。GDI  的CBitmap 处理功能又有局限,仅仅能处理BMP格式的图片。 怎么办?这时。我们便可使用CImage类,由于这个类本身封装了GDI+得使用环境,所以无需我们手动设置,简化了我们的操作。  同一时候。又能够利用GDI+中强大的图片处理功能,及能够简便的与CBitmap对象进行转换
,大慷慨便了在GDI环境下。进行各种图片处理工作 。

事实上,将其称作 GDI/ GDI+ 混合编程,这样才更确切些。

为什么引入CImage类?

CBitmap 类仅仅能处理BMP格式的图片,很受限。

而CImage能够处理JPGE GIF BMP PNG多种格式图片,扩展了图片处理功能 且能与CBitmap 进行转换( 由于所加载的位图句柄都是HBITMAP,所以可相互转换),因此引入CImage类进行图像处理

     CImage provides enhanced bitmap support, including the ability to load and save images in JPEG, GIF, BMP, and Portable Network Graphics (PNG) formats

CImage类介绍

    

CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,并且这些文件格式能够相互转换。

CImage是VC.NET中定义的一种MFC/ATL共享类,也是ATL的一种工具类,它提供增强型的(DDB和DIB)位图支持。能够装入、显示、转换和保存多种格式的图像文件,包含BMP、GIF、JPG、PNG、TIF等。CImage是一个独立的类。没有基类。

(CImage类是基于GDI+的,从VC.NET起引进。VC 6.0中没有。)

ATL(Active Template Library,活动模板库)是一套基于模板的 C++ 类,用以简化小而快的 COM 对象的编写。

为了在MFC程序中使用CImage类,必须包括ATL的图像头文件atlimage.h:(在VS08 SP1中不用包括)

#include <atlimage.h>

1  载入位图文件

  1. // CImage可载入的图片文件有JPG,BMP,TIF.PNG等格式  而CBitmap仅仅能载入BMP图片文件
  2. if(!PathFileExists(imgFilePath))
  3. return NULL;
  4. CImage nImage;
  5. nImage.Load(imgFilePath);
  6. return nImage.Detach();  //返回HBITMAP    可用CBitmap 处理 也可用CImage处理

2 与CBitmap转换

  1. CImage nImage;
  2. nImage.Load(imgFilePath);
  3. HBITMAP hBitmap=nImage.Detach(); // 获得位图句柄 用以转换
  4. // 转换方式一:
  5. CBitmap bmp;
  6. bmp.DeleteObject();
  7. bmp.Attach(hBitmap); //  转换为CBitmap对象
  8. // 转换方式二:
  9. CBitmap *pBitmap=CBitmap::FromHandle(nImage.m_hBitmap);

3 获得CImage对象的cdc

  1. CDC *pDC=CDC::FromHandle(nImage.GetDC());
  2. // Use pDC here
  3. nImage.ReleaseDC();

4 显示位图

思路: 将CImage对象 绘制在相应的DC中

所使用的函数 BitBlt   StretchBlt  Draw等

以Draw举例:

  1. BOOL Draw(
  2. HDC hDestDC,
  3. int xDest,
  4. int yDest,
  5. int nDestWidth,
  6. int nDestHeight,
  7. int xSrc,
  8. int ySrc,
  9. int nSrcWidth,
  10. int nSrcHeight
  11. ) const throw( );
  12. BOOL Draw(
  13. HDC hDestDC,
  14. const RECT& rectDest,
  15. const RECT& rectSrc
  16. ) const throw( );
  17. BOOL Draw(
  18. HDC hDestDC,
  19. int xDest,
  20. int yDest
  21. ) const throw( );
  22. BOOL Draw(
  23. HDC hDestDC,
  24. const POINT& pointDest
  25. ) const throw( );
  26. BOOL Draw(
  27. HDC hDestDC,
  28. int xDest,
  29. int yDest,
  30. int nDestWidth,
  31. int nDestHeight
  32. ) const throw( );
  33. BOOL Draw(
  34. HDC hDestDC,
  35. const RECT& rectDest
  36. ) const throw( );

Draw performs the same operation as StretchBlt, unless the image contains a transparent color or alpha
channel. In that case,Draw performs the same operation as eitherTransparentBlt orAlphaBlend as
required.

For versions of Draw that do not specify a source rectangle, the entire source image is the default. For the version ofDraw that does not specify a size for the destination rectangle, the size of the source image is the default
and no stretching or shrinking occurs.

EXAMPLE 1:

  1. CImage img;
  2. img.Load("1.jpg");
  3. if (!img.IsNull())
  4. {
  5. img.Draw(pDC->m_hDC,CRect(0,0,100,100));
  6. }

EXAMPLE 2: 画在还有一个位图中

  1. CImage img;
  2. img.Load(filePath);
  3. // 获得CImage对象的 CDC
  4. HDC hDC=img.GetDC();
  5. CDC *pDC=CDC::FromHandle(hDC);
  6. CBitmap bmp;// 仅仅是创建了位图对象,但还没有将位图对象与位图资源联系起来
  7. bmp.CreateCompatibleBitmap(pDC,nWidth,nHeight); // 创建新的位图资源
  8. CDC memDC;
  9. memDC.CreateCompatibleDC(pDC);
  10. CBitmap *pOld=memDC.SelectObject(&bmp);
  11. // 将img图像绘制到bmp中
  12. ::SetStretchBltMode(memDC.m_hDC,HALFTONE);
  13. ::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);
  14. img.StretchBlt(memDC.m_hDC,CRect(0,0,nWidth,nHeight)/*DestRect*/,CRect(0,0,nWidth,nHeight)/*SourceRect*/,SRCCOPY);
  15. HBITMAP hBitmap=(HBITMAP)memDC.SelectObject(pOld->m_hObject); // 获得新创建的位图资源句柄
  16. img.ReleaseDC();

5 将位图资源与对象进行分离

  1. inline HBITMAP CImage::Detach() throw()
  2. {
  3. HBITMAP hBitmap;
  4. ATLASSUME( m_hBitmap != NULL );
  5. ATLASSUME( m_hDC == NULL );
  6. hBitmap = m_hBitmap;
  7. m_hBitmap = NULL;
  8. m_pBits = NULL;
  9. m_nWidth = 0;
  10. m_nHeight = 0;
  11. m_nBPP = 0;
  12. m_nPitch = 0;
  13. m_iTransparentColor = -1;
  14. m_bHasAlphaChannel = false;
  15. m_bIsDIBSection = false;
  16. return( hBitmap );
  17. }

6 释放资源

CBitmap 使用DeleteObject()来主动释放掉位图资源

CImage   没有DeleteObject()函数 。而是用Destroy()函数来主动释放位图资源

  1. inline void CImage::Destroy() throw()
  2. {
  3. HBITMAP hBitmap;
  4. if( m_hBitmap != NULL )
  5. {
  6. hBitmap = Detach();
  7. ::DeleteObject( hBitmap );  //释放位图资源
  8. }
  9. }

CBitmap 析构时,会自己主动释放掉所占用的位图资源

CImage 析构时。也会自己主动释放掉所占用的位图资源

  1. inline CImage::~CImage() throw()
  2. {
  3. Destroy(); //释放掉所占用的位图资源
  4. s_initGDIPlus.DecreaseCImageCount();
  5. }

7 读写图像数据

主要用到3个函数 :

1 )GetBits() 获得数据区的指针

Retrieves a pointer to the actual bit values of a given pixel in a bitmap.

 
void* GetBits( ) throw( );
 
  1. inline void* CImage::GetBits() throw()
  2. {
  3. ATLASSUME( m_hBitmap != NULL );
  4. ATLASSERT( IsDIBSection() );
  5. return( m_pBits );
  6. }

A pointer to the bitmap buffer. If the bitmap is a bottom-up DIB, the pointer points near the end of the buffer. If the bitmap is a top-down DIB, the pointer points to the first byte of the buffer.

Using this pointer, along with the value returned by GetPitch, you can locate and change individual pixels in an image.

注意: 由GetBits()取得的指针不一定是图片数据的起始行。必须结合GetPitch()的值来确定起始行位置

2)GetPitch()

  1. inline int CImage::GetPitch() const throw()
  2. {
  3. ATLASSUME( m_hBitmap != NULL );
  4. ATLASSERT( IsDIBSection() );
  5. return( m_nPitch );
  6. }

获得图像数据每一行的字节数

The pitch of the image. If the return value is negative, the bitmap is a bottom-up DIB and its origin is the lower left corner. If the return value is positive, the bitmap is a top-down DIB and its origin is the upper left corner.

GetBits 与 GetPitch 关系:

当GetPitch()<0时,GetBits()获得的指针指向最后一行

当GetPitch()>0时。GetBits()获得的指针指向第一行

图像数据首行地址:

  1. BYTE *pData=NULL;
  2. if(img.GetPitch()<0)
  3. pData=(BYTE*)img.GetBits()+(img.GetPitch()*(img.GetHeight()-1));
  4. else
  5. pData=(BYTE*)img.GetBits();

  1. BYTE *pData=NULL;
  2. if(img.GetPitch()<0)
  3. pData=(BYTE *)img.GetPixelAddress(img.GetHeight()-1,0);
  4. else
  5. pData=(BYTE *)img.GetPixelAddress(0,0);

3)GetBPP() 返回每一个像素所占的bit数

  1. inline int CImage::GetBPP() const throw()
  2. {
  3. ATLASSUME( m_hBitmap != NULL );
  4. return( m_nBPP );
  5. }

The number of bits per pixel.

This value determines the number of bits that define each pixel and the maximum number of colors in the bitmap

一个综合样例:

  1. void CMyImage::Negatives(void)
  2. {
  3. int i, j;
  4. //图像每一行的字节数
  5. int nRowBytes = GetPitch();
  6. int nWidth = GetWidth();
  7. int nHeight = GetHeight();
  8. //每一个像素所占的字节数
  9. int nClrCount = GetBPP() / 8;
  10. LPBYTE p;
  11. for(int index = 0; index < nClrCount; index++)
  12. {
  13. p = (LPBYTE)GetBits();
  14. for(i = 0; i < nHeight; i++)
  15. {
  16. for(j = 0; j < nWidth; j++)
  17. {
  18. p[j*nClrCount + index] = 255 - p[j*nClrCount + index];
  19. }
  20. //假设nRowBytes>0  则从開始到结尾
  21. //假设nRowBytes<0, 则从结尾到開始
  22. p += nRowBytes;
  23. }
  24. }
  25. }

8 保存到图像文件里

Saves an image as the specified file name and type.

 
HRESULT Save(
IStream*
pStream,
REFGUID
guidFileType
) const throw();
HRESULT Save(
LPCTSTR
pszFileName,
REFGUID
guidFileType= GUID_NULL
)
  1. inline HRESULT CImage::Save( LPCTSTR pszFileName, REFGUID guidFileType ) const throw()
  2. {
  3. if( !InitGDIPlus() )
  4. {
  5. return( E_FAIL );
  6. }
  7. UINT nEncoders;
  8. UINT nBytes;
  9. Gdiplus::Status status;
  10. status = Gdiplus::GetImageEncodersSize( &nEncoders, &nBytes );
  11. if( status != Gdiplus::Ok )
  12. {
  13. return( E_FAIL );
  14. }
  15. USES_CONVERSION_EX;
  16. Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
  17. if( pEncoders == NULL )
  18. return E_OUTOFMEMORY;
  19. status = Gdiplus::GetImageEncoders( nEncoders, nBytes, pEncoders );
  20. if( status != Gdiplus::Ok )
  21. {
  22. return( E_FAIL );
  23. }
  24. CLSID clsidEncoder = CLSID_NULL;
  25. if( guidFileType == GUID_NULL )
  26. {
  27. // Determine clsid from extension
  28. clsidEncoder = FindCodecForExtension( ::PathFindExtension( pszFileName ), pEncoders, nEncoders );
  29. }
  30. else
  31. {
  32. // Determine clsid from file type
  33. clsidEncoder = FindCodecForFileType( guidFileType, pEncoders, nEncoders );
  34. }
  35. if( clsidEncoder == CLSID_NULL )
  36. {
  37. return( E_FAIL );
  38. }
  39. LPCWSTR pwszFileName = T2CW_EX( pszFileName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD );
  40. #ifndef _UNICODE
  41. if( pwszFileName == NULL )
  42. return E_OUTOFMEMORY;
  43. #endif // _UNICODE
  44. if( m_bHasAlphaChannel )
  45. {
  46. ATLASSUME( m_nBPP == 32 );
  47. Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast< BYTE* >( m_pBits ) );
  48. status = bm.Save( pwszFileName, &clsidEncoder, NULL );
  49. if( status != Gdiplus::Ok )
  50. {
  51. return( E_FAIL );
  52. }
  53. }
  54. else
  55. {
  56. Gdiplus::Bitmap bm( m_hBitmap, NULL );
  57. status = bm.Save( pwszFileName, &clsidEncoder, NULL );
  58. if( status != Gdiplus::Ok )
  59. {
  60. return( E_FAIL );
  61. }
  62. }
  63. return( S_OK );
  64. }
pStream

A pointer to a stream containing the file name for the image.

pszFileName

A pointer to the file name for the image.

guidFileType

The file type to save the image as. Can be one of the following:

  • ImageFormatBMP   An uncompressed bitmap image.

  • ImageFormatPNG   A Portable Network Graphic (PNG) compressed image.

  • ImageFormatJPEG   A JPEG compressed image.

  • ImageFormatGIF   A GIF compressed image.

Call this function to save the image using a specified name and type. If the guidFileType parameter is not included, the file name's file extension will be used to determine the image format. If no extension is provided, the image
will be saved in BMP format.

MSDN样例:

  1. Copy Code
  2. // Demonstrating saving various file formats
  3. int _tmain(int argc, _TCHAR* argv[])
  4. {
  5. CImage myimage;
  6. // load existing image
  7. myimage.Load("image.bmp");
  8. // save an image in BMP format
  9. myimage.Save("c:\image1.bmp");
  10. // save an image in BMP format
  11. myimage.Save("c:\image2",ImageFormatBMP);
  12. // save an image in JPEG format
  13. myimage.Save("c:\image3.jpg");
  14. // save an image in BMP format, even though jpg file extension is used
  15. myimage.Save("c:\image4.jpg",ImageFormatBMP);
  16. return 0;
  17. }

 9 应用实例: 将两个图像合并为一个新的图像

  1. //图像路径
  2. CString img1Path;
  3. CString img2Path;
  4. CString img3Path;
  5. img1Path=_T("1.bmp");
  6. img2Path=_T("2.bmp");
  7. img3Path=_T("3.bmp");  // 将 图片1、2 合并成图片3
  8. CImage img1,img2,img3;
  9. img1.Load(img1Path);
  10. img2.Load(img2Path);
  11. CBitmap bmp;
  12. CDC memDC;
  13. HDC hDC=NULL;
  14. CDC *pDC=NULL;
  15. CBitmap *pOld=NULL;
  16. HBITMAP hBitmap=NULL;
  17. //创建位图
  18. hDC=img1.GetDC();
  19. pDC=CDC::FromHandle(hDC);
  20. bmp.DeleteObject();
  21. bmp.CreateCompatibleBitmap(pDC,img1.GetWidth()/2,img1.GetHeight());
  22. memDC.DeleteDC();
  23. memDC.CreateCompatibleDC(pDC);
  24. pOld=memDC.SelectObject(&bmp);
  25. ::SetStretchBltMode(memDC.m_hDC,HALFTONE);
  26. ::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);
  27. // 背景置白色
  28. CRgn rectRgn;
  29. rectRgn.CreateRectRgn(0,0,img1.GetWidth()/2,img1.GetHeight());
  30. CBrush brush;
  31. brush.CreateSolidBrush(RGB(255,255,255));
  32. memDC.FillRgn(&rectRgn,&brush);
  33. //绘图
  34. img1.StretchBlt(memDC.m_hDC,CRect(0,0,img1.GetWidth()/2,img1.GetHeight()/2),CRect(0,0,img1.GetWidth(),img1.GetHeight()),SRCCOPY);
  35. img2.StretchBlt(memDC.m_hDC,CRect(0,img1.GetHeight()/2,img1.GetWidth()/2,img1.GetHeight()),CRect(0,0,img2.GetWidth(),img2.GetHeight()),SRCCOPY);
  36. hBitmap=(HBITMAP)memDC.SelectObject(pOld->m_hObject);
  37. img3.Attach(hBitmap);// 加载位图资源
  38. img3.Save(img3Path); // 保存新的位图
  39. img1.ReleaseDC();
  40. img1.Destroy();
  41. img2.Destroy();
  42. img3.Destroy();

转自:http://blog.csdn.net/shuilan0066/article/details/7080244

GDI 总结三: CImage类使用的更多相关文章

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

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

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

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

  3. GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?

    在很多资料上都说CImage类是基于GDI+的,可是为什么是基于GDI+的呢? 由于使用这个类时,并没有增加#include <gdiplus.h> .也没有在程序開始和结束时分别写GDI ...

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

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

  5. CImage类

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

  6. CImage类提供了GetBits()函数原理及实现

    CImage类提供了GetBits()函数来读取数据区,GetBits()函数返回的是图片最后一行第一个像素的地址,网上有人说返回指针的起始位置是不同的,有些图片返回的是左上角像素的地址,有些是左下角 ...

  7. 一个比CBitmap更优秀的类 -- CImage类

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

  8. cocos2d-x打飞机实例总结(一):程序入口分析和AppDelegate,Application,ApplicationProtocol三个类的分析

    首先,是个敲代码的,基本上都知道程序的入口是main函数,显然,就算在cocos2d-x框架中也一样 我们看看main函数做了什么 #include "main.h" #inclu ...

  9. 设计一个程序,程序中有三个类,Triangle,Lader,Circle。

    //此程序写出三个类,triangle,lader,circle:其中triangle类具有类型为double的a,b,c边以及周长,面积属性, //具有周长,面积以及修改三边的功能,还有判断能否构成 ...

随机推荐

  1. 循环次数( M - 暴力求解、打表)

    循环次数 Description           我们知道,在编程中,我们时常需要考虑到时间复杂度,特别是对于循环的部分.例如,         如果代码中出现         for(i=1;i ...

  2. linux中/etc与/var目录,各是什么意思?这两个目录下的文件有什么特点?

    http://zhidao.baidu.com/link?url=DkxU9CyhJb_dIUAPCmPmxRtQsENgCzqy5qnLPEj_V9DqNzdt6Qya0U5iCVRCYFkgoRo ...

  3. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  4. iOS 常用开源代码整理

    本文章不定期整理. 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功 ...

  5. javascript时间函数

    //时间函数 var myDate = new Date(); myDate.getYear();        //获取当前年份(2位) myDate.getFullYear();    //获取完 ...

  6. Genymotion Unable to create Virtual Device:Connection timeout

    1.进入C:\Users\[UserName]\AppData\Local\Genymobile,打开genymotion.log,找到最后几句话:     九月 2 14:29:45 [Genymo ...

  7. Clojure学习:表达式与函数

    Clojure是一门Lisp方言——确切地说,是一门JVM上的Lisp方言——也是一门非纯粹的函数式语言. Clojure理所当然地秉承了Lisp“代码即数据( code is data! )”的设计 ...

  8. coreldraw圆形裁剪

    裁剪方法: http://zhidao.baidu.com/link?url=9-OuTkkr7igOHgKDOhJgU6iUYY5MeGEGdNXX8p6RGq79Im4va0UdMAmH4gSDz ...

  9. JQuery - 改变css样式

    jQuery提供css()的方法来实现嵌入式改变元素样式,css()方法在使用上具有多样性.其中一种接受两个输入参数:样式属性和样式值,它们之间用逗号分开.比如我们要改变链接颜色,我们可以使用下面的代 ...

  10. C中的链接属性及作用域

    如果相同的标识符出现在几个不同的源文件中时,它们是表示相同的实体,还是不同的实体.标识符的链接属性决定如何处理在不同文件中出现的标识符.标识符的作用域与它的链接属性有关. 链接属性一般有三种:exte ...