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 ...
随机推荐
- Linux下精确控制时间的函数
Linux下精确控制时间的函数 在测试程序接口运行时间的时候,常用time,gettimeofday等函数,但是这些函数在程序执行的时候是耗费时间的,如果仅仅测试时间还行,但是如果程序中用到时间控制类 ...
- [欧拉] poj 2513 Colored Sticks
主题链接: http://poj.org/problem? id=2513 Colored Sticks Time Limit: 5000MS Memory Limit: 128000K Tota ...
- pcie inbound、outbound及EP、RC间的互相訪问
Inbound:PCI域訪问存储器域 Outbound:存储器域訪问PCI域 RC訪问EP: RC存储器域->outbound->RC PCI域->EP PCI域->inbou ...
- javascript UniqueID属性
在Web页中的每一个HTML元素都一个ID属性,ID作为其标示,在我们的普通理解中它应该是unique的.但是HTML元素的ID属性是可写的,这就造成了我们非常可能人为的使ID的反复.按么假设 ...
- Scala Hello 示例
object ScalaDemo1 { def main(args: Array[String]) { println("Hello,world!"); } }
- js中escape的用法----前端页面简单加密
escape() 方法,它用于转义不能用明文正确发送的任何字符.比如,电话号码中的空格将被转换成字符 %20,从而能够在 URL 中传递这些字符. http://localhost:8080/a?na ...
- InnoDB行格式(compact,redundant)对照
InnoDB行格式分两种格式(COMPACT,redundant)默觉得COMPACT compact的存储格式为 首部为一个非NULL的变长字段长度列表,并且是依照列的顺序逆序放置的,当列的长度小于 ...
- cocos2d-x V3.0 呼叫加速度计 Acceleration
今天克服了一个问题,我觉得非常酷 哈哈. 今天得到解决cocos2d-x 3.0 呼叫重力加速器问题,上网查了很多资料 发现是不够,不解决这个问题,我不知道如果我使用3.0 这一问题的版本号,但是,这 ...
- WPF中的三维空间(1)
原文:WPF中的三维空间(1) WPF中可以创建三维几何图形,支持3D对象的应用,支持从3D Max等软件将3D文件obj导入设计中,但是目前还不支持将材质同时导入,这样需要在WPF中对3D对象重新设 ...
- 解决 下载 CM-12.0 源代码出现 Fatal: duplicate project .....问题
在使用 repo init -u git://github.com/CyanogenMod/android.git -b cm-12.0 初始化代码库的时候出现如下错误: fatal: manifes ...