Как добавить прозрачный PNG в качестве значка на панели инструментов? - PullRequest
5 голосов
/ 07 ноября 2019

Мое намерение - создать панель инструментов в Win32, содержащую прозрачный значок. Я попробовал следующий код для создания простой панели инструментов с одной кнопкой, имеющей пользовательское изображение:

// Create the toolbar
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME,
                             NULL,
                             WS_CHILD | TBSTYLE_FLAT | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | CCS_BOTTOM,
                             0, 0, 0, 0,
                             hwnd,
                             NULL,
                             ghInstance, // <-this is the HINSTANCE of the application
                             NULL);

// Set the font (this cannot be the problem)
SendMessage(hToolbar,
            WM_SETFONT,
            (WPARAM)hFontBold,
            static_cast<LPARAM>(MAKELONG(TRUE, 0)));

auto hImagelist = ImageList_Create(32, 32,ILC_COLOR24 | ILC_MASK, 1, 0);

HBITMAP bitmap = static_cast<HBITMAP>(LoadImage(ghInstance,
    /* ID_IMG_SPAWN is my custom resource -> */ MAKEINTRESOURCE(ID_IMG_SPAWN), 
                                                IMAGE_BITMAP,
                                                32, 32,
                                                NULL));
ImageList_AddMasked(hImagelist,
                    bitmap,
                    RGB(255,255,255) /* white is the transparent color */);
SendMessage(hToolbar,
            TB_SETIMAGELIST,
            static_cast<WPARAM>(0),
            (LPARAM)hImagelist);

ImageList_Create поддерживает только 24-битные растровые изображения, что означает отсутствие альфа-канала для прозрачности. Однако я могу смоделировать эффект прозрачности, используя цвет маски через ImageList_AddMasked. (Здесь я устанавливаю белый (RGB(255, 255, 255)) цвет маски.)

Это работало нормально, но отображаемое таким образом изображение очень резкое / неровное из-за отсутствиягранулярность в альфа-канале (каждый пиксель либо прозрачный, либо полностью непрозрачный).

Я понимаю, что формат PNG может решить эту проблему, поскольку он обеспечивает настоящий альфа-канал. Я знаю, что формат PNG поддерживается Win32 ImageLists, но я не знаю, как правильно его использовать. (Ресурсы PNG могут быть добавлены к ресурсам Visual Studio, но я не знаю, как использовать их из кода.)

Я не смог найти способ заставить LoadImage загрузить PNG. Поддерживаются только типы IMAGE_BITMAP IMAGE_CURSOR и IMAGE_ICON. Я изменил ресурс (ID_IMG_SPAWN) на файл PNG и попробовал каждый из этих трех типов один за другим, но все вылилось в пустой экран, подобный этому:

Кто-нибудь может мне помочь? Как я могу использовать LoadImage, чтобы загрузить прозрачный PNG и использовать его в качестве изображения панели инструментов?

Ответы [ 2 ]

1 голос
/ 09 ноября 2019

ImageList_Create поддерживает только 24-битные растровые изображения, что означает отсутствие альфа-канала для прозрачности.

Нет, это неправильно. ImageList_Create также поддерживает 32-битные растровые изображения .

Поскольку вы намереваетесь создать панель инструментов в Win32, содержащую прозрачный значок, вам НЕ нужно загружать PNG вообще. Если вы хотите PNG, вам, возможно, придется обходиться с GdiPlus, как говорит @barmak.

32-битное растровое изображение имеет 8 бит для ALPHA. Использование 32-битных растровых изображений может дать тот же эффект, что и PNG.


Вы говорите, что изображение кнопки показывало пустым, когда вы делали это:

  • изменено *От 1019 * до ILC_COLOR32

  • изменен ресурс ID_IMG_SPAWN на 32-битное растровое изображение


В ФАКТЕ Показать32-битное растровое изображение должно быть правильно:

  • изменить ILC_COLOR24 на ILC_COLOR32

  • изменить ресурс ID_IMG_SPAWNв 32-битное растровое изображение с предварительно умноженным альфа .

  • создать раздел DIB для вашего растрового изображения при загрузке

(требование формата Win32 очень строго)


В: Как создать раздел DIB для растрового изображения?

A: Укажите LR_CREATEDIBSECTION в последнем параметре LoadImage.

Объяснение:

LoadImage((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,32, 32,NULL)

Это ваш код функции LoadImage. См. MSDN документ LoadImage , чтобы создать раздел DIB, все, что вам нужно, это указать LR_CREATEDIBSECTION в последнем параметре LoadImage.


Q: Какполучить BMP с предварительно умноженным альфа-каналом?

A: Pixelformer может помочь вам преобразовать ваш альфа-канал в файл с предварительно умноженным альфа-каналом BMP.

Шаги

  1. Откройте свое изображение (любой формат) в Pixelformer и выберите «Экспорт» в меню

Выберите A8: R8: G8: B8 (32 бит / с) и Предварительно умноженное альфа , затем нажмите Ok.

Тогда вы можете сохранить файл BMP! Импортируйте этот файл BMP в ресурсы Visual Studio, заменив предыдущий 24-битный BMP.


Тогда вам больше не нужно использовать ImageList_AddMasked (что делает изображение четким), потому что выуже есть узнаваемая альфа в вашем 32-битном BMP. Итак, прямое использование ImageList_Add.

Хорошо, после манипуляций, описанных выше, ваш код должен выглядеть так:

// Create the toolbar
HWND hToolbar = CreateWindow(TOOLBARCLASSNAME,NULL,
     WS_CHILD | TBSTYLE_FLAT | TBSTYLE_AUTOSIZE | TBSTYLE_LIST | CCS_BOTTOM,
     0, 0, 0, 0, hwnd, NULL, ghInstance, NULL);

// Set the font (this cannot be the problem)
SendMessage(hToolbar, WM_SETFONT, (WPARAM)hFontBold,
     static_cast<LPARAM>(MAKELONG(TRUE, 0)));

auto hImagelist =
ImageList_Create(32, 32,ILC_COLOR32 /*DON'T NEED THE MASK. CHANGED TO ILC_COLOR32.*/, 1, 0);

HBITMAP bitmap = static_cast<HBITMAP>(LoadImage((HINSTANCE)GetWindowLong(hwnd,
      GWL_HINSTANCE), MAKEINTRESOURCE(ID_IMG_SPAWN), IMAGE_BITMAP,
      32, 32, LR_CREATEDIBSECTION  /*THIS IS IMPORTANT*/   ));

ImageList_Add(hImagelist, bitmap, NULL);
SendMessage(hToolbar, TB_SETIMAGELIST, static_cast<WPARAM>(0), (LPARAM)hImagelist);

Это работало нормально, как показано ниже.


На эти вопросы, на которые я ответил выше, этого вполне достаточно, чтобы решить эту проблему.

Для получения дополнительной информации о точечных рисунках DIB и Предварительно умноженное Альфа , см. Ссылки.

1 голос
/ 07 ноября 2019

LoadImage вернет NULL при попытке загрузить ресурс PNG.

Вы можете добавить свой ресурс PNG как ICON. В противном случае используйте компонент Windows Imaging Component или Gdiplus + для загрузки ресурса png.

Считайте ресурс PNG следующим образом:

HBITMAP loadimage(HINSTANCE hinst, const wchar_t* name)
{
    HBITMAP hbitmap = NULL;
    ULONG_PTR token;
    Gdiplus::GdiplusStartupInput tmp;
    Gdiplus::GdiplusStartup(&token, &tmp, NULL);
    if(auto hres = FindResource(hinst, name, RT_RCDATA))
        if(auto size = SizeofResource(hinst, hres))
            if(auto data = LockResource(LoadResource(hinst, hres)))
                if(auto stream = SHCreateMemStream((BYTE*)data, size))
                {
                    Gdiplus::Bitmap bmp(stream);
                    stream->Release();
                    bmp.GetHBITMAP(Gdiplus::Color::Transparent, &hbitmap);
                }
    Gdiplus::GdiplusShutdown(token);
    return hbitmap;
}

...
auto hbitmap = loadimage(ghinst, MAKEINTRESOURCE(ID_PNG1 ));
if(hbitmap)
{
    ImageList_AddMasked(himage, hbitmap, 0);
    DeleteObject(hbitmap);
}

Определение ресурса должно выглядеть следующим образом:

ID_PNG1 RCDATA "file.png"
...