zoukankan      html  css  js  c++  java
  • CImage 是基于GDI+的,很老的一篇文章,我很久很久以前看到过的

     

          在许多资料上都说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.   
    4. #pragma once   
    5.   
    6. #include <atldef.h>   
    7. #include <atlbase.h>   
    8. #include <atlstr.h>   
    9. #include <atlsimpcoll.h>   
    10. #include <atltypes.h>   
    11.   
    12. #ifndef _ATL_NO_PRAGMA_WARNINGS   
    13. #pragma warning (push)   
    14. #pragma warning(disable : 4820) // padding added after member   
    15. #endif //!_ATL_NO_PRAGMA_WARNINGS   
    16.   
    17. #pragma warning( push, 3 )   
    18. #pragma push_macro("new")   
    19. #undef new   
    20. #include <gdiplus.h>   // 注意这里:添加了GDI+得头文件   
    21. #pragma pop_macro("new")   
    22. #pragma warning( pop )   
    23.   
    24. #include <shlwapi.h>   
    25.   
    26. #ifndef _ATL_NO_DEFAULT_LIBS   
    27. #pragma comment(lib, "gdi32.lib")   
    28. #pragma comment(lib, "shlwapi.lib")   
    29. #pragma comment(lib, "gdiplus.lib")   
    30. #if WINVER >= 0x0500   
    31. #pragma comment(lib, "msimg32.lib")   
    32. #endif  // WINVER >= 0x0500   
    33. #endif  // !_ATL_NO_DEFAULT_LIBS   
    34.   
    35. #pragma pack(push, _ATL_PACKING)  
    #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的定义:

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


     

     
    1. static CInitGDIPlus s_initGDIPlus;  
    static CInitGDIPlus s_initGDIPlus;
     
    1. static CDCCache s_cache;  
    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. }  
    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+

    再看下一个函数:

     
    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. }  
    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 构造函数

     
    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. }  
    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();}


     

     
    1. inline void CImage::CInitGDIPlus::IncreaseCImageCount() throw()  
    2. {  
    3.     EnterCriticalSection(&m_sect);  
    4.     m_nCImageObjects++;  
    5.     LeaveCriticalSection(&m_sect);  
    6. }  
    inline void CImage::CInitGDIPlus::IncreaseCImageCount() throw(){ EnterCriticalSection(&m_sect); m_nCImageObjects++; LeaveCriticalSection(&m_sect);}


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

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

    我们继续查找:

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


    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.   
    10.     UINT nCodecs;  
    11.     UINT nSize;  
    12.     Gdiplus::Status status;  
    13.     Gdiplus::ImageCodecInfo* pCodecs;  
    14.   
    15.     status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize );  
    16.     USES_ATL_SAFE_ALLOCA;  
    17.     pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );  
    18.   
    19.     if( pCodecs == NULL )  
    20.         return E_OUTOFMEMORY;  
    21.   
    22.     status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs );  
    23.     BuildCodecFilterString( pCodecs, nCodecs, strImporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator );  
    24.   
    25.     return( S_OK );  
    26. }  
    27.   
    28. inline HRESULT CImage::GetExporterFilterString( CSimpleString& strExporters,   
    29.     CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription /* = NULL */,  
    30.     DWORD dwExclude /* = excludeDefaultSave */TCHAR chSeparator /* = '|' */ )  
    31. {  
    32.     if( !InitGDIPlus() )  
    33.     {  
    34.         return( E_FAIL );  
    35.     }  
    36.   
    37.     UINT nCodecs;  
    38.     UINT nSize;  
    39.     Gdiplus::Status status;  
    40.     Gdiplus::ImageCodecInfo* pCodecs;  
    41.   
    42.     status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize );  
    43.     USES_ATL_SAFE_ALLOCA;  
    44.     pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );  
    45.   
    46.     if( pCodecs == NULL )  
    47.         return E_OUTOFMEMORY;  
    48.   
    49.     status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs );  
    50.     BuildCodecFilterString( pCodecs, nCodecs, strExporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator );  
    51.   
    52.     return( S_OK );  
    53. }  
    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 );}


     

     
    1. inline HRESULT CImage::Load( IStream* pStream ) throw()  
    2. {  
    3.     if( !InitGDIPlus() )  
    4.     {  
    5.         return( E_FAIL );  
    6.     }  
    7.   
    8.     Gdiplus::Bitmap bmSrc( pStream );  
    9.     if( bmSrc.GetLastStatus() != Gdiplus::Ok )  
    10.     {  
    11.         return( E_FAIL );  
    12.     }  
    13.   
    14.     return( CreateFromGdiplusBitmap( bmSrc ) );  
    15. }  
    16.   
    17. inline HRESULT CImage::Load( LPCTSTR pszFileName ) throw()  
    18. {  
    19.     if( !InitGDIPlus() )  
    20.     {  
    21.         return( E_FAIL );  
    22.     }  
    23.   
    24.     Gdiplus::Bitmap bmSrc( (CT2W)pszFileName );  
    25.     if( bmSrc.GetLastStatus() != Gdiplus::Ok )  
    26.     {  
    27.         return( E_FAIL );  
    28.     }  
    29.   
    30.     return( CreateFromGdiplusBitmap( bmSrc ) );  
    31. }  
    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 ) );}


     

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

     
    1. inline CImage::~CImage() throw()  
    2. {  
    3.     Destroy();  
    4.     s_initGDIPlus.DecreaseCImageCount();  
    5. }  
    inline CImage::~CImage() throw(){ Destroy(); s_initGDIPlus.DecreaseCImageCount();}


     

     
    1. inline void CImage::CInitGDIPlus::DecreaseCImageCount() throw()  
    2. {  
    3.     EnterCriticalSection(&m_sect);  
    4.     if( --m_nCImageObjects == 0 )  
    5.         ReleaseGDIPlus();  
    6.     LeaveCriticalSection(&m_sect);  
    7. }  
    inline void CImage::CInitGDIPlus::DecreaseCImageCount() throw(){ EnterCriticalSection(&m_sect); if( --m_nCImageObjects == 0 ) ReleaseGDIPlus(); LeaveCriticalSection(&m_sect);}


     

     
    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. }  
    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+

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

     
    1. static CInitGDIPlus s_initGDIPlus;  
    static CInitGDIPlus s_initGDIPlus;


     

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

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

          当所有CImage变量都析构完毕时,才关闭GDI+,否则,只是减少GDI+计算变量值。

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


    原文地址:http://blog.csdn.net/shuilan0066/article/details/7086371 

    我不喜欢做界面,所以就看过一次,因为我不会,所以有个印象。

    CImage 是 GDI+ 里的东西 

  • 相关阅读:
    11-基于CPCI的中频功率放大收发板
    10-基于TMS320C6678+XC7K325T的6U CPCI Full Camera Link图像处理平台
    141-FMC141-4路 250Msps/16bits ADC, FMC板卡
    125-FMC125-两路125Msps AD,两路160Msps DA FMC子卡模块
    164-基于TI DSP TMS320C6455和Altera FPGA EP2S130的Full CameraLink PDS150接口板卡
    北京太速科技有限公司 layout 事业部
    20-基于 DSP TMS320C6455的6U CPCI高速信号处理板卡
    64-基于TMS320C6455、XC5VSX95T 的6U CPCI无线通信处理平台
    18-基于双TMS320C6678 DSP的3U VPX的信号处理平台
    202-基于TI DSP TMS320C6678、Xilinx K7 FPGA XC72K325T的高速数据处理核心板
  • 原文地址:https://www.cnblogs.com/suanguade/p/4038055.html
Copyright © 2011-2022 走看看