У меня есть приложение 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);
}
Есть несколько проблем с нашим кодом:
hBmpMsk
вы пропускаете инициализацию содержимого, предоставляя NULL для указателя бит, итоговая иконка будет иметь абсолютно случайную прозрачность. Вам необходимо соответствующим образом заполнить эту битовую маску.Также вам, вероятно, нужно переключиться на более высокую битовую глубину, потому что монохромная битовая маска не может обрабатывать полупрозрачные части сглаженного текста.
Обновить
Я думаю, что вы должны нарисовать открытый текст, но с непрозрачным фоном, а затем получить текстовый прямоугольник, используя что-то вроде GetTextExtentPoint32
затем скопируйте данные из исходной битовой маски в hBmpMsk
и, наконец, заполните белый (текстовый) прямоугольник, чтобы новый значок сохранял прозрачность от оригинала и имел непрозрачный текстовый блок.
Спасибо за всю помощь от 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);
}