2

Im trying to capture mouse cursor using windows API GetCursorInfo and taking in to CURSORINFO structure after I reading ICONINFO using GetIconInfo so I will get hbmMask and hbmColor bitmap

The hbmMask bitmap is first applied with an AND raster operation, then the hbmColor bitmap is applied with an XOR raster operation. This results in an opaque cursor and a transparent background but this is not happening in my POC complete code in below example.

After doing AND raster on mask data and XOR on color data the final result will be cursor and covered with white colored rectangle 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;
}

After saving cursor getting image like this enter image description here

Krish
  • 376
  • 3
  • 14

1 Answers1

0

Finally I found excellent result using windows API.

Include comctl32.lib in to your project

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 ) Create ImageList_Create using width, height, ILC_COLOR32|ILC_MASK

2 ) Add bitmap in to ImageList_AddMasked and apply which color you want to make transparent, 000000 are black color in my code.

3 ) Get transparent icon from ImageList_GetIcon.

Krish
  • 376
  • 3
  • 14