Как сохранить прозрачность при написании текста на значке в системном трее Windows из неуправляемой программы на C

У меня есть приложение MFC C ++ (неуправляемое) для Windows, которое использует «стандартный» значок на панели задач. Этот значок был создан & отредактировано с использованием Visual Studio и имеет размер 32×32 пикселя только с 4-битным цветом (согласно редактору ресурсов VS).

В Visual Studio я также установил прозрачный фон (отображается белым цветом на изображении «до»).

Я хочу динамически изменить значок, написав 2 цифры (1-99) поверх него.

Используя код ниже (основанный на этом в этом вопросе: Как нарисовать текст с прозрачностью, используя GDI?), чтобы наложить на значок «55» желтым цветом, это работает, за исключением того, что прозрачность исчезает (она выглядит черной на изображении «после» и в системном трее). Мой фактический код отличается очень очень немного в том, что размер шрифта (20), имя шрифта (Courier New), цвет текста (желтый — RGB (255, 255, 0)) и числовое значение (55) являются скорее переменными времени выполнения чем фиксированные значения.

С благодарностью принимаются любые предложения о том, как сделать фон прозрачным с точки зрения системного трея.

Эти изображения были получены с помощью инструмента MS Snipping с открытым изображением в MS Paint, так как значок 32×32 не будет виден как есть.

Перед изображением:

Перед изображением

После изображения:

После изображения

Код:

void CreateNewIcon(HICON &hNewIcon, HICON hBackgroundIcon)
{
::DestroyIcon(hNewIcon);

// First create font
LOGFONT lf = { 0 };
lf.lfHeight = -20;
lf.lfWeight = FW_BOLD;
lf.lfOutPrecision = OUT_TT_PRECIS;
lf.lfQuality = CLEARTYPE_QUALITY;
wmemset(lf.lfFaceName, 0, LF_FACESIZE);
lstrcpy(lf.lfFaceName, L"Courier New");

HFONT hFont = ::CreateFontIndirect(&lf);

ICONINFO ii = { 0 };
::GetIconInfo(hBackgroundIcon, &ii);

BITMAP bm = { 0 };
::GetObject(ii.hbmColor, sizeof(bm), &bm);
SIZE szBmp = { bm.bmWidth, bm.bmHeight };

HDC hDc = ::GetDC(NULL);
HDC hMemDC = ::CreateCompatibleDC(hDc);

HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor);
HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont);

::SetBkMode(hMemDC, TRANSPARENT);
::SetTextColor(hMemDC, RGB(255, 255, 0));
::TextOut(hMemDC, 0, 8, L"55", 2);

::SelectObject(hMemDC, hOldFont);
::SelectObject(hMemDC, hOldBmp);

// We need a simple mask bitmap for the icon
HBITMAP hBmpMsk = ::CreateBitmap(szBmp.cx, szBmp.cy, 1, 1, NULL);

ICONINFO ii2 = { 0 };
ii2.fIcon = TRUE;
ii2.hbmColor = ii.hbmColor;
ii2.hbmMask = hBmpMsk;

// Create updated icon
hNewIcon = ::CreateIconIndirect(&ii2);

// Cleanup
::DeleteObject(hBmpMsk);
::DeleteDC(hMemDC);
::ReleaseDC(NULL, hDc);
::DeleteObject(ii.hbmColor);
::DeleteObject(ii.hbmMask);
::DeleteObject(hFont);
}

1

Решение

Есть несколько проблем с нашим кодом:

  • Вы пытаетесь нарисовать текст в чистом виде поверх прозрачной части значка. Но рендеринг шрифта cleartype должен выполняться на непрозрачном фоне, потому что он должен проверять цвет фона. Поэтому вам следует переключиться на качество с сглаживанием (или на качество без сглаживания) или предоставить непрозрачный фон для вашего текста.
  • Когда вы создаете hBmpMsk вы пропускаете инициализацию содержимого, предоставляя NULL для указателя бит, итоговая иконка будет иметь абсолютно случайную прозрачность. Вам необходимо соответствующим образом заполнить эту битовую маску.

Также вам, вероятно, нужно переключиться на более высокую битовую глубину, потому что монохромная битовая маска не может обрабатывать полупрозрачные части сглаженного текста.

Обновить

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

0

Другие решения

Спасибо за всю помощь от VTT, без которой я не смог бы зайти так далеко. Похоже, это работает для меня.

void CreateNewIcon(HICON &hNewIcon, HICON hBackgroundIcon)
{
::DestroyIcon(hNewIcon);

HDC hDc = ::GetDC(NULL);
HDC hMemDC = ::CreateCompatibleDC(hDc);

// Load up background icon
ICONINFO ii = { 0 };
::GetIconInfo(hBackgroundIcon, &ii);

HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor);

// Create font
LOGFONT lf = { 0 };
lf.lfHeight = -20;
lf.lfWeight = FW_BOLD;
lf.lfOutPrecision = OUT_TT_PRECIS;
lf.lfQuality = ANTIALIASED_QUALITY;
wmemset(lf.lfFaceName, 0, LF_FACESIZE);
lstrcpy(lf.lfFaceName, L"Courier New");

HFONT hFont = ::CreateFontIndirect(&lf);
HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont);

// Write text
::SetBkMode(hMemDC, TRANSPARENT);
::SetTextColor(hMemDC, RGB(255, 255, 0));
::TextOut(hMemDC, 0, 8, L"55", 2);

// Set up mask
HDC hMaskDC = ::CreateCompatibleDC(hDc);
HGDIOBJ hOldMaskBmp = ::SelectObject(hMaskDC, ii.hbmMask);

// Also write text on here
HGDIOBJ hOldMaskFont = ::SelectObject(hMaskDC, hFont);
::SetBkMode(hMaskDC, TRANSPARENT);
::SetTextColor(hMaskDC, RGB(255, 255, 0));
::TextOut(hMaskDC, 0, 8, L"55", 2);

// Get handle to create mask bitmap
HBITMAP hMaskBmp = (HBITMAP)::SelectObject(hMaskDC, hOldMaskBmp);

// Use new icon bitmap with text and new mask bitmap with text
ICONINFO ii2 = { 0 };
ii2.fIcon = TRUE;
ii2.hbmMask = hMaskBmp;
ii2.hbmColor = ii.hbmColor;

// Create updated icon
hNewIcon = ::CreateIconIndirect(&ii2);

// Cleanup bitmap mask
::DeleteObject(hMaskBmp);
::DeleteDC(hMaskDC);

// Cleanup font
::SelectObject(hMaskDC, hOldMaskFont);
::SelectObject(hMemDC, hOldFont);
::DeleteObject(hFont);

// Release background bitmap
::SelectObject(hMemDC, hOldBmp);

// Delete background icon bitmap info
::DeleteObject(ii.hbmColor);
::DeleteObject(ii.hbmMask);

::DeleteDC(hMemDC);
::ReleaseDC(NULL, hDc);
}
0

По вопросам рекламы [email protected]