用 MFC 做 GDI 开发的朋友肯定熟悉 CBitmap 类,该类封装了 HBITMAP 对象,简化了关于 HBITMAP 的 API 操作,如 LoadBitmap 方法可直接加载资源中指定 ID 的图片,但是很多情况下我们需要从文件中加载图片, CBitmap 类就没有提供这样的方法了。
下面我总结几种我知道的从文 件加载图片的方法:
1. 使用 API 函数 LoadImage ,指定 LR_LOADFROMFILE 标志。如:
HBITMAP hBitmap = (HBITMAP ) ::LoadImage (NULL , strPath , IMAGE_BITMAP , 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE );
这种方式十分简洁,但是根据我的实验,此方法貌似只能加载 bmp格式的图片,对于jpg/png等格式都加载不了,真是郁闷。
2.利用COM,我前段时间在CodeGuru淘宝淘到这个方法,我把代 码整理了一下,如下所示:
HBITMAP LoadImageFromFile ( PCTSTR pszBitmapFile )
{
IPicture * pIPic ;
IStream * pStream = NULL ;
HGLOBAL hGlobal ;
void * pVoid ;
FILE *fp = NULL ;
fopen_s ( &fp , CT2A ( pszBitmapFile ),"rb" );
if ( fp == NULL )return NULL ;
fseek ( fp , 0, SEEK_END );
long lFS = ftell (fp );
fseek ( fp , 0, SEEK_SET );
hGlobal = GlobalAlloc ( GPTR , lFS );
if ( hGlobal == NULL )
{
fclose (fp );
return NULL ;
}
pVoid = (void *)hGlobal ;
fread ( pVoid , 1, lFS , fp );
fclose ( fp );
// Create an IStream so IPicture can
if ( FAILED ( CreateStreamOnHGlobal ( hGlobal ,FALSE ,&pStream ) ) )
{
GlobalFree (hGlobal );
return NULL ;
}
HRESULT hr = OleLoadPicture ( pStream , 0, TRUE , IID_IPicture , (void **)&pIPic );
pStream ->Release ();
GlobalFree (hGlobal );
if ( FAILED (hr ) )
{
return NULL ;
}
HBITMAP hBitmap = NULL ;
pIPic ->get_Handle ( ( unsigned int *)&hBitmap );
HBITMAP hBitmapRet = (HBITMAP )CopyImage ( hBitmap , IMAGE_BITMAP , 0, 0, LR_COPYRETURNORG );
pIPic ->Release ();
return hBitmapRet ;
}
实验表明:这段代码可以加载JPG/GIF/BMP,对png格式加载不 了。不能使用框架的朋友可以试试这段代码,不过要注意,由于使用了COM,记得使用之前要初始化COM。
3.第三种方式,也是 我经常采取的方式,就是使用ATL和MFC的共享类Cimage。这个类十分强大,从它数千行的源码中就可以看出。然弱水三千,只取一瓢。用它从文件加载 图片,只算牛刀小试。
CImage img;
img.Load( strPath );
if( !img.IsNull() )
{
HBITMAP hBitmap = img.Detach();
}
我实验过的图片都能加载,而且很快。使用别的框架的朋友可以去研究一下 Cimage的源码,封装加载图片的功能,绝对比第二种使用COM加载的方法实用多了,也方便多了。
其他:理解 HBITMAP 结构的高手一般可以直接读取图片文件,分析数据流的。至于像我这样路过的人,不用搞那么复杂的了。对了, 还有个相对来说庞大的开源项目CxImage,电驴源码中就使用了 它。
转载于:https://my.oschina.net/dake/blog/196856