为了比较小的资源占用和比较快速的贴图速度,使用BitBlt自然是最佳方式,这是为数不多的软渲染GDI APIs里面有硬件加速的API之一,以前看到国外测试速度,不同的硬件下BitBlt比Graphics::DrawImage快100-1w倍,测试很简单就不说了,直接贴图100w张比执行时间。
为了使用BitBlt,需要HBITMAP数据,初始化CImage后调用CImage::Detach可以直接获得,该HBITMAP是DIBSECTION类型,各数据跟CImage一致,后面的Bitmap就出问题了。
CImage::Load
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 ) );
}
CImage::Detach不再释放内部HBITMAP
inline HBITMAP CImage::Detach() throw()
{
HBITMAP hBitmap;
ATLASSUME( m_hBitmap != 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 );
}
CImage::LoadFromResource 使用仅支持bmp的API
inline void CImage::LoadFromResource( HINSTANCE hInstance, LPCTSTR pszResourceName ) throw()
{
HBITMAP hBitmap;
hBitmap = HBITMAP( ::LoadImage( hInstance, pszResourceName, IMAGE_BITMAP, 0,
0, LR_CREATEDIBSECTION ) );
Attach( hBitmap );
}
CImage从资源载入图片,只能识别.bmp文件,其他文件将初始化失败导致断言失败ATLASSERT(m_hBitmap != 0),从文件路径载入调用Gdiplus::Bitmap,看来这个CImage只是对GDI+的轻量封装,贴图封装的是::BitBlt和::AlphaBlend。
GDI+全部操作都是自己实现。
Bitmap::FromResource
inline Bitmap::Bitmap(
IN HINSTANCE hInstance,
IN const WCHAR *bitmapName
)
{
GpBitmap *bitmap = NULL;
lastResult = DllExports::GdipCreateBitmapFromResource(hInstance,
bitmapName,
&bitmap);
SetNativeImage(bitmap);
}
Bitmap::FromFile
inline Bitmap::Bitmap(
IN const WCHAR *filename,
IN BOOL useEmbeddedColorManagement
)
{
GpBitmap *bitmap = NULL;
if(useEmbeddedColorManagement)
{
lastResult = DllExports::GdipCreateBitmapFromFileICM(filename, &bitmap);
}
else
{
lastResult = DllExports::GdipCreateBitmapFromFile(filename, &bitmap);
}
SetNativeImage(bitmap);
}
Bitmap是自力更生,从Bitmap::GetHBITMAP貌似性能比调用Bitmap的CImage高,但是GetHBITMAP第一个参数要求Gdiplus::Color,GDI+的Color是32位的,所以这个将导致最后的HBITMAP变成32位,::GetObject DIBSECTION BITMAPINFOHEADER biBitCount可以看到,因此可以断定其内部实现:创建内存兼容DC和32位图,再BitBlt。所以用CImage::Detach获得HBITMAP是最好的,源码中找不到这个m_hBitmap怎么初始化的,不然可以不用构造CImage对象了。
2011.12.9 找到CImage得到HBITMAP的方法:
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;
}