在很多资料上都说CImage类是基于GDI+的,可是为什么是基于GDI+的呢?

由于使用这个类时,并没有增加#include <gdiplus.h> 。也没有在程序開始和结束时分别写GDI+启动代码GdiplusStartupInput和结束代码GdiplusShutdown

使用这个类时。只须要加入头文件# include<altimage.h>就能够了,比GDI+得使用要简单一些。

而CImage 对图片的处理非常类似GDI+ 。其内部是不是封装了GDI+呢? 幸好,CImage类 是源代码公开的,我们能够研究其源代码。以便加深理解。

首先,看看altimage.h头文件

  1. #ifndef __ATLIMAGE_H__
  2. #define __ATLIMAGE_H__
  3. #pragma once
  4. #include <atldef.h>
  5. #include <atlbase.h>
  6. #include <atlstr.h>
  7. #include <atlsimpcoll.h>
  8. #include <atltypes.h>
  9. #ifndef _ATL_NO_PRAGMA_WARNINGS
  10. #pragma warning (push)
  11. #pragma warning(disable : 4820) // padding added after member
  12. #endif //!_ATL_NO_PRAGMA_WARNINGS
  13. #pragma warning( push, 3 )
  14. #pragma push_macro("new")
  15. #undef new
  16. #include <gdiplus.h>   // 注意这里:加入了GDI+得头文件
  17. #pragma pop_macro("new")
  18. #pragma warning( pop )
  19. #include <shlwapi.h>
  20. #ifndef _ATL_NO_DEFAULT_LIBS
  21. #pragma comment(lib, "gdi32.lib")
  22. #pragma comment(lib, "shlwapi.lib")
  23. #pragma comment(lib, "gdiplus.lib")
  24. #if WINVER >= 0x0500
  25. #pragma comment(lib, "msimg32.lib")
  26. #endif  // WINVER >= 0x0500
  27. #endif  // !_ATL_NO_DEFAULT_LIBS
  28. #pragma pack(push, _ATL_PACKING)

上面包括了GDI+得头文件

再来看CImage的定义:

  1. class CImage
  2. {
  3. private:
  4. class CDCCache
  5. {
  6. public:
  7. CDCCache() throw();
  8. ~CDCCache() throw();
  9. HDC GetDC() throw();
  10. void ReleaseDC( HDC ) throw();
  11. private:
  12. HDC m_ahDCs[CIMAGE_DC_CACHE_SIZE];
  13. };
  14. class CInitGDIPlus
  15. {
  16. public:
  17. CInitGDIPlus() throw();
  18. ~CInitGDIPlus() throw();
  19. bool Init() throw();
  20. void ReleaseGDIPlus() throw();
  21. void IncreaseCImageCount() throw();
  22. void DecreaseCImageCount() throw();
  23. private:
  24. ULONG_PTR m_dwToken;
  25. CRITICAL_SECTION m_sect;
  26. LONG m_nCImageObjects;
  27. };
  1. static CInitGDIPlus s_initGDIPlus;
  1. static CDCCache s_cache;

它定义了两个类成员变量: 当中CInitGDIPlus 是负责GDI+的启动和释放

我们再看一下,这个成员类的Init()方法:

  1. inline bool CImage::CInitGDIPlus::Init() throw()
  2. {
  3. EnterCriticalSection(&m_sect);
  4. bool fRet = true;
  5. if( m_dwToken == 0 )
  6. {
  7. Gdiplus::GdiplusStartupInput input;
  8. Gdiplus::GdiplusStartupOutput output;
  9. Gdiplus::Status status = Gdiplus::GdiplusStartup( &m_dwToken, &input, &output );   //启动GDI+
  10. if( status != Gdiplus::Ok )
  11. fRet = false;
  12. }
  13. LeaveCriticalSection(&m_sect);
  14. return fRet;
  15. }

也就是说 使用这个函数 启动GDI+

再看下一个函数:

  1. inline void CImage::CInitGDIPlus::ReleaseGDIPlus() throw()
  2. {
  3. EnterCriticalSection(&m_sect);
  4. if( m_dwToken != 0 )
  5. {
  6. Gdiplus::GdiplusShutdown( m_dwToken );
  7. }
  8. m_dwToken = 0;
  9. LeaveCriticalSection(&m_sect);
  10. }

也就是说, 使用这一个函数,用来关闭GDI+

到此,我们便可知道。CImage类是基于GDI+的,可是我们还不知道CImage 对象是不是在初始化时就启动了GDI+?假设不是。那什么时候才启动GDI+呢?

为解决这个疑惑,我们查看CImage 构造函数

  1. inline CImage::CImage() throw() :
  2. m_hBitmap( NULL ),
  3. m_pBits( NULL ),
  4. m_hDC( NULL ),
  5. m_nDCRefCount( 0 ),
  6. m_hOldBitmap( NULL ),
  7. m_nWidth( 0 ),
  8. m_nHeight( 0 ),
  9. m_nPitch( 0 ),
  10. m_nBPP( 0 ),
  11. m_iTransparentColor( -1 ),
  12. m_bHasAlphaChannel( false ),
  13. m_bIsDIBSection( false )
  14. {
  15. s_initGDIPlus.IncreaseCImageCount();
  16. }
  1. inline void CImage::CInitGDIPlus::IncreaseCImageCount() throw()
  2. {
  3. EnterCriticalSection(&m_sect);
  4. m_nCImageObjects++;
  5. LeaveCriticalSection(&m_sect);
  6. }

由此可见,构造函数并没有启动GDI+

也就是说定义  CImage image;  这个image变量时。并没有启动GDI+

我们继续查找:

  1. inline bool CImage::InitGDIPlus() throw()
  2. {
  3. bool bSuccess = s_initGDIPlus.Init();
  4. return( bSuccess );
  5. }

CImage使用InitGDIPlus() 来初始化GDI+

因此我们查找InitGDIPlus() 的全部引用 。发现下面函数:

  1. inline HRESULT CImage::GetImporterFilterString( CSimpleString& strImporters,
  2. CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription /* = NULL */,
  3. DWORD dwExclude /* = excludeDefaultLoad */, TCHAR chSeparator /* = '|' */ )
  4. {
  5. if( !InitGDIPlus() )
  6. {
  7. return( E_FAIL );
  8. }
  9. UINT nCodecs;
  10. UINT nSize;
  11. Gdiplus::Status status;
  12. Gdiplus::ImageCodecInfo* pCodecs;
  13. status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize );
  14. USES_ATL_SAFE_ALLOCA;
  15. pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
  16. if( pCodecs == NULL )
  17. return E_OUTOFMEMORY;
  18. status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs );
  19. BuildCodecFilterString( pCodecs, nCodecs, strImporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator );
  20. return( S_OK );
  21. }
  22. inline HRESULT CImage::GetExporterFilterString( CSimpleString& strExporters,
  23. CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription /* = NULL */,
  24. DWORD dwExclude /* = excludeDefaultSave */, TCHAR chSeparator /* = '|' */ )
  25. {
  26. if( !InitGDIPlus() )
  27. {
  28. return( E_FAIL );
  29. }
  30. UINT nCodecs;
  31. UINT nSize;
  32. Gdiplus::Status status;
  33. Gdiplus::ImageCodecInfo* pCodecs;
  34. status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize );
  35. USES_ATL_SAFE_ALLOCA;
  36. pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
  37. if( pCodecs == NULL )
  38. return E_OUTOFMEMORY;
  39. status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs );
  40. BuildCodecFilterString( pCodecs, nCodecs, strExporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator );
  41. return( S_OK );
  42. }
  1. inline HRESULT CImage::Load( IStream* pStream ) throw()
  2. {
  3. if( !InitGDIPlus() )
  4. {
  5. return( E_FAIL );
  6. }
  7. Gdiplus::Bitmap bmSrc( pStream );
  8. if( bmSrc.GetLastStatus() != Gdiplus::Ok )
  9. {
  10. return( E_FAIL );
  11. }
  12. return( CreateFromGdiplusBitmap( bmSrc ) );
  13. }
  14. inline HRESULT CImage::Load( LPCTSTR pszFileName ) throw()
  15. {
  16. if( !InitGDIPlus() )
  17. {
  18. return( E_FAIL );
  19. }
  20. Gdiplus::Bitmap bmSrc( (CT2W)pszFileName );
  21. if( bmSrc.GetLastStatus() != Gdiplus::Ok )
  22. {
  23. return( E_FAIL );
  24. }
  25. return( CreateFromGdiplusBitmap( bmSrc ) );
  26. }
  1. inline HRESULT CImage::Save( IStream* pStream, 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_ATL_SAFE_ALLOCA;
  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 = FindCodecForFileType( guidFileType, pEncoders, nEncoders );
  25. if( clsidEncoder == CLSID_NULL )
  26. {
  27. return( E_FAIL );
  28. }
  29. if( m_bHasAlphaChannel )
  30. {
  31. ATLASSUME( m_nBPP == 32 );
  32. Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast< BYTE* >( m_pBits ) );
  33. status = bm.Save( pStream, &clsidEncoder, NULL );
  34. if( status != Gdiplus::Ok )
  35. {
  36. return( E_FAIL );
  37. }
  38. }
  39. else
  40. {
  41. Gdiplus::Bitmap bm( m_hBitmap, NULL );
  42. status = bm.Save( pStream, &clsidEncoder, NULL );
  43. if( status != Gdiplus::Ok )
  44. {
  45. return( E_FAIL );
  46. }
  47. }
  48. return( S_OK );
  49. }
  50. inline HRESULT CImage::Save( LPCTSTR pszFileName, REFGUID guidFileType ) const throw()
  51. {
  52. if( !InitGDIPlus() )
  53. {
  54. return( E_FAIL );
  55. }
  56. UINT nEncoders;
  57. UINT nBytes;
  58. Gdiplus::Status status;
  59. status = Gdiplus::GetImageEncodersSize( &nEncoders, &nBytes );
  60. if( status != Gdiplus::Ok )
  61. {
  62. return( E_FAIL );
  63. }
  64. USES_CONVERSION_EX;
  65. Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
  66. if( pEncoders == NULL )
  67. return E_OUTOFMEMORY;
  68. status = Gdiplus::GetImageEncoders( nEncoders, nBytes, pEncoders );
  69. if( status != Gdiplus::Ok )
  70. {
  71. return( E_FAIL );
  72. }
  73. CLSID clsidEncoder = CLSID_NULL;
  74. if( guidFileType == GUID_NULL )
  75. {
  76. // Determine clsid from extension
  77. clsidEncoder = FindCodecForExtension( ::PathFindExtension( pszFileName ), pEncoders, nEncoders );
  78. }
  79. else
  80. {
  81. // Determine clsid from file type
  82. clsidEncoder = FindCodecForFileType( guidFileType, pEncoders, nEncoders );
  83. }
  84. if( clsidEncoder == CLSID_NULL )
  85. {
  86. return( E_FAIL );
  87. }
  88. LPCWSTR pwszFileName = T2CW_EX( pszFileName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD );
  89. #ifndef _UNICODE
  90. if( pwszFileName == NULL )
  91. return E_OUTOFMEMORY;
  92. #endif // _UNICODE
  93. if( m_bHasAlphaChannel )
  94. {
  95. ATLASSUME( m_nBPP == 32 );
  96. Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast< BYTE* >( m_pBits ) );
  97. status = bm.Save( pwszFileName, &clsidEncoder, NULL );
  98. if( status != Gdiplus::Ok )
  99. {
  100. return( E_FAIL );
  101. }
  102. }
  103. else
  104. {
  105. Gdiplus::Bitmap bm( m_hBitmap, NULL );
  106. status = bm.Save( pwszFileName, &clsidEncoder, NULL );
  107. if( status != Gdiplus::Ok )
  108. {
  109. return( E_FAIL );
  110. }
  111. }
  112. return( S_OK );
  113. }

