VC++使用GDI+实现HBITMAP与图片文件之间的相互转换(附源码)
Posted dvlinker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VC++使用GDI+实现HBITMAP与图片文件之间的相互转换(附源码)相关的知识,希望对你有一定的参考价值。
有时我们需要把图片文件加载到内存中的HBITMAP中,有时我们需要把内存中的HBITMAP位图保存成图片文件。如果仅使用GDI函数去处理,是比较难实现的,借助GDI+对象我们可以轻易的实现。本文我们就来讲述一下如何实现HBITMAP与图片文件之间的相互转换。
1、将图片文件加载到HBITMAP对象中
先将指定路径的图片文件加载到CImage对象中,然后再将CImage对象中的图片数据绘制到HBITMAP中。其中CImage类是Visual Studio中自带的MFC类,是专门用来处理图片文件的,CImage类内部其实就是使用GDI+来实现的,所以我们当前的这种方法,本质是使用GDI+实现的。相关代码如下:
HBITMAP GetHBitmapFromFile( CString strFilePath )
if ( !PathFileExists( strFilePath ) )
return NULL;
// 先将图片加载到CImage对象中
CImage img;
HRESULT hResult = img.Load( strFilePath );
if ( hResult != S_OK )
return NULL;
// 然后将CImage对象中的图片绘制到新创建的HBITMAP对象上
HDC hDC = GetDC( NULL ); // 获取屏幕DC
HDC hDstDC = CreateCompatibleDC( hDC );
HBITMAP hDstBitmap = ::CreateCompatibleBitmap( hDC, img.GetWidth(), img.GetHeight() );
::SelectObject( hDstDC, hDstBitmap );
img.Draw( hDstDC, 0, 0 );
::DeleteDC( hDstDC );
::ReleaseDC( NULL, hDC );
return hDstBitmap;
有人可能会说,我当前进行的是Win32窗口编程,不使用MFC框架,使用MFC库还需要将MFC库带上,也会增大程序安装包的大小。其实Visua Studio中可以直接go到CImage类的cpp实现代码中,我们完全可以将CImage类从MFC库中剥离出来的,即直接将CImage类的.h头文件和.cpp源文件拷贝出来,然后将文件中依赖MFC的接口换掉就可以了,操作起来很简单,我们就这样处理过。
2、将HBITMAP中的图片保存成多种类型的图片文件
我们需要使用到GDI+中的Bitmap对象,先调用Bitmap::FromHBITMAP接口将HBITMAP中的图片数据加载到Bitmap对象中,然后再调用Bitmap::Save接口将Bitmap对象中的图片数据保存成图片文件。相关代码如下所示:(代码中根据要保存成的文件路径中的后缀名,确定要保存成什么类型的图片)
// 获取jpeg等编码Clsid
// 这是一个中间函数,下面的主函数SaveHBitmapToFile会调用到该函数
int GetEncoderClsid( const WCHAR* format, CLSID* pClsid )
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize( &num, &size );
if( size == 0 )
return -1;
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if( pImageCodecInfo == NULL )
return -1;
GetImageEncoders( num, size, pImageCodecInfo );
for( UINT j = 0; j < num; ++j )
if( wcscmp( pImageCodecInfo[j].MimeType, format ) == 0 )
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
free( pImageCodecInfo );
return -1;
// 使用gdi+将HBITMAP位图句柄图片资源保存成图片文件,图片文件的类型包括bmp、jpg、png、gif和tiff
BOOL SaveHBitmapToFile( HBITMAP hBmp, LPCTSTR lpfilename )
if ( hBmp == NULL || lpfilename == NULL )
WriteLog( _T("[SaveHBitmapToFile] hBmp或lpfilename为空,return") );
return FALSE;
CUIString strLog;
int nLastErrCode = 0;
Bitmap *pSrcBmp = Bitmap::FromHBITMAP( hBmp, NULL );
if ( pSrcBmp == NULL )
nLastErrCode = ::GetLastError();
strLog.Format( _T("[SaveHBitmapToFile] Bitmap::FromHBITMAP失败,GetLastError: %d"),
nLastErrCode );
WriteLog( strLog );
return FALSE;
// 获取文件的扩展名,根据文件名中的扩展名确定要保存成什么类型的图片
CUIString strExtName = _T("");
CUIString strFilePatch = lpfilename;
int nPos = strFilePatch.ReverseFind(_T('.'));
if ( nPos != -1)
strExtName = strFilePatch.Right( strFilePatch.GetLength() - nPos - 1 );
// GDI+中有五种编码:bmp、jpeg、gif、tiff和png,下面根据
// 文件名的扩展部分来获取对应的编码CLSID
CLSID encoderClsid;
if ( strExtName == _T("bmp") )
GetEncoderClsid( L"image/bmp", &encoderClsid );
else if ( strExtName == _T("jpg") )
GetEncoderClsid( L"image/jpeg", &encoderClsid );
else if ( strExtName == _T("png") )
GetEncoderClsid( L"image/png", &encoderClsid );
else if ( strExtName == _T("gif") )
GetEncoderClsid( L"image/gif", &encoderClsid );
else if ( strExtName == _T("tiff") )
GetEncoderClsid( L"image/tiff", &encoderClsid );
else // 没有指定类型的扩展名,则默认使用png
GetEncoderClsid( L"image/png", &encoderClsid );
LPWSTR lpWStrFileName = NULL; // 注意:Bitmap::Save接口第一个参数是宽字节参数
#ifdef _UNICODE
lpWStrFileName = const_cast<LPTSTR>(lpfilename); // 如果是_UNICODE模式,直接使用
#else
WCHAR wchFileName[MAX_PATH*2] = 0;
MultiByteToWideChar( CP_ACP, 0, lpfilename, -1, wchFileName, sizeof(wchFileName)/sizeof(WCHAR) ); // 将窄字符转化为宽字符
lpWStrFileName = wchFileName;
#endif
Gdiplus::Status statusRet = pSrcBmp->Save( lpWStrFileName, &encoderClsid );
if ( statusRet != Gdiplus::Ok )
nLastErrCode = ::GetLastError();
strLog.Format( _T("[SaveHBitmapToFile] Bitmap::FromHBITMAP失败,,Gdiplus错误码:%d, GetLastError: %d"),
statusRet, nLastErrCode );
WriteLog( strLog );
// 释放内存
delete pSrcBmp;
return FALSE;
// 释放内存
delete pSrcBmp;
return TRUE;
以上是关于VC++使用GDI+实现HBITMAP与图片文件之间的相互转换(附源码)的主要内容,如果未能解决你的问题,请参考以下文章