对于图像操作,在遥远的计算机蛮荒时代,我们一般使用 CBitmap 类,这个类在 MFC 和 WTL 上均有实现。至于 DIB 格式的图像,以及文件存盘的操作,CBitmap 类就无能为力了。我们只能求助于自己来实现或者用别人实现的类了。 时代总是进步的,到 VC7 以后了,ATL 框架内增加了一个 CImage 类,基本上完成了上述的述求。但顽固如我等人,却一定要在 VC6 的圈子里混(因为编译出来的可执行文件不用带一大堆什么.Net框架,什么带manifest的古怪东东,又是什么神秘的特定版本的运行时DLL等等,我只想我的简单程序能顺畅的运行在所有的 Windows 平台上,如此而已),就开始倒行逆施的改造了 CImage 类了,改造如下。 这个类用到了 CString 类,这就必须要 WTL 才能工作,当然 MFC 框架应该也能。 还用到了 GDIplus,因此您最好还要下载能支持 VC6 的最后版本的 Platform SDK,且将 VC6 打上 SP6 补丁才能用。 一些资源的下载地址: 官方的原版 VC6sp6 补丁下载地址如下:请看清你需要的是中文还是英文 英文版地址: http://download.microsoft.com/download/1/9/f/19fe4660-5792-4683-99e0-8d48c22eed74/Vs6sp6.exe 简体中文版地址: http://download.microsoft.com/download/e/c/9/ec94a5d4-d0cf-4484-8b7a-21802f497309/Vs6sp6.exe 最后一个支持 VC6 的 PSDK 下载地址 http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm 最新版本的 WTL 的下载地址是 http://wtl.sourceforge.net/ 下面是使用注意事项: 在您的工程的 stdafx.h 文件的顶打头, 定义一个宏 #define __VC6_ATL_IMAGE_H__ 1 在 stdafx.h 的靠近下部包含这个文件 #include 在 stdafx.cpp 文件的末尾加上这么几句 #if _MSC_VER < 1300 CImage::CInitGDIPlus CImage::s_initGDIPlus; CImage::CDCCache CImage::s_cache; #endif 然后, 我们改工程的属性: 菜单项 "project" -> "settings" 蹦出"Project settings"对话框 "C/C++" -> "Category:" -> "Procompiled headers" 选中"Not using precompiled headers" 单选按钮, 不使用预编译头. (这里顺便一说, 建议同学们以后的工程都不使用预编译头, 这项 M$ 提供的特性给您造成的麻烦比给你的好处要多的多的多的多的多). 到这时, 就可以使用 CImage 类了啦, 比如说从磁盘文件装入图像, 保存图像文件, DIB 操作, 等等. 以下内容就是更改后的 atlimage.h 文件 // This is a part of the Active Template Library. // Copyright (C) Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #ifndef __ATLIMAGE_H__ #define __ATLIMAGE_H__ #pragma once //#include #include //#include //#include //#include #ifndef __TSTRING__ #define __TSTRING__ #include namespace std { typedef basic_string _tstring; }; // namespace std #endif // __TSTRING__ #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 //#pragma pop_macro("new") #pragma warning( pop ) #include #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) namespace ATL { template< typename N > inline N WINAPI _AtlAlignUp( N n, ULONG nAlign ) throw() { return( N( (n+(nAlign-1))&~(N( nAlign )-1) ) ); } typedef CString CSimpleString; const int CIMAGE_DC_CACHE_SIZE = 4; class CImage; class CImageDC { public: CImageDC( const CImage& image ) throw(); ~CImageDC() throw(); operator HDC() const throw(); private: const CImage& m_image; HDC m_hDC; }; 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; }; public: static const DWORD createAlphaChannel; static const DWORD excludeGIF ; static const DWORD excludeBMP ; static const DWORD excludeEMF ; static const DWORD excludeWMF ; static const DWORD excludeJPEG ; static const DWORD excludePNG ; static const DWORD excludeTIFF ; static const DWORD excludeIcon ; static const DWORD excludeOther ; static const DWORD excludeDefaultLoad ; static const DWORD excludeDefaultSave ; static const DWORD excludeValid ; enum DIBOrientation { DIBOR_DEFAULT, DIBOR_TOPDOWN, DIBOR_BOTTOMUP }; public: CImage() throw(); virtual ~CImage() throw(); operator HBITMAP() const throw(); #if WINVER >= 0x0500 BOOL AlphaBlend( HDC hDestDC, int xDest, int yDest, BYTE bSrcAlpha = 0xff, BYTE bBlendOp = AC_SRC_OVER ) const throw(); BOOL AlphaBlend( HDC hDestDC, const POINT& pointDest, BYTE bSrcAlpha = 0xff, BYTE bBlendOp = AC_SRC_OVER ) const throw(); BOOL AlphaBlend( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BYTE bSrcAlpha = 0xff, BYTE bBlendOp = AC_SRC_OVER ) const throw(); BOOL AlphaBlend( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, BYTE bSrcAlpha = 0xff, BYTE bBlendOp = AC_SRC_OVER ) const throw(); #endif // WINVER >= 0x0500 void Attach( HBITMAP hBitmap, DIBOrientation eOrientation = DIBOR_DEFAULT ) throw(); BOOL BitBlt( HDC hDestDC, int xDest, int yDest, DWORD dwROP = SRCCOPY ) const throw(); BOOL BitBlt( HDC hDestDC, const POINT& pointDest, DWORD dwROP = SRCCOPY ) const throw(); BOOL BitBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, DWORD dwROP = SRCCOPY ) const throw(); BOOL BitBlt( HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, DWORD dwROP = SRCCOPY ) const throw(); BOOL Create( int nWidth, int nHeight, int nBPP, DWORD dwFlags = 0 ) throw(); BOOL CreateEx( int nWidth, int nHeight, int nBPP, DWORD eCompression, const DWORD* pdwBitmasks = NULL, DWORD dwFlags = 0 ) throw(); void Destroy() throw(); HBITMAP Detach() throw(); BOOL Draw( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight ) const throw(); BOOL Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc ) const throw(); BOOL Draw( HDC hDestDC, int xDest, int yDest ) const throw(); BOOL Draw( HDC hDestDC, const POINT& pointDest ) const throw(); BOOL Draw( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight ) const throw(); BOOL Draw( HDC hDestDC, const RECT& rectDest ) const throw(); const void* GetBits() const throw(); void* GetBits() throw(); int GetBPP() const throw(); void GetColorTable( UINT iFirstColor, UINT nColors, RGBQUAD* prgbColors ) const throw(); HDC GetDC() const throw(); static HRESULT GetExporterFilterString( CSimpleString& strExporters, CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription = NULL, DWORD dwExclude = excludeDefaultSave, TCHAR chSeparator = _T( '|' ) ); static HRESULT GetImporterFilterString( CSimpleString& strImporters, CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription = NULL, DWORD dwExclude = excludeDefaultLoad, TCHAR chSeparator = _T( '|' ) ); int GetHeight() const throw(); int GetMaxColorTableEntries() const throw(); int GetPitch() const throw(); const void* GetPixelAddress( int x, int y ) const throw(); void* GetPixelAddress( int x, int y ) throw(); COLORREF GetPixel( int x, int y ) const throw(); LONG GetTransparentColor() const throw(); int GetWidth() const throw(); bool IsDIBSection() const throw(); bool IsIndexed() const throw(); bool IsNull() const throw(); HRESULT Load( LPCTSTR pszFileName ) throw(); HRESULT Load( IStream* pStream ) throw(); void LoadFromResource( HINSTANCE hInstance, LPCTSTR pszResourceName ) throw(); void LoadFromResource( HINSTANCE hInstance, UINT nIDResource ) throw(); BOOL MaskBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, HBITMAP hbmMask, int xMask, int yMask, DWORD dwROP = SRCCOPY ) const throw(); BOOL MaskBlt( HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, HBITMAP hbmMask, const POINT& pointMask, DWORD dwROP = SRCCOPY ) const throw(); BOOL MaskBlt( HDC hDestDC, int xDest, int yDest, HBITMAP hbmMask, DWORD dwROP = SRCCOPY ) const throw(); BOOL MaskBlt( HDC hDestDC, const POINT& pointDest, HBITMAP hbmMask, DWORD dwROP = SRCCOPY ) const throw(); BOOL PlgBlt( HDC hDestDC, const POINT* pPoints, HBITMAP hbmMask = NULL ) const throw(); BOOL PlgBlt( HDC hDestDC, const POINT* pPoints, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, HBITMAP hbmMask = NULL, int xMask = 0, int yMask = 0 ) const throw(); BOOL PlgBlt( HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, HBITMAP hbmMask = NULL, const POINT& pointMask = CPoint( 0, 0 ) ) const throw(); void ReleaseDC() const throw(); HRESULT Save( IStream* pStream, REFGUID guidFileType ) const throw(); HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType = GUID_NULL ) const throw(); void SetColorTable( UINT iFirstColor, UINT nColors, const RGBQUAD* prgbColors ) throw(); void SetPixel( int x, int y, COLORREF color ) throw(); void SetPixelIndexed( int x, int y, int iIndex ) throw(); void SetPixelRGB( int x, int y, BYTE r, BYTE g, BYTE b ) throw(); LONG SetTransparentColor( LONG iTransparentColor ) throw(); BOOL StretchBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, DWORD dwROP = SRCCOPY ) const throw(); BOOL StretchBlt( HDC hDestDC, const RECT& rectDest, DWORD dwROP = SRCCOPY ) const throw(); BOOL StretchBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwROP = SRCCOPY ) const throw(); BOOL StretchBlt( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, DWORD dwROP = SRCCOPY ) const throw(); #if WINVER >= 0x0500 BOOL TransparentBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, UINT crTransparent = CLR_INVALID ) const throw(); BOOL TransparentBlt( HDC hDestDC, const RECT& rectDest, UINT crTransparent = CLR_INVALID ) const throw(); BOOL TransparentBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent = CLR_INVALID ) const throw(); BOOL TransparentBlt( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, UINT crTransparent = CLR_INVALID ) const throw(); #endif // WINVER >= 0x0500 static BOOL IsTransparencySupported() throw(); private: HBITMAP m_hBitmap; void* m_pBits; int m_nWidth; int m_nHeight; int m_nPitch; int m_nBPP; bool m_bIsDIBSection; bool m_bHasAlphaChannel; LONG m_iTransparentColor; static CInitGDIPlus s_initGDIPlus; public: inline static void ReleaseGDIPlus() { s_initGDIPlus.ReleaseGDIPlus(); } // Implementation private: static CLSID FindCodecForExtension( LPCTSTR pszExtension, const Gdiplus::ImageCodecInfo* pCodecs, UINT nCodecs ); static CLSID FindCodecForFileType( REFGUID guidFileType, const Gdiplus::ImageCodecInfo* pCodecs, UINT nCodecs ); static void BuildCodecFilterString( const Gdiplus::ImageCodecInfo* pCodecs, UINT nCodecs, CSimpleString& strFilter, CSimpleArray< GUID >& aguidFileTypes, LPCTSTR pszAllFilesDescription, DWORD dwExclude, TCHAR chSeparator ); static bool ShouldExcludeFormat( REFGUID guidFileType, DWORD dwExclude ) throw(); void UpdateBitmapInfo( DIBOrientation eOrientation ); HRESULT CreateFromGdiplusBitmap( Gdiplus::Bitmap& bmSrc ) throw(); static bool InitGDIPlus() throw(); static int ComputePitch( int nWidth, int nBPP ) { return( (((nWidth*nBPP)+31)/32)*4 ); } static void GenerateHalftonePalette( LPRGBQUAD prgbPalette ); COLORREF GetTransparentRGB() const; private: mutable HDC m_hDC; mutable int m_nDCRefCount; mutable HBITMAP m_hOldBitmap; static CDCCache s_cache; }; #if _MSC_VER >= 1300 __declspec(selectany) CImage::CInitGDIPlus CImage::s_initGDIPlus; __declspec(selectany) CImage::CDCCache CImage::s_cache; #else #ifndef __VC6_ATL_IMAGE_H__ #error "please define __VC6_ATL_IMAGE_H__ flag in stdafx.h file's begin and following..." #endif // add the following 4 lines to stdafx.cpp file // // #if _MSC_VER < 1300 // CImage::CInitGDIPlus CImage::s_initGDIPlus; // CImage::CDCCache CImage::s_cache; // #endif // #endif __declspec(selectany) const DWORD CImage::createAlphaChannel = 0x01; __declspec(selectany) const DWORD CImage::excludeGIF = 0x01; __declspec(selectany) const DWORD CImage::excludeBMP = 0x02; __declspec(selectany) const DWORD CImage::excludeEMF = 0x04; __declspec(selectany) const DWORD CImage::excludeWMF = 0x08; __declspec(selectany) const DWORD CImage::excludeJPEG = 0x10; __declspec(selectany) const DWORD CImage::excludePNG = 0x20; __declspec(selectany) const DWORD CImage::excludeTIFF = 0x40; __declspec(selectany) const DWORD CImage::excludeIcon = 0x80; __declspec(selectany) const DWORD CImage::excludeOther = 0x80000000; __declspec(selectany) const DWORD CImage::excludeDefaultLoad = 0; __declspec(selectany) const DWORD CImage::excludeDefaultSave = CImage::excludeIcon|CImage::excludeEMF|CImage::excludeWMF; __declspec(selectany) const DWORD CImage::excludeValid = 0x800000ff; inline CImageDC::CImageDC( const CImage& image ) throw( ) : m_image( image ) , m_hDC( image.GetDC() ) { if( m_hDC == NULL ) { ATLASSERT(FALSE); // AtlThrow( E_OUTOFMEMORY ); } } inline CImageDC::~CImageDC() throw() { m_image.ReleaseDC(); } inline CImageDC::operator HDC() const throw() { return( m_hDC ); } inline CImage::CInitGDIPlus::CInitGDIPlus() throw() : m_dwToken( 0 ), m_nCImageObjects( 0 ) { __try { InitializeCriticalSection(&m_sect); } __except( STATUS_NO_MEMORY == GetExceptionCode() ) { ATLASSERT(FALSE); // AtlThrow( E_OUTOFMEMORY ); } } inline CImage::CInitGDIPlus::~CInitGDIPlus() throw() { ReleaseGDIPlus(); DeleteCriticalSection(&m_sect); } 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 ); if( status != Gdiplus::Ok ) fRet = false; } LeaveCriticalSection(&m_sect); return fRet; } inline void CImage::CInitGDIPlus::ReleaseGDIPlus() throw() { EnterCriticalSection(&m_sect); if( m_dwToken != 0 ) { Gdiplus::GdiplusShutdown( m_dwToken ); } m_dwToken = 0; LeaveCriticalSection(&m_sect); } inline void CImage::CInitGDIPlus::IncreaseCImageCount() throw() { EnterCriticalSection(&m_sect); m_nCImageObjects++; LeaveCriticalSection(&m_sect); } inline void CImage::CInitGDIPlus::DecreaseCImageCount() throw() { EnterCriticalSection(&m_sect); if( --m_nCImageObjects == 0 ) ReleaseGDIPlus(); LeaveCriticalSection(&m_sect); } inline CImage::CDCCache::CDCCache() throw() { int iDC; for( iDC = 0; iDC < CIMAGE_DC_CACHE_SIZE; iDC++ ) { m_ahDCs[iDC] = NULL; } } inline CImage::CDCCache::~CDCCache() throw() { int iDC; for( iDC = 0; iDC < CIMAGE_DC_CACHE_SIZE; iDC++ ) { if( m_ahDCs[iDC] != NULL ) { ::DeleteDC( m_ahDCs[iDC] ); } } } inline HDC CImage::CDCCache::GetDC() throw() { HDC hDC; for( int iDC = 0; iDC < CIMAGE_DC_CACHE_SIZE; iDC++ ) { hDC = static_cast< HDC >( InterlockedExchangePointer( reinterpret_cast< void** >(&m_ahDCs[iDC]), NULL ) ); if( hDC != NULL ) { return( hDC ); } } hDC = ::CreateCompatibleDC( NULL ); return( hDC ); } inline void CImage::CDCCache::ReleaseDC( HDC hDC ) throw() { for( int iDC = 0; iDC < CIMAGE_DC_CACHE_SIZE; iDC++ ) { HDC hOldDC; hOldDC = static_cast< HDC >( InterlockedExchangePointer( reinterpret_cast< void** >(&m_ahDCs[iDC]), hDC ) ); if( hOldDC == NULL ) { return; } else { hDC = hOldDC; } } if( hDC != NULL ) { ::DeleteDC( hDC ); } } 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 CImage::~CImage() throw() { Destroy(); s_initGDIPlus.DecreaseCImageCount(); } inline CImage::operator HBITMAP() const throw() { return( m_hBitmap ); } #if WINVER >= 0x0500 inline BOOL CImage::AlphaBlend( HDC hDestDC, int xDest, int yDest, BYTE bSrcAlpha, BYTE bBlendOp ) const throw() { return( AlphaBlend( hDestDC, xDest, yDest, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight, bSrcAlpha, bBlendOp ) ); } inline BOOL CImage::AlphaBlend( HDC hDestDC, const POINT& pointDest, BYTE bSrcAlpha, BYTE bBlendOp ) const throw() { return( AlphaBlend( hDestDC, pointDest.x, pointDest.y, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight, bSrcAlpha, bBlendOp ) ); } inline BOOL CImage::AlphaBlend( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, BYTE bSrcAlpha, BYTE bBlendOp ) const throw() { BLENDFUNCTION blend; BOOL bResult; blend.SourceConstantAlpha = bSrcAlpha; blend.BlendOp = bBlendOp; blend.BlendFlags = 0; if( m_bHasAlphaChannel ) { blend.AlphaFormat = AC_SRC_ALPHA; } else { blend.AlphaFormat = 0; } GetDC(); bResult = ::AlphaBlend( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, blend ); ReleaseDC(); return( bResult ); } inline BOOL CImage::AlphaBlend( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, BYTE bSrcAlpha, BYTE bBlendOp ) const throw() { return( AlphaBlend( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, rectSrc.left, rectSrc.top, rectSrc.right-rectSrc.left, rectSrc.bottom-rectSrc.top, bSrcAlpha, bBlendOp ) ); } #endif // WINVER >= 0x0500 inline void CImage::Attach( HBITMAP hBitmap, DIBOrientation eOrientation ) throw() { ATLASSERT( m_hBitmap == NULL ); // ATLASSUME( m_hBitmap == NULL ); ATLASSERT( hBitmap != NULL ); m_hBitmap = hBitmap; UpdateBitmapInfo( eOrientation ); } inline BOOL CImage::BitBlt( HDC hDestDC, int xDest, int yDest, DWORD dwROP ) const throw() { return( BitBlt( hDestDC, xDest, yDest, m_nWidth, m_nHeight, 0, 0, dwROP ) ); } inline BOOL CImage::BitBlt( HDC hDestDC, const POINT& pointDest, DWORD dwROP ) const throw() { return( BitBlt( hDestDC, pointDest.x, pointDest.y, m_nWidth, m_nHeight, 0, 0, dwROP ) ); } inline BOOL CImage::BitBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, DWORD dwROP ) const throw() { BOOL bResult; ATLASSERT(m_hBitmap != NULL); // ATLASSUME( m_hBitmap != NULL ); ATLASSERT( hDestDC != NULL ); GetDC(); bResult = ::BitBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, dwROP ); ReleaseDC(); return( bResult ); } inline BOOL CImage::BitBlt( HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, DWORD dwROP ) const throw() { return( BitBlt( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, pointSrc.x, pointSrc.y, dwROP ) ); } inline BOOL CImage::Create( int nWidth, int nHeight, int nBPP, DWORD dwFlags ) throw() { return( CreateEx( nWidth, nHeight, nBPP, BI_RGB, NULL, dwFlags ) ); } inline BOOL CImage::CreateEx( int nWidth, int nHeight, int nBPP, DWORD eCompression, const DWORD* pdwBitfields, DWORD dwFlags ) throw() { // USES_ATL_SAFE_ALLOCA; LPBITMAPINFO pbmi = NULL; HBITMAP hBitmap = NULL; ATLASSERT( (eCompression == BI_RGB) || (eCompression == BI_BITFIELDS) ); if( dwFlags&createAlphaChannel ) { ATLASSERT( (nBPP == 32) && (eCompression == BI_RGB) ); } // pbmi = (LPBITMAPINFO)_ATL_SAFE_ALLOCA(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); pbmi = (LPBITMAPINFO) malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256); if( pbmi == NULL ) return FALSE; memset( &pbmi->bmiHeader, 0, sizeof( pbmi->bmiHeader ) ); pbmi->bmiHeader.biSize = sizeof( pbmi->bmiHeader ); pbmi->bmiHeader.biWidth = nWidth; pbmi->bmiHeader.biHeight = nHeight; pbmi->bmiHeader.biPlanes = 1; pbmi->bmiHeader.biBitCount = USHORT( nBPP ); pbmi->bmiHeader.biCompression = eCompression; if( nBPP <= 8 ) { ATLASSERT( eCompression == BI_RGB ); #pragma warning(push) #pragma warning(disable:4068) //Disable unknown pragma warning that prefast pragma causes. #pragma prefast(push) #pragma prefast(disable:203, "no buffer overrun here, buffer was alocated properly") memset( pbmi->bmiColors, 0, 256*sizeof( RGBQUAD ) ); #pragma prefast(pop) #pragma warning(pop) } else { if( eCompression == BI_BITFIELDS ) { ATLASSERT( pdwBitfields != NULL ); // Checked::memcpy_s(pbmi->bmiColors, 3*sizeof( DWORD ), pdwBitfields, 3*sizeof( DWORD )); memcpy(pbmi->bmiColors, pdwBitfields, 3*sizeof( DWORD )); } } hBitmap = ::CreateDIBSection( NULL, pbmi, DIB_RGB_COLORS, &m_pBits, NULL, 0 ); if( hBitmap == NULL ) { return( FALSE ); } Attach( hBitmap, (nHeight < 0) ? DIBOR_TOPDOWN : DIBOR_BOTTOMUP ); if( dwFlags&createAlphaChannel ) { m_bHasAlphaChannel = true; } free(pbmi); return( TRUE ); } inline void CImage::Destroy() throw() { HBITMAP hBitmap; if( m_hBitmap != NULL ) { hBitmap = Detach(); ::DeleteObject( hBitmap ); } } inline HBITMAP CImage::Detach() throw() { HBITMAP hBitmap; ATLASSERT( m_hBitmap != NULL ); // ATLASSUME( m_hBitmap != NULL ); ATLASSERT( m_hDC == NULL ); // ATLASSUME( m_hDC == NULL ); hBitmap = m_hBitmap; m_hBitmap = NULL; m_pBits = NULL; m_nWidth = 0; m_nHeight = 0; m_nBPP = 0; m_nPitch = 0; m_iTransparentColor = -1; m_bHasAlphaChannel = false; m_bIsDIBSection = false; return( hBitmap ); } inline BOOL CImage::Draw( HDC hDestDC, const RECT& rectDest ) const throw() { return( Draw( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, 0, 0, m_nWidth, m_nHeight ) ); } inline BOOL CImage::Draw( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight ) const throw() { return( Draw( hDestDC, xDest, yDest, nDestWidth, nDestHeight, 0, 0, m_nWidth, m_nHeight ) ); } inline BOOL CImage::Draw( HDC hDestDC, const POINT& pointDest ) const throw() { return( Draw( hDestDC, pointDest.x, pointDest.y, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight ) ); } inline BOOL CImage::Draw( HDC hDestDC, int xDest, int yDest ) const throw() { return( Draw( hDestDC, xDest, yDest, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight ) ); } inline BOOL CImage::Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc ) const throw() { return( Draw( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, rectSrc.left, rectSrc.top, rectSrc.right-rectSrc.left, rectSrc.bottom-rectSrc.top ) ); } inline BOOL CImage::Draw( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight ) const throw() { BOOL bResult; ATLASSERT( m_hBitmap != NULL ); // ATLASSUME( m_hBitmap != NULL ); ATLASSERT( hDestDC != NULL ); ATLASSERT( nDestWidth > 0 ); ATLASSERT( nDestHeight > 0 ); ATLASSERT( nSrcWidth > 0 ); ATLASSERT( nSrcHeight > 0 ); GetDC(); #if WINVER >= 0x0500 if( (m_iTransparentColor != -1) && IsTransparencySupported() ) { bResult = ::TransparentBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, GetTransparentRGB() ); } else if( m_bHasAlphaChannel && IsTransparencySupported() ) { BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = 0xff; bf.AlphaFormat = AC_SRC_ALPHA; bResult = ::AlphaBlend( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, bf ); } else #endif // WINVER >= 0x0500 { bResult = ::StretchBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, SRCCOPY ); } ReleaseDC(); return( bResult ); } inline const void* CImage::GetBits() const throw() { ATLASSERT( m_hBitmap != NULL ); // ATLASSUME( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); return( m_pBits ); } inline void* CImage::GetBits() throw() { ATLASSERT(m_hBitmap != NULL); // ATLASSUME( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); return( m_pBits ); } inline int CImage::GetBPP() const throw() { ATLASSERT( m_hBitmap != NULL ); return( m_nBPP ); } inline void CImage::GetColorTable( UINT iFirstColor, UINT nColors, RGBQUAD* prgbColors ) const throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( m_pBits != NULL ); ATLASSERT( IsIndexed() ); GetDC(); ::GetDIBColorTable( m_hDC, iFirstColor, nColors, prgbColors ); ReleaseDC(); } inline HDC CImage::GetDC() const throw() { ATLASSERT( m_hBitmap != NULL ); m_nDCRefCount++; if( m_hDC == NULL ) { m_hDC = s_cache.GetDC(); m_hOldBitmap = HBITMAP( ::SelectObject( m_hDC, m_hBitmap ) ); } return( m_hDC ); } inline bool CImage::ShouldExcludeFormat( REFGUID guidFileType, DWORD dwExclude ) throw() { static const GUID* apguidFormats[] = { &Gdiplus::ImageFormatGIF, &Gdiplus::ImageFormatBMP, &Gdiplus::ImageFormatEMF, &Gdiplus::ImageFormatWMF, &Gdiplus::ImageFormatJPEG, &Gdiplus::ImageFormatPNG, &Gdiplus::ImageFormatTIFF, &Gdiplus::ImageFormatIcon, NULL }; ATLASSERT( (dwExclude|excludeValid) == excludeValid ); for( int iFormat = 0; apguidFormats[iFormat] != NULL; iFormat++ ) { if( guidFileType == *apguidFormats[iFormat] ) { return( (dwExclude&(1<& aguidFileTypes, LPCTSTR pszAllFilesDescription, DWORD dwExclude, TCHAR chSeparator ) { USES_CONVERSION; if( pszAllFilesDescription != NULL ) { aguidFileTypes.Add( const_cast(GUID_NULL) ); } CString strAllExtensions; CString strTempFilter; for( UINT iCodec = 0; iCodec < nCodecs; iCodec++ ) { const Gdiplus::ImageCodecInfo* pCodec = &pCodecs[iCodec]; if( !ShouldExcludeFormat( pCodec->FormatID, dwExclude ) ) { CString pwszFilenameExtension( W2CT(pCodec->FilenameExtension) ); strTempFilter += W2CT( pCodec->FormatDescription ); strTempFilter += _T( " (" ); strTempFilter += pwszFilenameExtension; strTempFilter += _T( ")" ); strTempFilter += chSeparator; strTempFilter += pwszFilenameExtension; strTempFilter += chSeparator; aguidFileTypes.Add( const_cast(pCodec->FormatID) ); if( !strAllExtensions.IsEmpty() ) { strAllExtensions += _T( ";" ); } strAllExtensions += pwszFilenameExtension; } } if( pszAllFilesDescription != NULL ) { strFilter += pszAllFilesDescription; strFilter += chSeparator; strFilter += strAllExtensions; strFilter += chSeparator; } strFilter += strTempFilter; strFilter += chSeparator; if( aguidFileTypes.GetSize() == 0 ) { strFilter += chSeparator; } } 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 = NULL; status = Gdiplus::GetImageDecodersSize( &nCodecs, &nSize ); // USES_ATL_SAFE_ALLOCA; // pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) ); pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( malloc(nSize) ); if( pCodecs == NULL ) return E_OUTOFMEMORY; status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs ); BuildCodecFilterString( pCodecs, nCodecs, strImporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator ); free(pCodecs); 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) ); pCodecs = static_cast< Gdiplus::ImageCodecInfo* >( malloc(nSize) ); if( pCodecs == NULL ) return E_OUTOFMEMORY; status = Gdiplus::GetImageDecoders( nCodecs, nSize, pCodecs ); BuildCodecFilterString( pCodecs, nCodecs, strExporters, aguidFileTypes, pszAllFilesDescription, dwExclude, chSeparator ); free(pCodecs); return( S_OK ); } inline int CImage::GetHeight() const throw() { ATLASSERT( m_hBitmap != NULL ); return( m_nHeight ); } inline int CImage::GetMaxColorTableEntries() const throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); if( IsIndexed() ) { return( 1<= 0) && (x < m_nWidth) ); ATLASSERT( (y >= 0) && (y < m_nHeight) ); GetDC(); COLORREF clr = ::GetPixel( m_hDC, x, y ); ReleaseDC(); return( clr ); } inline const void* CImage::GetPixelAddress( int x, int y ) const throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); ATLASSERT( (x >= 0) && (x < m_nWidth) ); ATLASSERT( (y >= 0) && (y < m_nHeight) ); return( LPBYTE( m_pBits )+(y*m_nPitch)+((x*m_nBPP)/8) ); } inline void* CImage::GetPixelAddress( int x, int y ) throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); ATLASSERT( (x >= 0) && (x < m_nWidth) ); ATLASSERT( (y >= 0) && (y < m_nHeight) ); return( LPBYTE( m_pBits )+(y*m_nPitch)+((x*m_nBPP)/8) ); } inline LONG CImage::GetTransparentColor() const throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( (m_nBPP == 4) || (m_nBPP == 8) ); return( m_iTransparentColor ); } inline int CImage::GetWidth() const throw() { ATLASSERT( m_hBitmap != NULL ); return( m_nWidth ); } inline bool CImage::IsDIBSection() const throw() { return( m_bIsDIBSection ); } inline bool CImage::IsIndexed() const throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); return( m_nBPP <= 8 ); } inline bool CImage::IsNull() const throw() { return( m_hBitmap == NULL ); } 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() { USES_CONVERSION; if( !InitGDIPlus() ) { return( E_FAIL ); } Gdiplus::Bitmap bmSrc( T2CW(pszFileName) ); if( bmSrc.GetLastStatus() != Gdiplus::Ok ) { return( E_FAIL ); } return( CreateFromGdiplusBitmap( bmSrc ) ); } inline HRESULT CImage::CreateFromGdiplusBitmap( Gdiplus::Bitmap& bmSrc ) throw() { Gdiplus::PixelFormat eSrcPixelFormat = bmSrc.GetPixelFormat(); UINT nBPP = 32; DWORD dwFlags = 0; Gdiplus::PixelFormat eDestPixelFormat = PixelFormat32bppRGB; if( eSrcPixelFormat&PixelFormatGDI ) { nBPP = Gdiplus::GetPixelFormatSize( eSrcPixelFormat ); eDestPixelFormat = eSrcPixelFormat; } if( Gdiplus::IsAlphaPixelFormat( eSrcPixelFormat ) ) { nBPP = 32; dwFlags |= createAlphaChannel; eDestPixelFormat = PixelFormat32bppARGB; } BOOL bSuccess = Create( bmSrc.GetWidth(), bmSrc.GetHeight(), nBPP, dwFlags ); if( !bSuccess ) { return( E_FAIL ); } // USES_ATL_SAFE_ALLOCA; Gdiplus::ColorPalette* pPalette = NULL; if( Gdiplus::IsIndexedPixelFormat( eSrcPixelFormat ) ) { UINT nPaletteSize = bmSrc.GetPaletteSize(); // pPalette = static_cast< Gdiplus::ColorPalette* >( _ATL_SAFE_ALLOCA(nPaletteSize, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) ); pPalette = static_cast< Gdiplus::ColorPalette* >( malloc(nPaletteSize) ); if( pPalette == NULL ) return E_OUTOFMEMORY; bmSrc.GetPalette( pPalette, nPaletteSize ); RGBQUAD argbPalette[256]; ATLASSERT( (pPalette->Count > 0) && (pPalette->Count <= 256) ); for( UINT iColor = 0; iColor < pPalette->Count; iColor++ ) { Gdiplus::ARGB color = pPalette->Entries[iColor]; argbPalette[iColor].rgbRed = (BYTE)( (color>>RED_SHIFT) & 0xff ); argbPalette[iColor].rgbGreen = (BYTE)( (color>>GREEN_SHIFT) & 0xff ); argbPalette[iColor].rgbBlue = (BYTE)( (color>>BLUE_SHIFT) & 0xff ); argbPalette[iColor].rgbReserved = 0; } SetColorTable( 0, pPalette->Count, argbPalette ); } if( eDestPixelFormat == eSrcPixelFormat ) { // The pixel formats are identical, so just memcpy the rows. Gdiplus::BitmapData data; Gdiplus::Rect rect( 0, 0, GetWidth(), GetHeight() ); if(bmSrc.LockBits( &rect, Gdiplus::ImageLockModeRead, eSrcPixelFormat, &data )!=Gdiplus::Ok) { return E_OUTOFMEMORY; } size_t nBytesPerRow = _AtlAlignUp( nBPP*GetWidth(), 8 )/8; BYTE* pbDestRow = static_cast< BYTE* >( GetBits() ); BYTE* pbSrcRow = static_cast< BYTE* >( data.Scan0 ); for( int y = 0; y < GetHeight(); y++ ) { memcpy(pbDestRow, pbSrcRow, nBytesPerRow); pbDestRow += GetPitch(); pbSrcRow += data.Stride; } bmSrc.UnlockBits( &data ); } else { // Let GDI+ work its magic Gdiplus::Bitmap bmDest( GetWidth(), GetHeight(), GetPitch(), eDestPixelFormat, static_cast< BYTE* >( GetBits() ) ); Gdiplus::Graphics gDest( &bmDest ); gDest.DrawImage( &bmSrc, 0, 0 ); } free(pPalette); return( S_OK ); } inline void CImage::LoadFromResource( HINSTANCE hInstance, LPCTSTR pszResourceName ) throw() { HBITMAP hBitmap; hBitmap = HBITMAP( ::LoadImage( hInstance, pszResourceName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ) ); Attach( hBitmap ); } inline void CImage::LoadFromResource( HINSTANCE hInstance, UINT nIDResource ) throw() { LoadFromResource( hInstance, MAKEINTRESOURCE( nIDResource ) ); } inline BOOL CImage::MaskBlt( HDC hDestDC, int xDest, int yDest, int nWidth, int nHeight, int xSrc, int ySrc, HBITMAP hbmMask, int xMask, int yMask, DWORD dwROP ) const throw() { BOOL bResult; ATLASSERT( m_hBitmap != NULL ); ATLASSERT( hDestDC != NULL ); GetDC(); bResult = ::MaskBlt( hDestDC, xDest, yDest, nWidth, nHeight, m_hDC, xSrc, ySrc, hbmMask, xMask, yMask, dwROP ); ReleaseDC(); return( bResult ); } inline BOOL CImage::MaskBlt( HDC hDestDC, const RECT& rectDest, const POINT& pointSrc, HBITMAP hbmMask, const POINT& pointMask, DWORD dwROP ) const throw() { return( MaskBlt( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, pointSrc.x, pointSrc.y, hbmMask, pointMask.x, pointMask.y, dwROP ) ); } inline BOOL CImage::MaskBlt( HDC hDestDC, int xDest, int yDest, HBITMAP hbmMask, DWORD dwROP ) const throw() { return( MaskBlt( hDestDC, xDest, yDest, m_nWidth, m_nHeight, 0, 0, hbmMask, 0, 0, dwROP ) ); } inline BOOL CImage::MaskBlt( HDC hDestDC, const POINT& pointDest, HBITMAP hbmMask, DWORD dwROP ) const throw() { return( MaskBlt( hDestDC, pointDest.x, pointDest.y, m_nWidth, m_nHeight, 0, 0, hbmMask, 0, 0, dwROP ) ); } inline BOOL CImage::PlgBlt( HDC hDestDC, const POINT* pPoints, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, HBITMAP hbmMask, int xMask, int yMask ) const throw() { BOOL bResult; ATLASSERT( m_hBitmap != NULL ); ATLASSERT( hDestDC != NULL ); GetDC(); bResult = ::PlgBlt( hDestDC, pPoints, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, hbmMask, xMask, yMask ); ReleaseDC(); return( bResult ); } inline BOOL CImage::PlgBlt( HDC hDestDC, const POINT* pPoints, const RECT& rectSrc, HBITMAP hbmMask, const POINT& pointMask ) const throw() { return( PlgBlt( hDestDC, pPoints, rectSrc.left, rectSrc.top, rectSrc.right- rectSrc.left, rectSrc.bottom-rectSrc.top, hbmMask, pointMask.x, pointMask.y ) ); } inline BOOL CImage::PlgBlt( HDC hDestDC, const POINT* pPoints, HBITMAP hbmMask ) const throw() { return( PlgBlt( hDestDC, pPoints, 0, 0, m_nWidth, m_nHeight, hbmMask, 0, 0 ) ); } inline void CImage::ReleaseDC() const throw() { HBITMAP hBitmap; ATLASSERT( m_hDC != NULL ); m_nDCRefCount--; if( m_nDCRefCount == 0 ) { hBitmap = HBITMAP( ::SelectObject( m_hDC, m_hOldBitmap ) ); ATLASSERT( hBitmap == m_hBitmap ); s_cache.ReleaseDC( m_hDC ); m_hDC = NULL; } } inline CLSID CImage::FindCodecForExtension( LPCTSTR pszExtension, const Gdiplus::ImageCodecInfo* pCodecs, UINT nCodecs ) { USES_CONVERSION; WCHAR szExt[MAX_PATH] = { 0 }; lstrcpynW(szExt, T2CW(pszExtension), MAX_PATH); WCHAR szExtensions[MAX_PATH*4] = { 0 }; for( UINT iCodec = 0; iCodec < nCodecs; iCodec++ ) { lstrcpynW(szExtensions, pCodecs[iCodec].FilenameExtension, MAX_PATH*4); WCHAR * pEnd = szExtensions + lstrlenW(szExtensions); WCHAR * pIter = szExtensions; do { WCHAR * pToken = wcschr(pIter, L';'); if (pToken) { *pToken = '/0'; pToken ++; } WCHAR * strExtension = ::PathFindExtensionW(pIter); if (strExtension) { if (lstrcmpiW(szExt, strExtension) == 0) { return( pCodecs[iCodec].Clsid ); } } if (pToken) { pIter = pToken; } else { pIter += lstrlenW(pIter); } } while( pIter < pEnd ); } return( CLSID_NULL ); } inline CLSID CImage::FindCodecForFileType( REFGUID guidFileType, const Gdiplus::ImageCodecInfo* pCodecs, UINT nCodecs ) { for( UINT iCodec = 0; iCodec < nCodecs; iCodec++ ) { if( pCodecs[iCodec].FormatID == guidFileType ) { return( pCodecs[iCodec].Clsid ); } } return( CLSID_NULL ); } 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) ); Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( malloc(nBytes) ); 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 ) { ATLASSERT( 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 ); } } free(pEncoders); 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; // Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) ); Gdiplus::ImageCodecInfo* pEncoders = static_cast< Gdiplus::ImageCodecInfo* >( malloc(nBytes) ); 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 ); LPCWSTR pwszFileName = T2CW( pszFileName ); #ifndef _UNICODE if( pwszFileName == NULL ) return E_OUTOFMEMORY; #endif // _UNICODE if( m_bHasAlphaChannel ) { ATLASSERT( 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 ); } } free(pEncoders); return( S_OK ); } inline void CImage::SetColorTable( UINT iFirstColor, UINT nColors, const RGBQUAD* prgbColors ) throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( IsDIBSection() ); ATLASSERT( IsIndexed() ); GetDC(); ::SetDIBColorTable( m_hDC, iFirstColor, nColors, prgbColors ); ReleaseDC(); } inline void CImage::SetPixel( int x, int y, COLORREF color ) throw() { ATLASSERT( m_hBitmap != NULL ); ATLASSERT( (x >= 0) && (x < m_nWidth) ); ATLASSERT( (y >= 0) && (y < m_nHeight) ); GetDC(); ::SetPixel( m_hDC, x, y, color ); ReleaseDC(); } inline void CImage::SetPixelIndexed( int x, int y, int iIndex ) throw() { SetPixel( x, y, PALETTEINDEX( iIndex ) ); } inline void CImage::SetPixelRGB( int x, int y, BYTE r, BYTE g, BYTE b ) throw() { SetPixel( x, y, RGB( r, g, b ) ); } inline LONG CImage::SetTransparentColor( LONG iTransparentColor ) throw() { LONG iOldTransparentColor; ATLASSERT( m_hBitmap != NULL ); ATLASSERT( (m_nBPP == 4) || (m_nBPP == 8) ); ATLASSERT( iTransparentColor < GetMaxColorTableEntries() ); ATLASSERT( iTransparentColor >= -1 ); iOldTransparentColor = m_iTransparentColor; m_iTransparentColor = iTransparentColor; return( iOldTransparentColor ); } inline BOOL CImage::StretchBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, DWORD dwROP ) const throw() { return( StretchBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, 0, 0, m_nWidth, m_nHeight, dwROP ) ); } inline BOOL CImage::StretchBlt( HDC hDestDC, const RECT& rectDest, DWORD dwROP ) const throw() { return( StretchBlt( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, 0, 0, m_nWidth, m_nHeight, dwROP ) ); } inline BOOL CImage::StretchBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwROP ) const throw() { BOOL bResult; ATLASSERT( m_hBitmap != NULL ); ATLASSERT( hDestDC != NULL ); GetDC(); bResult = ::StretchBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, dwROP ); ReleaseDC(); return( bResult ); } inline BOOL CImage::StretchBlt( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, DWORD dwROP ) const throw() { return( StretchBlt( hDestDC, rectDest.left, rectDest.top, rectDest.right- rectDest.left, rectDest.bottom-rectDest.top, rectSrc.left, rectSrc.top, rectSrc.right-rectSrc.left, rectSrc.bottom-rectSrc.top, dwROP ) ); } #if WINVER >= 0x0500 inline BOOL CImage::TransparentBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, UINT crTransparent ) const throw() { return( TransparentBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, 0, 0, m_nWidth, m_nHeight, crTransparent ) ); } inline BOOL CImage::TransparentBlt( HDC hDestDC, const RECT& rectDest, UINT crTransparent ) const throw() { return( TransparentBlt( hDestDC, rectDest.left, rectDest.top, rectDest.right-rectDest.left, rectDest.bottom-rectDest.top, crTransparent ) ); } inline BOOL CImage::TransparentBlt( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, UINT crTransparent ) const throw() { BOOL bResult; ATLASSERT( m_hBitmap != NULL ); ATLASSERT( hDestDC != NULL ); GetDC(); if( crTransparent == CLR_INVALID ) { crTransparent = GetTransparentRGB(); } bResult = ::TransparentBlt( hDestDC, xDest, yDest, nDestWidth, nDestHeight, m_hDC, xSrc, ySrc, nSrcWidth, nSrcHeight, crTransparent ); ReleaseDC(); return( bResult ); } inline BOOL CImage::TransparentBlt( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc, UINT crTransparent ) const throw() { return( TransparentBlt( hDestDC, rectDest.left, rectDest.top, rectDest.right-rectDest.left, rectDest.bottom-rectDest.top, rectSrc.left, rectSrc.top, rectSrc.right-rectSrc.left, rectSrc.bottom-rectSrc.top, crTransparent ) ); } #endif // WINVER >= 0x0500 inline BOOL CImage::IsTransparencySupported() throw() { return( TRUE ); } inline void CImage::UpdateBitmapInfo( DIBOrientation eOrientation ) { DIBSECTION dibsection; int nBytes; nBytes = ::GetObject( m_hBitmap, sizeof( DIBSECTION ), &dibsection ); if( nBytes == sizeof( DIBSECTION ) ) { m_bIsDIBSection = true; m_nWidth = dibsection.dsBmih.biWidth; m_nHeight = abs( dibsection.dsBmih.biHeight ); m_nBPP = dibsection.dsBmih.biBitCount; m_nPitch = ComputePitch( m_nWidth, m_nBPP ); m_pBits = dibsection.dsBm.bmBits; if( eOrientation == DIBOR_DEFAULT ) { eOrientation = (dibsection.dsBmih.biHeight > 0) ? DIBOR_BOTTOMUP : DIBOR_TOPDOWN; } if( eOrientation == DIBOR_BOTTOMUP ) { m_pBits = LPBYTE( m_pBits )+((m_nHeight-1)*m_nPitch); m_nPitch = -m_nPitch; } } else { // Non-DIBSection ATLASSERT( nBytes == sizeof( BITMAP ) ); m_bIsDIBSection = false; m_nWidth = dibsection.dsBm.bmWidth; m_nHeight = dibsection.dsBm.bmHeight; m_nBPP = dibsection.dsBm.bmBitsPixel; m_nPitch = 0; m_pBits = 0; } m_iTransparentColor = -1; m_bHasAlphaChannel = false; } inline void CImage::GenerateHalftonePalette( LPRGBQUAD prgbPalette ) { int r; int g; int b; int gray; LPRGBQUAD prgbEntry; prgbEntry = prgbPalette; for( r = 0; r < 6; r++ ) { for( g = 0; g < 6; g++ ) { for( b = 0; b < 6; b++ ) { prgbEntry->rgbBlue = BYTE( b*255/5 ); prgbEntry->rgbGreen = BYTE( g*255/5 ); prgbEntry->rgbRed = BYTE( r*255/5 ); prgbEntry->rgbReserved = 0; prgbEntry++; } } } for( gray = 0; gray < 20; gray++ ) { prgbEntry->rgbBlue = BYTE( gray*255/20 ); prgbEntry->rgbGreen = BYTE( gray*255/20 ); prgbEntry->rgbRed = BYTE( gray*255/20 ); prgbEntry->rgbReserved = 0; prgbEntry++; } } inline COLORREF CImage::GetTransparentRGB() const { RGBQUAD rgb; ATLASSERT( m_hDC != NULL ); // Must have a DC ATLASSERT( m_iTransparentColor != -1 ); ::GetDIBColorTable( m_hDC, m_iTransparentColor, 1, &rgb ); return( RGB( rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue ) ); } inline bool CImage::InitGDIPlus() throw() { bool bSuccess = s_initGDIPlus.Init(); return( bSuccess ); } }; // namespace ATL #pragma pack(pop) #ifndef _ATL_NO_PRAGMA_WARNINGS #pragma warning (pop) #endif #endif // __ATLIMAGE_H__