- Use CreateDIBitmap with the CDM_CREATEDIB undocumented flag to create alpha bitmaps. This permits to create display compatible yet 32bpp DDBs.
CORE-8695 #comment PLease retest, should be OK now.

svn path=/trunk/; revision=64967
This commit is contained in:
Jérôme Gardou 2014-10-24 17:31:50 +00:00
parent a09a102a08
commit 954bd930d0

View file

@ -241,56 +241,41 @@ static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
* *
* Create the alpha bitmap for a 32-bpp icon that has an alpha channel. * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
*/ */
static HBITMAP create_alpha_bitmap( static
_In_ HBITMAP color, HBITMAP
_In_opt_ const BITMAPINFO *src_info, create_alpha_bitmap(
_In_opt_ const void *color_bits ) _In_opt_ HBITMAP color,
_In_opt_ BITMAPINFO *src_info,
_In_opt_ const void *color_bits,
_In_ LONG width,
_In_ LONG height)
{ {
HBITMAP alpha = NULL, hbmpOld; HBITMAP alpha = NULL, hbmpOld;
BITMAPINFO *info = NULL;
HDC hdc = NULL, hdcScreen; HDC hdc = NULL, hdcScreen;
void *bits = NULL;
unsigned char *ptr; unsigned char *ptr;
void *bits = NULL;
int i; int i;
LONG width, height;
BITMAP bm;
if (!GetObjectW( color, sizeof(bm), &bm ))
return NULL;
if (bm.bmBitsPixel != 32)
return NULL;
hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
if(!hdcScreen) if (!hdcScreen)
return NULL; return NULL;
if(GetDeviceCaps(hdcScreen, BITSPIXEL) != 32)
goto done;
hdc = CreateCompatibleDC(hdcScreen); hdc = CreateCompatibleDC(hdcScreen);
if(!hdc) if (!hdc)
goto done;
if(src_info)
{ {
WORD bpp; DeleteDC(hdcScreen);
DWORD compr; return NULL;
int size;
if(!bmi_has_alpha(src_info, color_bits))
goto done;
if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &width, &height, &bpp, &compr))
goto done;
if(bpp != 32)
goto done;
size = get_dib_image_size(width, height, bpp);
bits = HeapAlloc(GetProcessHeap(), 0, size);
if(!bits)
goto done;
CopyMemory(bits, color_bits, size);
} }
else
if (color)
{ {
BITMAP bm;
BITMAPINFO *info = NULL;
if (!GetObjectW( color, sizeof(bm), &bm ))
goto done;
if (bm.bmBitsPixel != 32)
goto done;
info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])); info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256]));
if(!info) if(!info)
goto done; goto done;
@ -308,46 +293,116 @@ static HBITMAP create_alpha_bitmap(
bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage); bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage);
if(!bits) if(!bits)
{
HeapFree(GetProcessHeap(), 0, info);
goto done; goto done;
}
if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS ))
{
HeapFree(GetProcessHeap(), 0, info);
goto done; goto done;
}
if (!bmi_has_alpha( info, bits )) if (!bmi_has_alpha( info, bits ))
{
HeapFree(GetProcessHeap(), 0, info);
goto done; goto done;
width = bm.bmWidth; }
height = bm.bmHeight;
}
/* pre-multiply by alpha */ /* pre-multiply by alpha */
for (i = 0, ptr = bits; i < width * height; i++, ptr += 4) for (i = 0, ptr = bits; i < width * height; i++, ptr += 4)
{ {
unsigned int alpha = ptr[3]; unsigned int alpha = ptr[3];
ptr[0] = ptr[0] * alpha / 255; ptr[0] = (ptr[0] * alpha) / 255;
ptr[1] = ptr[1] * alpha / 255; ptr[1] = (ptr[1] * alpha) / 255;
ptr[2] = ptr[2] * alpha / 255; ptr[2] = (ptr[2] * alpha) / 255;
} }
/* Create the bitmap */ /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
alpha = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight); alpha = CreateDIBitmap(hdc, NULL, CBM_INIT | 2, bits, info, DIB_RGB_COLORS);
if(!alpha)
goto done; HeapFree(GetProcessHeap(), 0, info);
hbmpOld = SelectObject(hdc, alpha); HeapFree(GetProcessHeap(), 0, bits);
if(!hbmpOld) }
goto done; else
if(!StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight, {
0, 0, width, height, WORD bpp;
bits, src_info ? src_info : info, DIB_RGB_COLORS, SRCCOPY )) DWORD compr;
{ int size;
SelectObject(hdc, hbmpOld); LONG orig_width, orig_height;
hbmpOld = NULL;
DeleteObject(alpha); if(!bmi_has_alpha(src_info, color_bits))
alpha = NULL; goto done;
if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &orig_width, &orig_height, &bpp, &compr))
goto done;
if(bpp != 32)
goto done;
size = get_dib_image_size(orig_width, orig_height, bpp);
bits = HeapAlloc(GetProcessHeap(), 0, size);
if(!bits)
goto done;
CopyMemory(bits, color_bits, size);
/* pre-multiply by alpha */
for (i = 0, ptr = bits; i < width * height; i++, ptr += 4)
{
unsigned int alpha = ptr[3];
ptr[0] = (ptr[0] * alpha) / 255;
ptr[1] = (ptr[1] * alpha) / 255;
ptr[2] = (ptr[2] * alpha) / 255;
}
/* Create the bitmap. Set the bitmap info to have the right width and height */
if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = width;
((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = height;
}
else
{
src_info->bmiHeader.biWidth = width;
src_info->bmiHeader.biHeight = height;
}
/* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
alpha = CreateDIBitmap(hdcScreen, NULL, 2, NULL, src_info, DIB_RGB_COLORS);
/* Restore values */
if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = orig_width;
((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = orig_height;
}
else
{
src_info->bmiHeader.biWidth = orig_width;
src_info->bmiHeader.biHeight = orig_height;
}
if(!alpha)
goto done;
hbmpOld = SelectObject(hdc, alpha);
if(!hbmpOld)
{
DeleteObject(alpha);
alpha = NULL;
goto done;
}
if(!StretchDIBits( hdc, 0, 0, width, height,
0, 0, orig_width, orig_height,
bits, src_info, DIB_RGB_COLORS, SRCCOPY ))
{
SelectObject(hdc, hbmpOld);
hbmpOld = NULL;
DeleteObject(alpha);
alpha = NULL;
}
else
{
SelectObject(hdc, hbmpOld);
}
} }
SelectObject(hdc, hbmpOld);
done: done:
DeleteDC(hdcScreen); DeleteDC(hdcScreen);
if(hdc) DeleteDC( hdc ); DeleteDC( hdc );
if(info) HeapFree( GetProcessHeap(), 0, info );
if(bits) HeapFree(GetProcessHeap(), 0, bits); if(bits) HeapFree(GetProcessHeap(), 0, bits);
TRACE("Returning 0x%08x.\n", alpha); TRACE("Returning 0x%08x.\n", alpha);
@ -571,8 +626,7 @@ static BOOL CURSORICON_GetCursorDataFromBMI(
pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
goto done; goto done;
pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL); pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL);
if(pdata->bpp == 32) pdata->hbmAlpha = create_alpha_bitmap(NULL, pbmiCopy, pvColor, pdata->cx, pdata->cy);
pdata->hbmAlpha = create_alpha_bitmap(pdata->hbmColor, pbmiCopy, pvColor);
/* Now convert the info to monochrome for the mask bits */ /* Now convert the info to monochrome for the mask bits */
if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
@ -673,7 +727,7 @@ static BOOL CURSORICON_GetCursorDataFromIconInfo(
pCursorData->cx = bm.bmWidth; pCursorData->cx = bm.bmWidth;
pCursorData->cy = bm.bmHeight; pCursorData->cy = bm.bmHeight;
if(pCursorData->bpp == 32) if(pCursorData->bpp == 32)
pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL); pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL, 0, 0);
} }
else else
{ {