Небольшая нежелательная прозрачность от FillRectangle
У меня есть окно, созданное с 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
Я указал значение 254 для альфа-компонента. Это приводит к непрозрачной заливке 99,6%, а это не то, что я хочу.
Когда я указываю 255 в качестве альфа-компонента, кажется, что нет заполнения; мое окно становится полностью прозрачным. Это проблема, потому что я хочу рисовать фигуры, которые на 100% непрозрачны, но я также хочу рисовать и те, которые не являются прозрачными.
2 ответа
Кажется, есть некоторые qwerks с FillRectangle
, Это становится очевидным, когда мы наблюдаем, что с помощью FillEllipse
с SolidBrush
чей альфа-компонент равен 255, в результате фигура отображается идеально (непрозрачно).
Вот два обходных пути, которые я придумал, каждый из которых решает проблему для меня:
Вызов
FillRectangle
дваждыSolidBrush b(Color(254, 255, 0, 0)); gfx.FillRectangle(&b, Rect(0, 0, width, height)); gfx.FillRectangle(&b, Rect(0, 0, width, height));
Поскольку одна и та же область заполняется дважды, они будут смешиваться и создавать RGB(255, 0, 0) независимо от содержимого за окном (теперь оно на 100% непрозрачно). Я не предпочитаю этот метод, поскольку он требует, чтобы каждый прямоугольник был нарисован дважды.
использование
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
вместо. Или - скорее всего - есть какая-то проблема сFillPolygon
который называетсяFillRectangle
, Однако, если вы добавите дополнительный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% непрозрачную форму, что решает мою проблему.
UpdateLayeredWindow()
требуется растровое изображение с предварительно умноженным альфа:
Обратите внимание, что API используют предварительно умноженный альфа-канал, что означает, что значения красного, зеленого и синего каналов в растровом изображении должны быть предварительно умножены на значение альфа-канала. Например, если значение альфа-канала равно x, красный, зеленый и синий каналы должны быть умножены на x и разделены на 0xff до вызова.
Ты можешь использовать Bitmap::ConvertFormat()
преобразовать растровое изображение в предварительно умноженное (формат PixelFormat32bppPARGB
).