我之前写了一篇文章,关于如果将HBITMA(如Excel文件的图标)显示在界面上。
Win32 使HBITMAP显示成透明效果
由于有的HBITMAP有透明色,如果直接把这个HBITMAP画在界面上,透明的地方就会显示成黑色(也不一定是黑色)。当时我用的方法是把这个HBITMAP通过转换成GDI+的Image里面,然后把这个Image画在界面上,这样就可以去掉黑色。最近又发现了一个新的方法,主要的API就是AlphaBlend函数。
先看看效果图:
图一:直接用BitBlt把HBITMAP画到DC上面
图二:通过AlphaBlend将HBITMAP画到DC上面
关于AlphaBlend,MSDN上面的解释是:
The AlphaBlend function displays bitmaps that have transparent or semitransparent pixels.
BOOL AlphaBlend( HDC hdcDest, // handle to destination DC int nXOriginDest, // x-coord of upper-left corner int nYOriginDest, // y-coord of upper-left corner int nWidthDest, // destination width int nHeightDest, // destination height HDC hdcSrc, // handle to source DC int nXOriginSrc, // x-coord of upper-left corner int nYOriginSrc, // y-coord of upper-left corner int nWidthSrc, // source width int nHeightSrc, // source height BLENDFUNCTION blendFunction // alpha-blending function );
这里最关键的就是设置这个BLENDFUNCTION 函数了,它告诉了API如何混合Alpha。关于Alpha是怎么混合的,MSDN上面有详细说明
我写的代码如下:
case WM_PAINT: { RECT rc = { 0 }; GetClientRect(hWnd, &rc); int x = (rc.right - 256) / 2; // 画的图片在窗体中间 int y = (rc.bottom - 256) / 2; // 画的图片在窗体中间 PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); HDC hMemDC = CreateCompatibleDC(NULL); // 创建一个兼容内存DC HGDIOBJ hOldObj = SelectObject(hMemDC, g_hBitmap); // 将g_bitmap选入到这个内存DC // 如果用这句话的话,就会得到图一的效果 //BitBlt(hdc, x, y, ICON_WIDTH, ICON_HEIGHT, hMemDC, 0, 0, SRCCOPY); BLENDFUNCTION ftn = { 0 }; ftn.BlendOp = AC_SRC_OVER; // 目前只能设置这个值 ftn.AlphaFormat = AC_SRC_ALPHA; // 也只能设置这个值 ftn.BlendFlags = 0; // 必须为0 ftn.SourceConstantAlpha = 255; // 指定源图片的alpha // 调用这个函数来进行Alpha混合 AlphaBlend(hdc, x, y, 256, 256, hMemDC, 0, 0, 256, 256, ftn); SelectObject(hMemDC, hOldObj); DeleteObject(hMemDC); EndPaint(hWnd, &ps); } break;
图三:SourceConstantAlpha设置为128的效果
==================================================================
上面提取的图标的大小是256 * 256。
关于如何提取一个文件的图标,方法如下:
HBITMAP ExtractFileIcon(LPCTSTR pszPath, UINT nWidth, UINT nHeight) { HBITMAP hBitmpa = NULL; if ( (NULL != pszPath) && (nWidth > 0.0) && (nHeight > 0.0) ) { IShellItemImageFactory *psif = NULL; SIZE size = { nWidth, nHeight }; HRESULT hr = ::SHCreateItemFromParsingName(pszPath, NULL, IID_PPV_ARGS(&psif)); if ( SUCCEEDED(hr) && (NULL != psif) ) { psif->GetImage(size, SIIGBF_ICONONLY, &hBitmpa); } SAFE_RELEASE(psif); } return hBitmpa; }