c - 使用缓冲区的 Windows AlphaBlend

标签 c winapi transparency chromium-embedded alphablending

我想在给定窗口内绘制一个缓冲区(带有 alpha 信息!)。绘图是在 WM_PAINT 之外完成的(它是在从 Chromium-Embedded-Framework 调用的 CefRenderHandler::OnPaint 方法中完成的)。

我遇到的问题是:

  • 窗口的旧内容未被清除(如果更改缓冲区,我会绘制旧内容和绘制新内容)。
  • alpha channel 被错误地解释 - 我认为,即使像素具有 alpha 信息,它也被绘制为没有 alpha 信息

这是我目前所拥有的:

OnPaint(...):

HDC screen_dc = GetDC(windowHandle);
RECT rcWin;
GetClientRect(windowHandle, &rcWin);

BITMAPINFO info;
ZeroMemory(&info, sizeof(BITMAPINFO));
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biWidth = width;
info.bmiHeader.biHeight = -height;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biSizeImage = width*height * 4;
info.bmiHeader.biCompression = BI_RGB;

void *buf;
HBITMAP hDib = CreateDIBSection(screen_dc, &info, DIB_RGB_COLORS, (void **)&buf, 0, 0);
memcpy(buf, buffer, width * height * 4); //buffer contains bitmap to draw
HDC hDibDC = CreateCompatibleDC(screen_dc);
HGDIOBJ hOldObj = SelectObject(hDibDC, hDib);
BLENDFUNCTION blendFunction_;
blendFunction.BlendOp = AC_SRC_OVER;
blendFunction.BlendFlags = 0;
blendFunction.SourceConstantAlpha = 255;
blendFunction.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(screen_dc, 0, 0, width, height, hDibDC, 0, 0, width, height, blendFunction);

SelectObject(hDibDC, hOldObj);
ReleaseDC(windowHandle, screen_dc);
DeleteObject(hDib);
DeleteDC(hDibDC);

窗口创建:

WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = BrowserWindowWndProc;
wcex.hInstance = hinstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = WHITE_BRUSH;
wcex.lpszClassName = BROWSER_WINDOW_CLASS;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
RegisterClassEx(&wcex);

DWORD exStyle{0};
exStyle |= WS_EX_TOOLWINDOW;
exStyle |= WS_EX_LAYERED;

DWORD style {0};
style |= WS_SYSMENU;
style |= WS_VISIBLE;

HWND hWnd = CreateWindowEx(
    exStyle,
    BROWSER_WINDOW_CLASS, 
    BROWSER_WINDOW_CLASS,
    style,
    100,
    100,
    300,
    300,
    nullptr,
    nullptr, 
    hinstance,
    nullptr
);
...
SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 255, LWA_COLORKEY);

你能帮我解决这些问题吗?

提前谢谢你。

最佳答案

没有必要同时使用 AlphaBlend 和分层窗口。仅使用分层窗口:

void OnPaint(HDC hdc, int width, int height, HBITMAP hbitmap)
{
    HDC memdc = CreateCompatibleDC(hdc);
    auto oldbmp = SelectObject(memdc, hbitmap);

    BITMAP bm;
    GetObject(hbitmap, sizeof(bm), &bm);
    BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);

    SelectObject(memdc, oldbmp);
    DeleteDC(memdc);
}

其中 hbitmap 是之前创建的位图的句柄。使用 SetLayeredWindowAttributes(hwnd, RGB(255,255,255), 255, LWA_COLORKEY);

时,位图的白色区域应该显示为透明

或者使用LWA_COLORKEY | LWA_ALPHA 调整透明度和 alpha 级别。

假设 OnPaint 是对 WM_PAINT 的响应,使用 BeginPaint/EndPaint 而不是 GetDC/ReleaseDC

请注意 WHITE_BRUSH 为零,因此 wcex.hbrBackground = WHITE_BRUSH; 将背景画笔设置为零。而是分配一个画笔 handle 。

或者,您可以在同一窗口中使用 TransparentBlt:

HDC memdc = CreateCompatibleDC(hdc);
auto oldbmp = SelectObject(memdc, hbitmap);

BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm);
TransparentBlt(hdc, 0, 0, width, height, 
    memdc, 0, 0, bm.bmWidth, bm.bmHeight, RGB(255, 255, 255));

SelectObject(memdc, oldbmp);
DeleteDC(memdc);

关于c - 使用缓冲区的 Windows AlphaBlend,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39868302/

相关文章:

具有透明窗口和远程桌面的 WPF 应用程序会导致弹出窗口

c - 无法解析 header 中定义的 Eclipse C 常量

c - 确定多项式方程的次数

c# - 如何让两个应用程序通过 LAN 找到并连接?

winapi - 如何弹出USB可移动磁盘/卷,类似于Windows资源管理器中的 "Eject"功能?

c++ - 如何在 Win32 应用程序中拖动纯色矩形而不会出现白色闪烁且不会干扰屏幕上的其他对象?

c# - 如何制作真正透明的控件?

c - 引用函数不编译

c - 为什么我的排序代码在 c 中不起作用?

c++ - Qt - 从 Widget 抓取像素图不采用正确的 alpha channel