c++ - 捕获鼠标光标并在 Win32 中应用透明蒙版

标签 c++ image-processing cursor icons image-masking

我正在尝试使用 Windows API GetCursorInfo 捕获鼠标光标,并在使用 GetIconInfo< 读取 ICONINFO 后接收到 CURSORINFO 结构 所以我会得到 hbmMaskhbmColor 位图

hbmMask 位图首先应用AND 光栅操作,然后hbmColor 位图应用XOR光栅操作。这会导致不透明的光标和透明的背景,但这在下面示例中的 POC 完整代码中没有发生。

在对掩码数据进行AND 光栅化和对颜色数据进行XOR 之后,最终结果将是光标并覆盖有白色矩形32*32。

 void save_as_bitmap(unsigned char *bitmap_data, int rowPitch, int width, int height, char *filename)
    {
        // A file is created, this is where we will save the screen capture.

        FILE *f;

        BITMAPFILEHEADER   bmfHeader;
        BITMAPINFOHEADER   bi;

        bi.biSize = sizeof(BITMAPINFOHEADER);
        bi.biWidth = width;
        //Make the size negative if the image is upside down.
        bi.biHeight = -height;
        //There is only one plane in RGB color space where as 3 planes in YUV.
        bi.biPlanes = 1;
        //In windows RGB, 8 bit - depth for each of R, G, B and alpha.
        bi.biBitCount = 32;
        //We are not compressing the image.
        bi.biCompression = BI_RGB;
        // The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.
        bi.biSizeImage = 0;
        bi.biXPelsPerMeter = 0;
        bi.biYPelsPerMeter = 0;
        bi.biClrUsed = 0;
        bi.biClrImportant = 0;

        // rowPitch = the size of the row in bytes.
        DWORD dwSizeofImage = rowPitch * height;

        // Add the size of the headers to the size of the bitmap to get the total file size
        DWORD dwSizeofDIB = dwSizeofImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

        //Offset to where the actual bitmap bits start.
        bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

        //Size of the file
        bmfHeader.bfSize = dwSizeofDIB;

        //bfType must always be BM for Bitmaps
        bmfHeader.bfType = 0x4D42; //BM   

                                   // TODO: Handle getting current directory
        fopen_s(&f, filename, "wb");

        DWORD dwBytesWritten = 0;
        dwBytesWritten += fwrite(&bmfHeader, sizeof(BITMAPFILEHEADER), 1, f);
        dwBytesWritten += fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, f);
        dwBytesWritten += fwrite(bitmap_data, 1, dwSizeofImage, f);

        fclose(f);
    }

    //ST484 : HBIMAPtoBYTE : Convert BITMAP to BYTE array.
    std::vector<BYTE> HBIMAPtoBYTE( HBITMAP hBitmap, 
                                    int     &hBitmapSize,
                                    bool    &bResult,
                                    int     &nWidth,
                                    int     &nHeight    )
    {
        bResult = true;
        BITMAP bmp;
        if (!GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bmp)) 
        {
            DeleteObject(hBitmap);
            bResult = false;            
        }
        int rpcbiPlanes = 32;
        BITMAPINFO info;
        memset(&info, 0, sizeof(BITMAPINFO));
        info.bmiHeader.biSize       = sizeof(info.bmiHeader);
        info.bmiHeader.biWidth      = bmp.bmWidth;
        info.bmiHeader.biHeight     = -bmp.bmHeight;
        info.bmiHeader.biPlanes     = 1;
        info.bmiHeader.biBitCount   = rpcbiPlanes;
        info.bmiHeader.biCompression= BI_RGB;

        size_t pixelSize    = info.bmiHeader.biBitCount / 8;
        size_t scanlineSize = (pixelSize * info.bmiHeader.biWidth + 3) & ~3;
        size_t bitmapSize   = bmp.bmHeight * scanlineSize;

        hBitmapSize         = bitmapSize;
        nWidth              = bmp.bmWidth;
        nHeight             = bmp.bmHeight; 
        std::vector<BYTE> pixels(bitmapSize);

        HDC hdc = ::GetDC(NULL);
        if(!GetDIBits(hdc, hBitmap, 0, bmp.bmHeight, &pixels[0], &info, DIB_RGB_COLORS))
        {
            hBitmapSize = 0;
            bResult = false;                
        }

        return pixels;
    }

// getHCursor : Capture cursor.
CURSORINFO getHCursor()
{
  CURSORINFO cursorInfo;
  cursorInfo.cbSize = sizeof(CURSORINFO);

  if (GetCursorInfo(&cursorInfo) == 0) 
  { 
    MessageBox(NULL, _T("Exception  : GetCursorInfo creation failed"),_T("message"),MB_OK|MB_SYSTEMMODAL);      
    cursorInfo.hCursor = NULL;
    return cursorInfo;
  }    
  return cursorInfo;
}

