[PATCH] user32: Create a mask from alpha channel when loading a 32 bpp icon.

Dmitry Timoshkov dmitry at baikal.ru
Tue Jul 17 23:23:34 CDT 2018


This patch fixes an application that draws user32 icons manually:

hicon = LoadImage(NULL, "oic_ques.ico", IMAGE_ICON, 256, 256, LR_LOADFROMFILE);
GetIconInfo(hicon, &info);
GetObject(info.hbmMask, sizeof(bm), &bm);

hMemDC = CreateCompatibleDC(hdc);

SelectObject(hMemDC, info.hbmColor);
StretchBlt(hdc, 200, 0, 200, 200,
           hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

SelectObject(hMemDC, info.hbmMask);
StretchBlt(hdc, 400, 0, 200, 200,
           hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCAND);
SelectObject(hMemDC, info.hbmColor);
StretchBlt(hdc, 400, 0, 200, 200,
           hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCINVERT);

For testing purposes I edited dlls/user32/resources/oic_ques.ico and
removed everything except the 256x256 32 bpp PNG image. Then I created
a test app that draws separately mask and color bitmaps from the icon
info and then draws an icon using the code above. With this patch
under Wine the mask and the final icon visually look similar to what
I see under Windows.

Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/user32/cursoricon.c | 97 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 0adb73bf56..c561c70364 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -1131,6 +1131,93 @@ done:
     return alpha;
 }
 
+static HBITMAP create_alpha_mask( HBITMAP color )
+{
+    HBITMAP alpha;
+    char info_buf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
+    BITMAPINFO *info = (BITMAPINFO *)info_buf;
+    BITMAP bm;
+    HDC hdc;
+    void *bits;
+    unsigned char *ptr;
+    int i;
+
+    if (!GetObjectW( color, sizeof(bm), &bm )) return 0;
+    if (bm.bmBitsPixel != 32) return 0;
+
+    if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
+
+    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info->bmiHeader.biWidth = bm.bmWidth;
+    info->bmiHeader.biHeight = -bm.bmHeight;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = 32;
+    info->bmiHeader.biCompression = BI_RGB;
+    info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
+    info->bmiHeader.biXPelsPerMeter = 0;
+    info->bmiHeader.biYPelsPerMeter = 0;
+    info->bmiHeader.biClrUsed = 0;
+    info->bmiHeader.biClrImportant = 0;
+    if (!(alpha = CreateDIBSection( hdc, info, DIB_RGB_COLORS, &bits, NULL, 0 ))) goto done;
+
+    GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS );
+    if (!bmi_has_alpha( info, bits ))
+    {
+        DeleteObject( alpha );
+        alpha = 0;
+        goto done;
+    }
+
+    for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
+    {
+        if (ptr[3] == 0xff)
+            ptr[0] = ptr[1] = ptr[2] = 0;
+        else
+            ptr[0] = ptr[1] = ptr[2] = 0xff;
+
+        ptr[3] = 0;
+    }
+
+done:
+    DeleteDC( hdc );
+    return alpha;
+}
+
+static HBITMAP create_mask_from_alpha( HBITMAP color )
+{
+    BITMAP bm;
+    HBITMAP alpha, mask;
+    HDC hdc_dst, hdc_src;
+
+    alpha = create_alpha_mask( color );
+    if (!alpha) return 0;
+
+    GetObjectW( alpha, sizeof(bm), &bm );
+
+    mask = CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL );
+    if (!mask) return 0;
+
+    hdc_src = CreateCompatibleDC( 0 );
+    hdc_dst = CreateCompatibleDC( 0 );
+    if (hdc_src && hdc_dst)
+    {
+        SelectObject( hdc_src, alpha );
+        SelectObject( hdc_dst, mask );
+        BitBlt( hdc_dst, 0, 0, bm.bmWidth, bm.bmHeight, hdc_src, 0, 0, SRCCOPY );
+    }
+    else
+    {
+        DeleteObject( mask );
+        mask = 0;
+    }
+
+    DeleteDC( hdc_src );
+    DeleteDC( hdc_dst );
+    DeleteObject( alpha );
+
+    return mask;
+}
+
 
 /***********************************************************************
  *          create_icon_from_bmi
@@ -1296,6 +1383,16 @@ static HICON create_icon_from_bmi( const BITMAPINFO *bmi, DWORD maxsize, HMODULE
                        0, 0, bmi_width, bmi_height,
                        mask_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );
     }
+    else
+    {
+        HBITMAP alpha_mask = create_mask_from_alpha( color );
+
+        if (alpha_mask)
+        {
+            DeleteObject( mask );
+            mask = alpha_mask;
+        }
+    }
     ret = TRUE;
 
 done:
-- 
2.17.1




More information about the wine-devel mailing list