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

Alexandre Julliard julliard at winehq.org
Fri Jul 20 03:04:22 CDT 2018


Dmitry Timoshkov <dmitry at baikal.ru> writes:

> 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;
> +}

This seems to be a lot of redundant code. It shouldn't be necessary to
allocate a new DIB section and copy the bits again, we already have
access to the original data. Also the mask bitmap is already allocated,
and we already have code for blitting to it. You should be able to
simply build a mask_bits array and go through the existing code paths.

-- 
Alexandre Julliard
julliard at winehq.org



More information about the wine-devel mailing list