如何显示透明背景的菜单位图
How to show menu bitmaps with transparent background
我正在使用此代码:
m_bmpSwap.LoadBitmap(IDB_BITMAP2);
pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap);
看起来像:
这只是一张测试图片:
如何让我的图像看起来像透明背景一样?
24位图片
我看过this但是我做不出来
我调整为背景为 192/192/192 的 8 位图像并加载如下:
HBITMAP hBmp;
hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDB_BITMAP2),
IMAGE_BITMAP,
0, 0, // cx,cy
LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS);
m_bmpSwap.Attach(hBmp);
pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap);
如果我不是 运行 WindowsBlinds:
似乎更好
但是当我重新打开 WindowsBlinds 并再次显示它时:
我自己是色盲,但我可以看出背景实际上匹配对话框背景而不是菜单颜色背景。
这是我能做的最好的了吗?
我怎样才能将 24 位或 32 位图像作为菜单位图?
添加 LR_LOADTRANSPARENT
标志以及 LR_LOADMAP3DCOLORS
这将适用于 8 位或 4 位图像(未经 Windows 盲人测试)
或者您可以手动更改背景颜色
void swap_color(HBITMAP hbmp)
{
if(!hbmp)
return;
HDC hdc = ::GetDC(HWND_DESKTOP);
BITMAP bm;
GetObject(hbmp, sizeof(bm), &bm);
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = bm.bmWidth;
bi.bmiHeader.biHeight = bm.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
std::vector<uint32_t> pixels(bm.bmWidth * bm.bmHeight);
GetDIBits(hdc, hbmp, 0, bm.bmHeight, &pixels[0], &bi, DIB_RGB_COLORS);
//assume that the color at (0,0) is the background color
uint32_t color_old = pixels[0];
//this is the new background color
uint32_t bk = GetSysColor(COLOR_MENU);
//swap RGB with BGR
uint32_t color_new = RGB(GetBValue(bk), GetGValue(bk), GetRValue(bk));
for (auto &pixel : pixels)
if(pixel == color_old)
pixel = color_new;
SetDIBits(hdc, hbmp, 0, bm.bmHeight, &pixels[0], &bi, DIB_RGB_COLORS);
::ReleaseDC(HWND_DESKTOP, hdc);
}
用法:
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
swap_color(bmp);
menu.SetMenuItemBitmaps(0, MF_BYPOSITION, &bmp, &bmp);
我找到了这个 article。我在这里复制制作的代码:
#define COLORREF2RGB(Color) (Color & 0xff00) | ((Color >> 16) & 0xff) \
| ((Color << 16) & 0xff0000)
//-------------------------------------------------------------------------------
// ReplaceColor
//
// Author : Dimitri Rochette drochette@coldcat.fr
// Specials Thanks to Joe Woodbury for his comments and code corrections
//
// Includes : Only <windows.h>
//
// hBmp : Source Bitmap
// cOldColor : Color to replace in hBmp
// cNewColor : Color used for replacement
// hBmpDC : DC of hBmp ( default NULL ) could be NULL if hBmp is not selected
//
// Retcode : HBITMAP of the modified bitmap or NULL for errors
//
//-------------------------------------------------------------------------------
HBITMAP ReplaceColor(HBITMAP hBmp,COLORREF cOldColor,COLORREF cNewColor,HDC hBmpDC)
{
HBITMAP RetBmp=NULL;
if (hBmp)
{
HDC BufferDC=CreateCompatibleDC(NULL); // DC for Source Bitmap
if (BufferDC)
{
HBITMAP hTmpBitmap = (HBITMAP) NULL;
if (hBmpDC)
if (hBmp == (HBITMAP)GetCurrentObject(hBmpDC, OBJ_BITMAP))
{
hTmpBitmap = CreateBitmap(1, 1, 1, 1, NULL);
SelectObject(hBmpDC, hTmpBitmap);
}
HGDIOBJ PreviousBufferObject=SelectObject(BufferDC,hBmp);
// here BufferDC contains the bitmap
HDC DirectDC=CreateCompatibleDC(NULL); // DC for working
if (DirectDC)
{
// Get bitmap size
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
// create a BITMAPINFO with minimal initilisation
// for the CreateDIBSection
BITMAPINFO RGB32BitsBITMAPINFO;
ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));
RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
RGB32BitsBITMAPINFO.bmiHeader.biWidth=bm.bmWidth;
RGB32BitsBITMAPINFO.bmiHeader.biHeight=bm.bmHeight;
RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;
RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;
// pointer used for direct Bitmap pixels access
UINT * ptPixels;
HBITMAP DirectBitmap = CreateDIBSection(DirectDC,
(BITMAPINFO *)&RGB32BitsBITMAPINFO,
DIB_RGB_COLORS,
(void **)&ptPixels,
NULL, 0);
if (DirectBitmap)
{
// here DirectBitmap!=NULL so ptPixels!=NULL no need to test
HGDIOBJ PreviousObject=SelectObject(DirectDC, DirectBitmap);
BitBlt(DirectDC,0,0,
bm.bmWidth,bm.bmHeight,
BufferDC,0,0,SRCCOPY);
// here the DirectDC contains the bitmap
// Convert COLORREF to RGB (Invert RED and BLUE)
cOldColor=COLORREF2RGB(cOldColor);
cNewColor=COLORREF2RGB(cNewColor);
// After all the inits we can do the job : Replace Color
for (int i=((bm.bmWidth*bm.bmHeight)-1);i>=0;i--)
{
if (ptPixels[i]==cOldColor) ptPixels[i]=cNewColor;
}
// little clean up
// Don't delete the result of SelectObject because it's
// our modified bitmap (DirectBitmap)
SelectObject(DirectDC,PreviousObject);
// finish
RetBmp=DirectBitmap;
}
// clean up
DeleteDC(DirectDC);
}
if (hTmpBitmap)
{
SelectObject(hBmpDC, hBmp);
DeleteObject(hTmpBitmap);
}
SelectObject(BufferDC,PreviousBufferObject);
// BufferDC is now useless
DeleteDC(BufferDC);
}
}
return RetBmp;
}
现在,如果我将 24 位位图添加到我的项目中,并将背景设置为 71/71/71 并像这样加载它:
HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP,
0, 0, // cx,cy
LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS);
HBITMAP hBmp2 = ReplaceColor(hBmp, RGB(71, 71, 71), GetSysColor(COLOR_MENU), NULL);
DeleteObject(hBmp);
m_bmpSwap.Attach(hBmp2);
pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap);
结果:
我正在使用此代码:
m_bmpSwap.LoadBitmap(IDB_BITMAP2);
pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap);
看起来像:
这只是一张测试图片:
如何让我的图像看起来像透明背景一样?
24位图片
我看过this但是我做不出来
我调整为背景为 192/192/192 的 8 位图像并加载如下:
HBITMAP hBmp;
hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDB_BITMAP2),
IMAGE_BITMAP,
0, 0, // cx,cy
LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS);
m_bmpSwap.Attach(hBmp);
pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap);
如果我不是 运行 WindowsBlinds:
似乎更好但是当我重新打开 WindowsBlinds 并再次显示它时:
我自己是色盲,但我可以看出背景实际上匹配对话框背景而不是菜单颜色背景。
这是我能做的最好的了吗?
我怎样才能将 24 位或 32 位图像作为菜单位图?
添加 LR_LOADTRANSPARENT
标志以及 LR_LOADMAP3DCOLORS
这将适用于 8 位或 4 位图像(未经 Windows 盲人测试)
或者您可以手动更改背景颜色
void swap_color(HBITMAP hbmp)
{
if(!hbmp)
return;
HDC hdc = ::GetDC(HWND_DESKTOP);
BITMAP bm;
GetObject(hbmp, sizeof(bm), &bm);
BITMAPINFO bi = { 0 };
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = bm.bmWidth;
bi.bmiHeader.biHeight = bm.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
std::vector<uint32_t> pixels(bm.bmWidth * bm.bmHeight);
GetDIBits(hdc, hbmp, 0, bm.bmHeight, &pixels[0], &bi, DIB_RGB_COLORS);
//assume that the color at (0,0) is the background color
uint32_t color_old = pixels[0];
//this is the new background color
uint32_t bk = GetSysColor(COLOR_MENU);
//swap RGB with BGR
uint32_t color_new = RGB(GetBValue(bk), GetGValue(bk), GetRValue(bk));
for (auto &pixel : pixels)
if(pixel == color_old)
pixel = color_new;
SetDIBits(hdc, hbmp, 0, bm.bmHeight, &pixels[0], &bi, DIB_RGB_COLORS);
::ReleaseDC(HWND_DESKTOP, hdc);
}
用法:
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
swap_color(bmp);
menu.SetMenuItemBitmaps(0, MF_BYPOSITION, &bmp, &bmp);
我找到了这个 article。我在这里复制制作的代码:
#define COLORREF2RGB(Color) (Color & 0xff00) | ((Color >> 16) & 0xff) \
| ((Color << 16) & 0xff0000)
//-------------------------------------------------------------------------------
// ReplaceColor
//
// Author : Dimitri Rochette drochette@coldcat.fr
// Specials Thanks to Joe Woodbury for his comments and code corrections
//
// Includes : Only <windows.h>
//
// hBmp : Source Bitmap
// cOldColor : Color to replace in hBmp
// cNewColor : Color used for replacement
// hBmpDC : DC of hBmp ( default NULL ) could be NULL if hBmp is not selected
//
// Retcode : HBITMAP of the modified bitmap or NULL for errors
//
//-------------------------------------------------------------------------------
HBITMAP ReplaceColor(HBITMAP hBmp,COLORREF cOldColor,COLORREF cNewColor,HDC hBmpDC)
{
HBITMAP RetBmp=NULL;
if (hBmp)
{
HDC BufferDC=CreateCompatibleDC(NULL); // DC for Source Bitmap
if (BufferDC)
{
HBITMAP hTmpBitmap = (HBITMAP) NULL;
if (hBmpDC)
if (hBmp == (HBITMAP)GetCurrentObject(hBmpDC, OBJ_BITMAP))
{
hTmpBitmap = CreateBitmap(1, 1, 1, 1, NULL);
SelectObject(hBmpDC, hTmpBitmap);
}
HGDIOBJ PreviousBufferObject=SelectObject(BufferDC,hBmp);
// here BufferDC contains the bitmap
HDC DirectDC=CreateCompatibleDC(NULL); // DC for working
if (DirectDC)
{
// Get bitmap size
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
// create a BITMAPINFO with minimal initilisation
// for the CreateDIBSection
BITMAPINFO RGB32BitsBITMAPINFO;
ZeroMemory(&RGB32BitsBITMAPINFO,sizeof(BITMAPINFO));
RGB32BitsBITMAPINFO.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
RGB32BitsBITMAPINFO.bmiHeader.biWidth=bm.bmWidth;
RGB32BitsBITMAPINFO.bmiHeader.biHeight=bm.bmHeight;
RGB32BitsBITMAPINFO.bmiHeader.biPlanes=1;
RGB32BitsBITMAPINFO.bmiHeader.biBitCount=32;
// pointer used for direct Bitmap pixels access
UINT * ptPixels;
HBITMAP DirectBitmap = CreateDIBSection(DirectDC,
(BITMAPINFO *)&RGB32BitsBITMAPINFO,
DIB_RGB_COLORS,
(void **)&ptPixels,
NULL, 0);
if (DirectBitmap)
{
// here DirectBitmap!=NULL so ptPixels!=NULL no need to test
HGDIOBJ PreviousObject=SelectObject(DirectDC, DirectBitmap);
BitBlt(DirectDC,0,0,
bm.bmWidth,bm.bmHeight,
BufferDC,0,0,SRCCOPY);
// here the DirectDC contains the bitmap
// Convert COLORREF to RGB (Invert RED and BLUE)
cOldColor=COLORREF2RGB(cOldColor);
cNewColor=COLORREF2RGB(cNewColor);
// After all the inits we can do the job : Replace Color
for (int i=((bm.bmWidth*bm.bmHeight)-1);i>=0;i--)
{
if (ptPixels[i]==cOldColor) ptPixels[i]=cNewColor;
}
// little clean up
// Don't delete the result of SelectObject because it's
// our modified bitmap (DirectBitmap)
SelectObject(DirectDC,PreviousObject);
// finish
RetBmp=DirectBitmap;
}
// clean up
DeleteDC(DirectDC);
}
if (hTmpBitmap)
{
SelectObject(hBmpDC, hBmp);
DeleteObject(hTmpBitmap);
}
SelectObject(BufferDC,PreviousBufferObject);
// BufferDC is now useless
DeleteDC(BufferDC);
}
}
return RetBmp;
}
现在,如果我将 24 位位图添加到我的项目中,并将背景设置为 71/71/71 并像这样加载它:
HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP,
0, 0, // cx,cy
LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS);
HBITMAP hBmp2 = ReplaceColor(hBmp, RGB(71, 71, 71), GetSysColor(COLOR_MENU), NULL);
DeleteObject(hBmp);
m_bmpSwap.Attach(hBmp2);
pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap);
结果: