How to show menu bitmaps with transparent background
我正在使用此代码:
1 2 | m_bmpSwap.LoadBitmap(IDB_BITMAP2); pMnuPopup->SetMenuItemBitmaps(0, MF_BYPOSITION, &m_bmpSwap, &m_bmpSwap); |
它看起来像:
这只是一个测试图像:
我如何准确地使图像看起来像具有透明背景?
这是24位图像。
我已经看到了,但是我无法解决。
我调整为以192/192/192为背景的8位图像,并像这样加载:
1 2 3 4 5 6 7 8 9 10 | 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位图像作为菜单位图?
添加
这将适用于8位或4位图像(未经Windows百叶窗测试)
或者您可以手动更改背景颜色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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); } |
用法:
1 2 3 4 | CBitmap bmp; bmp.LoadBitmap(IDB_BITMAP1); swap_color(bmp); menu.SetMenuItemBitmaps(0, MF_BYPOSITION, &bmp, &bmp); |
我找到了这篇文章。我在这里复制生成的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #define COLORREF2RGB(Color) (Color & 0xff00) | ((Color >> 16) & 0xff) \\ | ((Color << 16) & 0xff0000) //------------------------------------------------------------------------------- // ReplaceColor // // Author : Dimitri Rochette [email protected] // 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并像这样加载它:
1 2 3 4 5 6 7 8 9 10 | 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); |
结果: