zoukankan      html  css  js  c++  java
  • GDI+ 两个汇总 : 为什么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)  


    上面包括了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.     };  


     

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


     

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


     

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


     

    有上面可知: 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

  • 相关阅读:
    activiti 用户手册中 10分钟 小例子 简单代码搭建 及 其中的 各种坑
    Eclipse启动项目正常,放到tomcat下单独启动就报错的 一例
    Project facet jst.web.jstl has not been defined.
    MySQL删除所有表的外键约束、禁用外键约束
    Unsupported major.minor version 52.0解决办法
    Could not update Activiti database schema: unknown version from database: '5.20.0.1'
    Android SDK下载地址
    Unity3d游戏中添加移动MM支付SDK问题处理
    Unity3d集成移动MM SDK 2.2的技术要点(坑爹的MM SDK)
    Android SDK更新 Connection to http://dl-ssl.google.com refused 解决方法
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4732065.html
Copyright © 2011-2022 走看看