//Main Call
int _tmain(int argc, _TCHAR* argv[])
{
    int CountP = 0;
    while (true)
    {       
        CURSORINFO CursorInfo = getHCursor();
        if (CursorInfo.hCursor == NULL) 
        {           
            ::Sleep(MinSleep);
            continue;
        }   

        ICONINFO iconInfo;
        if (!GetIconInfo(CursorInfo.hCursor, &iconInfo)) 
        {   
            MessageBox(NULL, _T("Exception : GetIconInfo creation failed"),_T("message"),MB_OK|MB_SYSTEMMODAL);
            ::Sleep(MinSleep);  
        }       
            std::vector<BYTE> bColorBitmap;
            std::vector<BYTE> bMaskBitmap;
            std::vector<BYTE> bDestBitmap;

            int sz_hbmColor         = 0;
            int sz_hbmMask          = 0;
            int sz_hbDest           = 0;
            int nWidth              = 0;
            int nHeight             = 0;
            bool hbmColor_result    = false;
            bool hbmMask_result     = false;
            bool hbmDest_result     = false;
            int rpcbiPlanes = 32;

            bool isColorShape = (iconInfo.hbmColor != NULL);        

            // read mask and color in to byte vector.
            bColorBitmap =  HBIMAPtoBYTE(iconInfo.hbmColor,sz_hbmColor,hbmColor_result,nWidth,nHeight);             
            bMaskBitmap  =  HBIMAPtoBYTE(iconInfo.hbmMask,sz_hbmMask,hbmMask_result,nWidth,nHeight);

            //Create Dummy bitmap using width and height filled with black color.
            HBITMAP desBitmap = CreateBitmap(nWidth,nHeight,1,rpcbiPlanes,NULL);

            if(desBitmap != NULL)
            {
                // read dummy bitmap in to byte vector.
                bDestBitmap = HBIMAPtoBYTE(desBitmap,sz_hbDest,hbmDest_result,nWidth,nHeight);

            }

            //the mask bitmap is first applied with an AND raster operation.
            for(int i = 0; i < nHeight ; i++)
            {
                for(int j = 0; j < nWidth; j++)
                {
                    bDestBitmap[i*4*nWidth + j*4    ]   &= bMaskBitmap[i*4*nWidth + j*4    ];
                    bDestBitmap[i*4*nWidth + j*4 + 1]   &= bMaskBitmap[i*4*nWidth + j*4 + 1];
                    bDestBitmap[i*4*nWidth + j*4 + 2]   &= bMaskBitmap[i*4*nWidth + j*4 + 2];
                    bDestBitmap[i*4*nWidth + j*4 + 3]   &= bMaskBitmap[i*4*nWidth + j*4 + 3];
                }
            }

            //then the color bitmap is applied with an XOR raster operation.
            for(int i = 0; i < nHeight ; i++)
            {
                for(int j = 0; j < nWidth; j++)
                {
                    bDestBitmap[i*4*nWidth + j*4    ]   ^= bColorBitmap[i*4*nWidth + j*4    ];
                    bDestBitmap[i*4*nWidth + j*4 + 1]   ^= bColorBitmap[i*4*nWidth + j*4 + 1];
                    bDestBitmap[i*4*nWidth + j*4 + 2]   ^= bColorBitmap[i*4*nWidth + j*4 + 2];
                    bDestBitmap[i*4*nWidth + j*4 + 3]   ^= bColorBitmap[i*4*nWidth + j*4 + 3];
                }
            }

            //Save Color bitmap.
            sprintf_s(file_name,"C:\\Test\\captured\\Cursor_%d.bmp", CountP);
            save_as_bitmap(&(bDestBitmap[0]), nWidth*4, nWidth, nHeight, file_name); 

            CountP++;           

        Sleep(MaxSleep);

    }   
    return 0;
}

保存光标后得到这样的图像enter image description here

最佳答案

最后我发现使用 Windows API 的结果非常好。

comctl32.lib 包含到您的项目中

HIMAGELIST iCursorList=ImageList_Create(nWidth,nHeight,ILC_COLOR32|ILC_MASK,8,8);
ImageList_AddMasked(iCursorList,iconInfo.hbmColor,000000);      
DeleteObject(iconInfo.hbmColor);
TRANSPARENT_HICON = ImageList_GetIcon(iCursorList,0,ILD_TRANSPARENT);

1)创建ImageList_Create使用宽度高度ILC_COLOR32|ILC_MASK

2 ) 添加位图到ImageList_AddMasked并应用你想要透明的颜色,000000 在我的代码中是黑色。

3)从ImageList_GetIcon获取透明图标.

关于c++ - 捕获鼠标光标并在 Win32 中应用透明蒙版,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56338674/

相关文章:

android - 在 ContentValues 中查询

c++ - 有没有办法在指向类类型的指针中不使用 * 来调用类运算符?

algorithm - 如何减少二值图像中的背景噪声

c++ - vector 的预分配 vector ,但在填充时内存仍然线性增加

opencv - 使用 OpenCL 和 GPU 不会提高我的相机的 fps 性能

c# - Spring 圈圈数怎么算?

image - 将 GIF 转换为 CUR 文件

java - 将数据从 Cursor 绑定(bind)到 Spinner Android

c++ - Boost::Log - 使用严重性和自定义过滤器属性记录?使用哪个宏?

c++ - 在给定按钮窗口句柄的情况下,如何模拟按钮单击?