有上面可知: CImage对象 在第一次Load() 或第一次Save() 时 启动GDI+

以下我们看看 CImage析构时,能否将GDI+关闭掉:

  1. inline CImage::~CImage() throw()
  2. {
  3. Destroy();
  4. s_initGDIPlus.DecreaseCImageCount();
  5. }
  1. inline void CImage::CInitGDIPlus::DecreaseCImageCount() throw()
  2. {
  3. EnterCriticalSection(&m_sect);
  4. if( --m_nCImageObjects == 0 )
  5. ReleaseGDIPlus();
  6. LeaveCriticalSection(&m_sect);
  7. }
  1. inline void CImage::CInitGDIPlus::ReleaseGDIPlus() throw()
  2. {
  3. EnterCriticalSection(&m_sect);
  4. if( m_dwToken != 0 )
  5. {
  6. Gdiplus::GdiplusShutdown( m_dwToken );
  7. }
  8. m_dwToken = 0;
  9. LeaveCriticalSection(&m_sect);
  10. }

也就是说,一个CImage对象退出时。并不直接关闭GDI+ ,而是只将GDI+使用计数减一。 当其为0时。再关闭GDI+

而这是通过类静态变量来实现计数的:

  1. static CInitGDIPlus s_initGDIPlus;

由此,我们可作例如以下总结:

当定义多个CImge 变量时, 当某个变量载入图片或保存图片时,启动GDI+。之后。 当其它变量再载入图片或保存时,添加GDI+计数变量

当全部CImage变量都析构完成时,才关闭GDI+。否则,仅仅是降低GDI+计算变量值。

所以说,CImage类是基于GDI+的。

 转会:http://blog.csdn.net/shuilan0066/article/details/7086371

GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?的更多相关文章

  1. GDI 总结三: CImage类使用

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

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

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

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

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

  4. CImage类

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

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

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

  6. 戏说 .NET GDI+系列学习教程(一、Graphics类--纸)

    Graphics类(纸) Graphics类封装一个GDI+绘图图面,提供将对象绘制到显示设备的方法,Graphics与特定的设备上下文关联. 画图方法都被包括在Graphics类中,在画任何对象时, ...

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

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

  8. 强大的CImage类

    这下有了CImage类,处理其他类型的图片不再寻找第三方类库了.加载到对话框背景的代码如下:  //从资源里载入背景JPEG图片 HRSRC hRsrc=::FindResource(AfxGetRe ...

  9. CImage类的介绍与使用

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

随机推荐

  1. 【Unity3D自学记录】可视化对照十多种排序算法(C#版)

    在这篇文章中.我会向大家展示一些排序算法的可视化过程.我还写了一个工具.大家可对照查看某两种排序算法. 下载源代码 – 75.7 KB 下载演示样例 – 27.1 KB 引言 首先,我觉得是最重要的是 ...

  2. 使用Nexus搭建企业maven仓库(二)

    先阅读<使用Nexus搭建企业maven仓库(一)> http://blog.csdn.net/ouyida3/article/details/40747545 1.官网眼下最新的版本号是 ...

  3. Redis深入之数据结构

    Redis主要数据结构 链表 Redis使用的C语言并没有内置这样的数据结构,所以Redis构建了自己的链表实现.列表键的底层实现之中的一个就是链表,一个列表键包括了数量比較多的元素,列表中包括的元素 ...

  4. SSL与TLS的区别以及介绍(转)

    SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层.SSL通过互相认证.使用数字签名确保完整性.使用加密确保私密性,以实现客户 ...

  5. 64地点 Windows 8/7 根据系统 32地点PLSQL 耦合 64 地点 Oracle 11g

    64地点 Windows 8/7 根据系统 32地点PL/SQL 耦合 64 地点 Oracle 11g     说明:安装后Oracle的 oci.dll 是64位的,而32位应用程序 PL/SQL ...

  6. Visual Studio跨平台开发实战(4) - Xamarin Android基本控制项介绍

    原文 Visual Studio跨平台开发实战(4) - Xamarin Android基本控制项介绍 前言 不同于iOS,Xamarin 在Visual Studio中针对Android,可以直接设 ...

  7. hdu2457 Trie图+dp

    hdu2457 给定n个模式串, 和一个文本串 问如果修改最少的字符串使得文本串不包含模式串, 输出最少的次数,如果不能修改成功,则输出-1 dp[i][j] 表示长度为i的字符串, 到达状态j(Tr ...

  8. oracle转mysql总结(转)

    ares-sdk初始开发测试使用的是oracle数据库,由于宁波通商的特殊需要,必须把数据库环境从oracle转向mysql. 现对转换过程中出现的问题及经验总结如下: 主键生成策略 创建一个专门记录 ...

  9. easyui LinkButton

    http://www.zi-han.net/case/easyui/menu&button.html

  10. 第4周 页面限制8060 bytes

    原文:第4周 页面限制8060 bytes 恭喜您!在你面前就只剩下几页了,然后你就可以完成第1个月的SQL Server性能调优培训了.今天我将讲下页的一些限制,还有为什么你会喜欢这些限制,同时也会 ...