c++ - FillRectangle 出现轻微不合需要的透明度

标签 c++ winapi graphics gdi+

我有一个使用 WS_EX_LAYERED 窗口样式创建的窗口。我目前正在使用 GDI+ 绘制内存位图,并使用 UpdateLayeredWindow更新我的分层窗口的图形内容。

这是我的代码片段:

void Redraw(HWND hWnd, int width, int height) {
    static bool floppy = true;

    floppy = !floppy;

    HDC hScreenDC = GetDC(HWND_DESKTOP);
    HDC hMemDC = CreateCompatibleDC(hScreenDC);
    HBITMAP hBmp = CreateCompatibleBitmap(hScreenDC, width, height);
    HGDIOBJ hObj = SelectObject(hMemDC, hBmp);

    Graphics gfx(hMemDC);

    SolidBrush b(Color(254, (floppy ? 255 : 0), (floppy ? 0 : 255), 0));
    gfx.FillRectangle(&b, Rect(0, 0, width, height));

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

    POINT src = { 0, 0 };

    SIZE size;
    size.cx = width;
    size.cy = height;

    Assert(UpdateLayeredWindow(
        hWnd,
        hScreenDC,
        NULL,
        &size,
        hMemDC,
        &src,
        RGB(0, 0, 0),
        &blend,
        ULW_ALPHA
    ));

    SelectObject(hMemDC, hObj);
    DeleteObject(hBmp);
    DeleteDC(hMemDC);
    ReleaseDC(HWND_DESKTOP, hScreenDC);
}

在创建 SolidBrush 时,我为 alpha 分量指定了值 254。这会导致 99.6% 的不透明填充,这不是我想要的。

当我指定 255 作为 alpha 分量时,似乎没有填充;我的 window 变得完全透明。这是一个问题,因为我希望绘制 100% 不透明的形状,但我也希望绘制一些不透明的形状。

最佳答案

FillRectangle 似乎有一些 qwerks。当我们观察到将 FillEllipse 与 Alpha 分量为 255 的 SolidBrush 一起使用时,这一点变得很明显,导致形状完美渲染(不透明)。

以下是我想出的两种解决方法,它们分别为我解决了问题:

  • 调用 FillRectangle 两次

    SolidBrush b(Color(254, 255, 0, 0));
    gfx.FillRectangle(&b, Rect(0, 0, width, height));
    gfx.FillRectangle(&b, Rect(0, 0, width, height));
    

    由于同一区域被填充两次,因此无论窗口后面的内容如何(现在是 100% 不透明),它们都会混合并创建 RGB(255, 0, 0)。我不喜欢这种方法,因为它需要每个矩形绘制两次。

  • 使用 FillPolygon 相反

    FillEllipse一样,FillPolygon似乎没有颜色问题,除非你这样调用它:

    SolidBrush b(Color(255, 255, 0, 0));
    Point points[4];
    points[0] = Point(0, 0);
    points[1] = Point(width, 0);
    points[2] = Point(width, height);
    points[4] = Point(0, height);
    gfx.FillPolygon(&b, points, 4); //don't copy and paste - this won't work
    

    上面的代码将产生 100% 透明的窗口。我猜测这可能是由于某种形式的优化将调用传递给 FillRectangle 所致。或者 - 最有可能的是 - 由 FillRectangle 调用的 FillPolygon 存在一些问题。但是,如果向数组添加额外的 Point,则可以绕过它:

    SolidBrush b(Color(255, 255, 0, 0));
    Point points[5];
    points[0] = Point(0, 0);
    points[1] = Point(0, 0); //<-
    points[2] = Point(width, 0);
    points[3] = Point(width, height);
    points[4] = Point(0, height);
    gfx.FillPolygon(&b, points, 5);
    

    上面的代码确实会绘制一个 100% 不透明的形状,这解决了我的问题。

关于c++ - FillRectangle 出现轻微不合需要的透明度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19214921/

相关文章:

c++ - Active Accessibility (COM) 调用返回不同,具体取决于调用者是线程还是进程。什么?

Java Graphics2D - 检测两个对象之间的碰撞

android - 帮我优化这个图形动画

c# - 使用 Windows API 从 C# Windows 窗体应用程序读取非 C# 应用程序文本框

c++ - 了解虚拟拷贝构造函数

c++ - 如何消除模板代码中的 "divide by 0"错误

C++ 错误 C2512 : no appropriate default constructor available

c - GetFileSizeEx 在 System32 目录上返回不正确的值

c++ - ImGui+OpenGL,render函数无法渲染字体

c++ - 如何检测析构函数中的堆栈展开