在 Win32 中显示带 alpha 通道的 32 位图像

Posted

技术标签:

【中文标题】在 Win32 中显示带 alpha 通道的 32 位图像【英文标题】:Displaying 32 bit image with alpha channel in Win32 【发布时间】:2015-04-05 11:13:23 【问题描述】:

截图:http://i.imgur.com/hbExq9N.jpg

您好,我正在尝试在静态控件之上设置带有 alpha 通道的 png,但透明像素总是填充白色或黑色。

图像是在静态控件的顶部还是仅在主窗口上绘制并不重要。

如果您有任何想法,请提供反馈。THX

对不起,我之前应该有邮政编码

//First try loading icon with transparency to static control or button:
//static control;

HWND hL;
HICON iStick;
case WM_CREATE:
iStick = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
hL = CreateWindow(L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_BITMAP/*SS_ICON*/, 193, 290, 32, 32, hwnd, NULL, hInst, NULL);
SendMessage(hL, STM_SETIMAGE, IMAGE_ICON, (LPARAM)iStick);
//SendMessage(hL, STM_SETICON, IMAGE_ICON, (LPARAM)iStick);

//Second try to draw on background 32bit bmp A8R8G8B8 : 

PAINTSTRUCT ps;
HDC hdc;
RECT r;
static HDC membit;
static BITMAP bm;

case WM_CREATE:
    SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_TOPMOST | WS_EX_LAYERED);
    SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE |SWP_NOSIZE);
    SetLayeredWindowAttributes(hWnd, 0, (255 * 100) / 100, LWA_ALPHA);
    hStick = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP15));
    GetObject(hStick, sizeof(bm), &bm);
    membit = CreateCompatibleDC(hdc);
    SelectObject(membit, hStick);
    ReleaseDC(hWnd, hdc);

case WM_CTLCOLOREDIT:
    SetTextColor((HDC)wParam, RGB(65, 65, 65));      //
    return 0;

//MakeStaticbackground transparent
case WM_CTLCOLORSTATIC:       
    SetBkMode((HDC)wParam, TRANSPARENT);             //  
    SetTextColor((HDC)wParam, RGB(38, 205, 247));    //
    return (BOOL)GetStockObject(NULL_BRUSH);    

case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);

    GetClientRect(hWnd, &r);

    FillRect(hdc, &r, hBrush);
    SetBkMode(hdc, TRANSPARENT);

    BLENDFUNCTION BlendFunction;
    BlendFunction.AlphaFormat = AC_SRC_ALPHA;
    BlendFunction.BlendFlags = 0;
    BlendFunction.BlendOp = AC_SRC_OVER;
    BlendFunction.SourceConstantAlpha = 255;

    //BitBlt(hdc, 500, 280, bm.bmWidth, bm.bmHeight, membit, 0, 0, SRCCOPY);

    AlphaBlend(hdc, 500, 280, bm.bmWidth, bm.bmHeight, membit, 0, 0, 32, 32, BlendFunction);

    //TransparentBlt(hdc, 500, 300, 32, 32, membit, 32, 32, 32, 32, RGB(255, 255, 255));

    EndPaint(hWnd, &ps);

    break;

case WM_ERASEBKGND:
    return (LRESULT)1;

还有更多我不记得了,但背景像素总是填充白色或黑色。

【问题讨论】:

【参考方案1】:

我认为您只需要透明度,而不是 Alpha 通道。你需要LWA_COLORKEY 而不是LWA_ALPHA

SetLayeredWindowAttributes(hWnd, window_background_brush, 255, LWA_COLORKEY);

这会将window_background_brush 替换为透明色。如果没有设置背景画笔,则需要设置,最好是白色。此外,最好使用图标,否则您最终会遇到粗糙的边缘。下面是绘制图标的示例代码:

HDC hDC = ::GetDC(m_hWnd);
HICON hicon = (HICON)LoadImage(NULL, "fullpath.ico", IMAGE_ICON, w, h, LR_LOADFROMFILE);
DrawIconEx(hDC, x, y, hicon, w, h, 0, NULL, DI_NORMAL);
DestroyIcon(hicon);
::ReleaseDC(m_hWnd, hDC);

【讨论】:

感谢 Barmak,您的代码运行良好,但我在每秒轮询操纵杆 60 次的函数中使用了您的代码,我得到了这个:i.imgur.com/jha99iQ.gif?1 HDC hDC = ::GetDC(hwnd); DrawIconEx(hDC, 193 + (js.lX / 22), 290 + (js.lY / 22), iStick, 32, 32, 0, NULL, DI_NORMAL); DrawIconEx(hDC, 340 + (js.lZ / 22), 290 + (js.lRz / 22), iStick, 32, 32, 0, NULL, DI_NORMAL); //DestroyIcon(iStick); ReleaseDC(hwnd, hDC); 优秀。但是有很多闪烁,或者可能是由于截屏引起的。我认为您需要背景图像的透明度,但似乎并非如此。我会删除WS_EX_LAYEREDSetLayeredWindowAttributes。用普通位图绘制背景图像。只用图标绘制那些移动的黑色精灵。同时添加WS_CLIPCHILDREN。如果仍有闪烁,您可以尝试 ExcludeClipRect 手动排除绘图中的控制区域。

以上是关于在 Win32 中显示带 alpha 通道的 32 位图像的主要内容,如果未能解决你的问题,请参考以下文章

将 GLubyte* 转换为 GLuint* 用于 alpha 纹理 Opengl 3.0 / c++ / Win32

使用 GDIPlus (WIN32 C++) 显示存储为 alpha 资源的图标

使用来自其他 32 位位图的 Alpha 通道组成新的 32 位位图

如何在png里删除alpha通道

调配 32 位 alpha 通道所需的 Intel 内在函数

Premiere 2.0 alpha道的问题