在做界面時候,經常需要通過加載圖片來達到美化的效果,畢竟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;
}
}
這兩個類的具體使用就比較簡單了,只是爲多個格式提供了一些便捷性。