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

时间:2019-05-28 09:10:11

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

我尝试使用Windows API GetCursorInfo捕获鼠标光标,并在使用CURSORINFO阅读ICONINFO之后进入GetIconInfo结构,因此我将获得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

1 个答案:

答案 0 :(得分:0)

最后,我发现使用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)使用widthheightILC_COLOR32|ILC_MASK

创建ImageList_Create

2)将位图添加到ImageList_AddMasked中,并应用您想要使其透明的颜色,000000在我的代码中为黑色。

3)从ImageList_GetIcon获取透明图标。