CImage/CPngImage的使用

在做界面時候,經常需要通過加載圖片來達到美化的效果,畢竟PS還是更專業些。但是VS對於圖片格式的支持還是麼有那麼好,導入資源中會有格式限制。以前用CxImage類做相關的轉換,但是那個是在VC6上弄得,現在項目改成VS2010,發現MFC中已經有了對相關內容支持的CImage/CPngImage類。

由於我這裏常用到Load(file),仔細的看了下相關的實現細節,其主要實現是依靠Gdiplus來實現的。裏面也間接演示了圖像數據創建Bitmap,有興趣的可以研究下。


inline HRESULT CImage::Load(_In_z_ 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::CreateFromGdiplusBitmap(_Inout_ 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) );

		if( pPalette == NULL )
			return E_OUTOFMEMORY;

		bmSrc.GetPalette( pPalette, nPaletteSize );

		RGBQUAD argbPalette[256];
		ATLENSURE_RETURN( (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++ )
		{
			Checked::memcpy_s(pbDestRow, nBytesPerRow, 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 );
	}

	return( S_OK );
}

這個有了HBITMAP,其他操作都可以參考着位圖來了。

CPngImage類從名字都能看出是一個處理PNG格式圖片的類。但是這個類很奇怪,他派生自CBitmap,但是它有包含一個靜態的CImage對象。代碼中可以看出來,它的加載基本通過靜態Image對象來實現,但是方法基本繼承自CBitmap。這個也爲CImage的使用提供了一個參考,只是感覺藏的有點深。

class CPngImage : public CBitmap  
{
// Construction/Destruction
public:
	CPngImage();
	virtual ~CPngImage();

// Attributes:
protected:
	static ATL::CImage* m_pImage;

// Operations:
public:
	BOOL Load (UINT uiResID, HINSTANCE hinstRes = NULL);
	BOOL Load (LPCTSTR lpszResourceName, HINSTANCE hinstRes = NULL);

	BOOL LoadFromFile (LPCTSTR lpszPath);
	BOOL LoadFromBuffer (LPBYTE lpBuffer, UINT uiSize);

	static void __stdcall CleanUp ()
	{
		if (m_pImage != NULL)
		{
			delete m_pImage;
			m_pImage = NULL;
		}
	}

這兩個類的具體使用就比較簡單了,只是爲多個格式提供了一些便捷性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章