Захват курсора мыши и применение маскирования прозрачности в Win32 - PullRequest
2 голосов
/ 28 мая 2019

Я пытаюсь перехватить курсор мыши, используя Windows API GetCursorInfo и получая CURSORINFO структуру после того, как я прочитал ICONINFO, используя GetIconInfo, поэтому я получу hbmMask и hbmColor растровое изображение

Растровое изображение hbmMask сначала применяется с растровой операцией AND, затем растровое изображение hbmColor применяется с растровой операцией XOR.Это приводит к непрозрачному курсору и прозрачному фону, но этого не происходит в моем полном коде POC в приведенном ниже примере.

После выполнения растров AND для данных маски и XOR для данных цвета, конечный результат будетбыть курсором и быть покрытым белым прямоугольником

 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 голосов
/ 04 июня 2019

Наконец, я нашел отличный результат, используя 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 используя width, height, ILC_COLOR32|ILC_MASK

2) Добавьте растровое изображение в ImageList_AddMasked и примените, какой цвет вы хотите сделать прозрачным, 000000 черного цвета в моемкод.

3) Получить прозрачный значок из ImageList_GetIcon .

...