Привет и добрый день всем,
Моя последняя цель — нарисовать файл PNG, включая альфа, на экране — это означает, что не в собственном окне, а где-то на рабочем столе.
Часть для загрузки PNG в HBITMAP работает сейчас (проверено это по-разному), но мне не удается нарисовать его в том числе альфа.
Насколько я слышал, лучший способ сделать это — использовать многослойные окна. Поэтому я много потрудился переделать пару примеров и крошечных уроков.
Следующий код компилируется без проблем и не выдает никаких сообщений (это означает, что функция showError («#») никогда не вызывается).
Еще есть ничего такого видно на экране: /
Извините, что это так долго … Надеюсь, кто-то хотел бы взглянуть на это хотя бы быстро ..
LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam);int main(HINSTANCE hInstance)
{WNDCLASSEX WndClass;
char sClassName[] = "mainClass";
WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;//WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = NULL;
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = sClassName;
WndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (RegisterClassEx(&WndClass) == 0) showError("-1");
HWND screen = CreateWindowEx(WS_EX_LAYERED,//WS_EX_LEFT
"mainClass",
"UpdateLayeredWind",
WS_DISABLED | WS_VISIBLE,
200,200,260,260,
NULL /*eventuelly, GM window*/,
NULL,
hInstance,
NULL);if (screen == NULL) showError("0");HBITMAP img = LoadImageResource("D://ThreadDraw/ThreadDraw-test/ThreadDraw/test.png");
if (img == NULL) showError("1");
BLENDFUNCTION blend = {0};
blend.AlphaFormat = AC_SRC_ALPHA;
blend.SourceConstantAlpha = 155;
POINT ptPos = {200,300};
SIZE sizeWnd = {260,260};
POINT ptPos2 = {200,300};ShowWindow(screen, SW_SHOW);while (1)
{PAINTSTRUCT ps;
HDC hdc;
BITMAP bitmap;
HDC hdcMem;
HGDIOBJ oldBitmap;
hdc = BeginPaint(screen, &ps);
hdcMem = CreateCompatibleDC(hdc);
oldBitmap = SelectObject(hdcMem, img);
GetObject(img, sizeof(bitmap), &bitmap);if (SetLayout(hdc,LAYOUT_RTL) == GDI_ERROR)
showError("5");if (!BitBlt(hdc, 0, 0, 64, 64, hdcMem, 0, 0, SRCCOPY))
showError("4");if (!UpdateLayeredWindow(screen,hdcMem,&ptPos,&sizeWnd,hdc,&ptPos2,RGB(255,255,255),&blend,ULW_ALPHA))//ULW_OPAQUE))
showError("2");EndPaint(screen, &ps);
SelectObject(hdcMem, oldBitmap);
DeleteDC(hdcMem);Sleep(10);
}return 0;
}LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
Кстати, если я использую ULW_OPAQUE вместо ULW_ALPHA в UpdateLayeredWindow, то появляется черное окно правильного размера, так что думаю, что проблема должна быть чем-то минимальным, связанным с функцией PAINTSTRUKT или BitBlt … Тем не менее, я пробовал много способов без каких-либо изменений ,
Надеюсь, кто-то может помочь. Заранее большое спасибо!
Это в основном неправильно. Ваш код должен:
CreateWindowEx
,UpdateLayeredWindow
,ShowWindow
, Окна позаботятся о покраске многослойного окна, поэтому вам не нужно обращаться с WM_PAINT
или позвоните по телефону BeginPaint
,И это все.
Если вы используете Visual Studio, создайте новый проект Win32, и он создаст новый проект с циклом сообщений для вас.
Обновить
Вот пример программы, которая создает прозрачное многослойное окно. Требуется функция для загрузки PNG в виде прозрачного растрового изображения. И это не имеет проверки ошибок.
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
LPCTSTR szWindowClass = _T("TransparentClass");
// Register class
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = DefWindowProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = szWindowClass;
RegisterClassEx(&wcex);
HWND hWnd = CreateWindowEx(WS_EX_LAYERED, szWindowClass, 0, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
int width;
int height;
HBITMAP hbmp = LoadPng(L"sample.png", &width, &height);
HDC hdcScreen = GetDC(0);
HDC hdc = CreateCompatibleDC(hdcScreen);
ReleaseDC(0, hdcScreen);
HBITMAP hbmpold = (HBITMAP)SelectObject(hdc, hbmp);
POINT dcOffset = {0, 0};
SIZE size = {width, height};
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
UpdateLayeredWindow(hWnd, 0, 0, &size, hdc, &dcOffset, 0, &bf, ULW_ALPHA);
SelectObject(hdc, hbmpold);
DeleteDC(hdc);
DeleteObject(hbmp);
ShowWindow(hWnd, SW_SHOW);
MSG msg;
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
Еще одно обновление
Вот некоторый код для предварительного умножения красного, зеленого и синего значений на альфа. Предполагается, что splash_image
указывает на размер данных ARGB 32bpp width*height
,
LPBYTE bits = (LPBYTE)splash_image;
int size = width * height;
for (int pixel = 0; pixel != size; ++pixel)
{
bits[0] = bits[0] * bits[3] / 255;
bits[1] = bits[1] * bits[3] / 255;
bits[2] = bits[2] * bits[3] / 255;
bits += 4;
}
Других решений пока нет …