GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?
在很多资料上都说CImage类是基于GDI+的,可是为什么是基于GDI+的呢?
由于使用这个类时,并没有增加#include <gdiplus.h> 。也没有在程序開始和结束时分别写GDI+启动代码GdiplusStartupInput和结束代码GdiplusShutdown
使用这个类时。只须要加入头文件# include<altimage.h>就能够了,比GDI+得使用要简单一些。
而CImage 对图片的处理非常类似GDI+ 。其内部是不是封装了GDI+呢? 幸好,CImage类 是源代码公开的,我们能够研究其源代码。以便加深理解。
首先,看看altimage.h头文件
- #ifndef __ATLIMAGE_H__
- #define __ATLIMAGE_H__
- #pragma once
- #include <atldef.h>
- #include <atlbase.h>
- #include <atlstr.h>
- #include <atlsimpcoll.h>
- #include <atltypes.h>
- #ifndef _ATL_NO_PRAGMA_WARNINGS
- #pragma warning (push)
- #pragma warning(disable : 4820) // padding added after member
- #endif //!_ATL_NO_PRAGMA_WARNINGS
- #pragma warning( push, 3 )
- #pragma push_macro("new")
- #undef new
- #include <gdiplus.h> // 注意这里:加入了GDI+得头文件
- #pragma pop_macro("new")
- #pragma warning( pop )
- #include <shlwapi.h>
- #ifndef _ATL_NO_DEFAULT_LIBS
- #pragma comment(lib, "gdi32.lib")
- #pragma comment(lib, "shlwapi.lib")
- #pragma comment(lib, "gdiplus.lib")
- #if WINVER >= 0x0500
- #pragma comment(lib, "msimg32.lib")
- #endif // WINVER >= 0x0500
- #endif // !_ATL_NO_DEFAULT_LIBS
- #pragma pack(push, _ATL_PACKING)
上面包括了GDI+得头文件
再来看CImage的定义:
- class CImage
- {
- private:
- class CDCCache
- {
- public:
- CDCCache() throw();
- ~CDCCache() throw();
- HDC GetDC() throw();
- void ReleaseDC( HDC ) throw();
- private:
- HDC m_ahDCs[CIMAGE_DC_CACHE_SIZE];
- };
- class CInitGDIPlus
- {
- public:
- CInitGDIPlus() throw();
- ~CInitGDIPlus() throw();
- bool Init() throw();
- void ReleaseGDIPlus() throw();
- void IncreaseCImageCount() throw();
- void DecreaseCImageCount() throw();
- private:
- ULONG_PTR m_dwToken;
- CRITICAL_SECTION m_sect;
- LONG m_nCImageObjects;
- };
- static CInitGDIPlus s_initGDIPlus;
- static CDCCache s_cache;
它定义了两个类成员变量: 当中CInitGDIPlus 是负责GDI+的启动和释放
我们再看一下,这个成员类的Init()方法:
- inline bool CImage::CInitGDIPlus::Init() throw()
- {
- EnterCriticalSection(&m_sect);
- bool fRet = true;
- if( m_dwToken == 0 )
- {
- Gdiplus::GdiplusStartupInput input;
- Gdiplus::GdiplusStartupOutput output;
- Gdiplus::Status status = Gdiplus::GdiplusStartup( &m_dwToken, &input, &output ); //启动GDI+
- if( status != Gdiplus::Ok )
- fRet = false;
- }
- LeaveCriticalSection(&m_sect);
- return fRet;
- }
也就是说 使用这个函数 启动GDI+
再看下一个函数:
- inline void CImage::CInitGDIPlus::ReleaseGDIPlus() throw()
- {
- EnterCriticalSection(&m_sect);
- if( m_dwToken != 0 )
- {
- Gdiplus::GdiplusShutdown( m_dwToken );
- }
- m_dwToken = 0;
- LeaveCriticalSection(&m_sect);
- }
也就是说, 使用这一个函数,用来关闭GDI+
到此,我们便可知道。CImage类是基于GDI+的,可是我们还不知道CImage 对象是不是在初始化时就启动了GDI+?假设不是。那什么时候才启动GDI+呢?
为解决这个疑惑,我们查看CImage 构造函数
- inline CImage::CImage() throw() :
- m_hBitmap( NULL ),
- m_pBits( NULL ),
- m_hDC( NULL ),
- m_nDCRefCount( 0 ),
- m_hOldBitmap( NULL ),
- m_nWidth( 0 ),
- m_nHeight( 0 ),
- m_nPitch( 0 ),
- m_nBPP( 0 ),
- m_iTransparentColor( -1 ),
- m_bHasAlphaChannel( false ),
- m_bIsDIBSection( false )
- {
- s_initGDIPlus.IncreaseCImageCount();
- }
- inline void CImage::CInitGDIPlus::IncreaseCImageCount() throw()
- {
- EnterCriticalSection(&m_sect);
- m_nCImageObjects++;
- LeaveCriticalSection(&m_sect);
- }
由此可见,构造函数并没有启动GDI+
也就是说定义 CImage image; 这个image变量时。并没有启动GDI+
我们继续查找:
- inline bool CImage::InitGDIPlus() throw()
- {
- bool bSuccess = s_initGDIPlus.Init();
- return( bSuccess );
- }
CImage使用InitGDIPlus() 来初始化GDI+
因此我们查找InitGDIPlus() 的全部引用 。发现下面函数:
- inline HRESULT CImage::GetImporterFilterString( CSimpleString& strImporters,
- CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription /* = NULL */,
- DWORD dwExclude /* = excludeDefaultLoad */, TCHAR chSeparator /* = '|' */ )
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- UINT nCodecs;
- UINT nSize;
- Gdiplus::Status status;
- Gdiplus::ImageCodecInfo* pCodecs;
- status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize );
- USES_ATL_SAFE_ALLOCA;
- pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
- if( pCodecs == NULL )
- return E_OUTOFMEMORY;
- status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs );
- BuildCodecFilterString( pCodecs, nCodecs, strImporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator );
- return( S_OK );
- }
- inline HRESULT CImage::GetExporterFilterString( CSimpleString& strExporters,
- CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription /* = NULL */,
- DWORD dwExclude /* = excludeDefaultSave */, TCHAR chSeparator /* = '|' */ )
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- UINT nCodecs;
- UINT nSize;
- Gdiplus::Status status;
- Gdiplus::ImageCodecInfo* pCodecs;
- status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize );
- USES_ATL_SAFE_ALLOCA;
- pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
- if( pCodecs == NULL )
- return E_OUTOFMEMORY;
- status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs );
- BuildCodecFilterString( pCodecs, nCodecs, strExporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator );
- return( S_OK );
- }
- inline HRESULT CImage::Load( IStream* pStream ) throw()
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- Gdiplus::Bitmap bmSrc( pStream );
- if( bmSrc.GetLastStatus() != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- return( CreateFromGdiplusBitmap( bmSrc ) );
- }
- inline HRESULT CImage::Load( LPCTSTR pszFileName ) throw()
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- Gdiplus::Bitmap bmSrc( (CT2W)pszFileName );
- if( bmSrc.GetLastStatus() != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- return( CreateFromGdiplusBitmap( bmSrc ) );
- }
- inline HRESULT CImage::Save( IStream* pStream, REFGUID guidFileType ) const throw()
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- UINT nEncoders;
- UINT nBytes;
- Gdiplus::Status status;
- status = Gdiplus::GetImageEncodersSize( &nEncoders, &nBytes );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- USES_ATL_SAFE_ALLOCA;
- Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
- if( pEncoders == NULL )
- return E_OUTOFMEMORY;
- status = Gdiplus::GetImageEncoders( nEncoders, nBytes, pEncoders );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- CLSID clsidEncoder = FindCodecForFileType( guidFileType, pEncoders, nEncoders );
- if( clsidEncoder == CLSID_NULL )
- {
- return( E_FAIL );
- }
- if( m_bHasAlphaChannel )
- {
- ATLASSUME( m_nBPP == 32 );
- Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast< BYTE* >( m_pBits ) );
- status = bm.Save( pStream, &clsidEncoder, NULL );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- }
- else
- {
- Gdiplus::Bitmap bm( m_hBitmap, NULL );
- status = bm.Save( pStream, &clsidEncoder, NULL );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- }
- return( S_OK );
- }
- inline HRESULT CImage::Save( LPCTSTR pszFileName, REFGUID guidFileType ) const throw()
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- UINT nEncoders;
- UINT nBytes;
- Gdiplus::Status status;
- status = Gdiplus::GetImageEncodersSize( &nEncoders, &nBytes );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- USES_CONVERSION_EX;
- Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
- if( pEncoders == NULL )
- return E_OUTOFMEMORY;
- status = Gdiplus::GetImageEncoders( nEncoders, nBytes, pEncoders );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- CLSID clsidEncoder = CLSID_NULL;
- if( guidFileType == GUID_NULL )
- {
- // Determine clsid from extension
- clsidEncoder = FindCodecForExtension( ::PathFindExtension( pszFileName ), pEncoders, nEncoders );
- }
- else
- {
- // Determine clsid from file type
- clsidEncoder = FindCodecForFileType( guidFileType, pEncoders, nEncoders );
- }
- if( clsidEncoder == CLSID_NULL )
- {
- return( E_FAIL );
- }
- LPCWSTR pwszFileName = T2CW_EX( pszFileName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD );
- #ifndef _UNICODE
- if( pwszFileName == NULL )
- return E_OUTOFMEMORY;
- #endif // _UNICODE
- if( m_bHasAlphaChannel )
- {
- ATLASSUME( m_nBPP == 32 );
- Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast< BYTE* >( m_pBits ) );
- status = bm.Save( pwszFileName, &clsidEncoder, NULL );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- }
- else
- {
- Gdiplus::Bitmap bm( m_hBitmap, NULL );
- status = bm.Save( pwszFileName, &clsidEncoder, NULL );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- }
- return( S_OK );
- }
有上面可知: CImage对象 在第一次Load() 或第一次Save() 时 启动GDI+
以下我们看看 CImage析构时,能否将GDI+关闭掉:
- inline CImage::~CImage() throw()
- {
- Destroy();
- s_initGDIPlus.DecreaseCImageCount();
- }
- inline void CImage::CInitGDIPlus::DecreaseCImageCount() throw()
- {
- EnterCriticalSection(&m_sect);
- if( --m_nCImageObjects == 0 )
- ReleaseGDIPlus();
- LeaveCriticalSection(&m_sect);
- }
- inline void CImage::CInitGDIPlus::ReleaseGDIPlus() throw()
- {
- EnterCriticalSection(&m_sect);
- if( m_dwToken != 0 )
- {
- Gdiplus::GdiplusShutdown( m_dwToken );
- }
- m_dwToken = 0;
- LeaveCriticalSection(&m_sect);
- }
也就是说,一个CImage对象退出时。并不直接关闭GDI+ ,而是只将GDI+使用计数减一。 当其为0时。再关闭GDI+
而这是通过类静态变量来实现计数的:
- static CInitGDIPlus s_initGDIPlus;
由此,我们可作例如以下总结:
当定义多个CImge 变量时, 当某个变量载入图片或保存图片时,启动GDI+。之后。 当其它变量再载入图片或保存时,添加GDI+计数变量
当全部CImage变量都析构完成时,才关闭GDI+。否则,仅仅是降低GDI+计算变量值。
所以说,CImage类是基于GDI+的。
GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?的更多相关文章
- GDI 总结三: CImage类使用
前言 CImage类是基于GDI+的.可是这里为什么要讲归于GDI? 主要是基于这种考虑: 在GDI+环境中,我们能够直接使用GDI+ ,没多少必要再使用CImage类 可是,假设再 ...
- 【VS开发】GDI+ 用CImage类来显示PNG、JPG等图片
系统环境:Windows 7 软件环境:Visual Studio 2008 SP1 本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也 ...
- 用CImage类来显示PNG、JPG等图片
系统环境:Windows 7软件环境:Visual Studio 2008 SP1本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也是A ...
- CImage类
CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素.这里介绍GDI+和CImage的一般使用方法和技巧. TAG: GDI CImage 后处理 我们知道,Vi ...
- CImage类提供了GetBits()函数原理及实现
CImage类提供了GetBits()函数来读取数据区,GetBits()函数返回的是图片最后一行第一个像素的地址,网上有人说返回指针的起始位置是不同的,有些图片返回的是左上角像素的地址,有些是左下角 ...
- 戏说 .NET GDI+系列学习教程(一、Graphics类--纸)
Graphics类(纸) Graphics类封装一个GDI+绘图图面,提供将对象绘制到显示设备的方法,Graphics与特定的设备上下文关联. 画图方法都被包括在Graphics类中,在画任何对象时, ...
- 一个比CBitmap更优秀的类 -- CImage类
Visual C++的CBitmap类的功能是比较弱的,它只能显示出在资源中的图标.位图.光标以及图元文件的内容,而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP.GIF.JPEG ...
- 强大的CImage类
这下有了CImage类,处理其他类型的图片不再寻找第三方类库了.加载到对话框背景的代码如下: //从资源里载入背景JPEG图片 HRSRC hRsrc=::FindResource(AfxGetRe ...
- CImage类的介绍与使用
CImage类的介绍与使用 程序代码下载处:http://download.csdn.net/source/2098910 下载处:http://hi.baidu.com/wangleitongxin ...
随机推荐
- AOP 之 6.1 AOP基础 ——跟我学spring3(转)
http://jinnianshilongnian.iteye.com/blog/1418596
- Linux档案种类与扩展名(2013.09.03)
档案种类: 正规档案(regular file ): 第一个字符为 [ -],例如 [-rwxrwxrwx ].另外,依照档案的内容,又大略可以分为: 纯文本档(ASCII) 二 ...
- HDU3977(斐波那契数列模n的循环节长度)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3977 题意:求斐波那契数列模p的循环节长度,注意p最大是2*10^9,但是它的素因子小于10^6. 分析过 ...
- Java 小样例:图书馆课程设计(Java 8 版)
用 Java 模拟一个图书馆.包含创建图书.创建读者.借书.还书.列出全部图书.列出全部读者.列出已借出的图书.列出过期未还的图书等功能. 每一个读者最多仅仅能借 3 本书,每一个书最多仅仅能借 3 ...
- POJ 1422 Air Raid(二分图匹配最小路径覆盖)
POJ 1422 Air Raid 题目链接 题意:给定一个有向图,在这个图上的某些点上放伞兵,能够使伞兵能够走到图上全部的点.且每一个点仅仅被一个伞兵走一次.问至少放多少伞兵 思路:二分图的最小路径 ...
- 使用Google Roads API抓取道路信息(java实现)
Google Roads API提供了强大的道路获取接口,用户仅仅需调用对应的API就能够获取对应区域的道路坐标以及道路的限速信息. 详细的调用方法例如以下: https://roads.google ...
- U8Linux磁盘与文件系统管理
1.扇区为最小的物理存储单位,每个扇区为512bytes;将扇区组成一个圆,那就是柱面,柱面是分区的最小单位.Linux系统的EX2文件系统:inode的内容用于记录文件的权限与相关属性. 至于blo ...
- 关于多线程的一个例子(UI实时显示)
在开发Window应用程序的时候,经常需要在界面上显示出已经执行到什么步骤了,拿一个简单例子来说,创建一个Winform程序,在窗体上访一个Button和一个Label,点击Button时做100次循 ...
- Linux中块设备驱动程序分析
基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 開始之前先来了解这个块设备中的核心数据结构: struct sbull_dev { i ...
- hdu2457 Trie图+dp
hdu2457 给定n个模式串, 和一个文本串 问如果修改最少的字符串使得文本串不包含模式串, 输出最少的次数,如果不能修改成功,则输出-1 dp[i][j] 表示长度为i的字符串, 到达状态j(Tr ...