diff --git a/dlls/windowscodecs/Makefile.in b/dlls/windowscodecs/Makefile.in index d031daa85a1..ffe092565d0 100644 --- a/dlls/windowscodecs/Makefile.in +++ b/dlls/windowscodecs/Makefile.in @@ -1,6 +1,6 @@ MODULE = windowscodecs.dll IMPORTLIB = windowscodecs -IMPORTS = uuid ole32 oleaut32 shlwapi advapi32 rpcrt4 +IMPORTS = uuid ole32 oleaut32 rpcrt4 shlwapi user32 gdi32 advapi32 EXTRAINCL = @PNGINCL@ EXTRADEFS = -DENTRY_PREFIX=WIC_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL EXTRALIBS = @APPLICATIONSERVICESLIB@ diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index 1d05ef55348..8762c816694 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -597,10 +597,142 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHBITMAP(IWICComponentFact } static HRESULT WINAPI ComponentFactory_CreateBitmapFromHICON(IWICComponentFactory *iface, - HICON hIcon, IWICBitmap **ppIBitmap) + HICON hicon, IWICBitmap **bitmap) { - FIXME("(%p,%p,%p): stub\n", iface, hIcon, ppIBitmap); - return E_NOTIMPL; + IWICBitmapLock *lock; + ICONINFO info; + BITMAP bm; + int width, height, x, y; + UINT stride, size; + BYTE *buffer; + DWORD *bits; + BITMAPINFO bi; + HDC hdc; + BOOL has_alpha; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", iface, hicon, bitmap); + + if (!bitmap) return E_INVALIDARG; + + if (!GetIconInfo(hicon, &info)) + return HRESULT_FROM_WIN32(GetLastError()); + + GetObjectW(info.hbmColor ? info.hbmColor : info.hbmMask, sizeof(bm), &bm); + + width = bm.bmWidth; + height = info.hbmColor ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2; + stride = width * 4; + size = stride * height; + + hr = BitmapImpl_Create(width, height, stride, size, NULL, + &GUID_WICPixelFormat32bppBGRA, WICBitmapCacheOnLoad, bitmap); + if (hr != S_OK) goto failed; + + hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock); + if (hr != S_OK) + { + IWICBitmap_Release(*bitmap); + goto failed; + } + IWICBitmapLock_GetDataPointer(lock, &size, &buffer); + + hdc = CreateCompatibleDC(0); + + memset(&bi, 0, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = width; + bi.bmiHeader.biHeight = -height; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + + has_alpha = FALSE; + + if (info.hbmColor) + { + GetDIBits(hdc, info.hbmColor, 0, height, buffer, &bi, DIB_RGB_COLORS); + + if (bm.bmBitsPixel == 32) + { + /* If any pixel has a non-zero alpha, ignore hbmMask */ + bits = (DWORD *)buffer; + for (x = 0; x < width && !has_alpha; x++, bits++) + { + for (y = 0; y < height; y++) + { + if (*bits & 0xff000000) + { + has_alpha = TRUE; + break; + } + } + } + } + } + else + GetDIBits(hdc, info.hbmMask, 0, height, buffer, &bi, DIB_RGB_COLORS); + + if (!has_alpha) + { + DWORD *rgba; + + if (info.hbmMask) + { + BYTE *mask; + + mask = HeapAlloc(GetProcessHeap(), 0, size); + if (!mask) + { + IWICBitmapLock_Release(lock); + IWICBitmap_Release(*bitmap); + DeleteDC(hdc); + hr = E_OUTOFMEMORY; + goto failed; + } + + /* read alpha data from the mask */ + GetDIBits(hdc, info.hbmMask, info.hbmColor ? 0 : height, height, mask, &bi, DIB_RGB_COLORS); + + for (y = 0; y < height; y++) + { + rgba = (DWORD *)(buffer + y * stride); + bits = (DWORD *)(mask + y * stride); + + for (x = 0; x < width; x++, rgba++, bits++) + { + if (!info.hbmColor) *rgba = ~*rgba; + + if (*bits) + *rgba = 0; + else + *rgba |= 0xff000000; + } + } + + HeapFree(GetProcessHeap(), 0, mask); + } + else + { + /* set constant alpha of 255 */ + for (y = 0; y < height; y++) + { + rgba = (DWORD *)(buffer + y * stride); + for (x = 0; x < width; x++, rgba++) + *rgba |= 0xff000000; + } + } + + } + + IWICBitmapLock_Release(lock); + DeleteDC(hdc); + +failed: + DeleteObject(info.hbmColor); + DeleteObject(info.hbmMask); + + return hr; } static HRESULT WINAPI ComponentFactory_CreateComponentEnumerator(IWICComponentFactory *iface, diff --git a/dlls/windowscodecs/tests/bitmap.c b/dlls/windowscodecs/tests/bitmap.c index 40b8ce6865a..fb7183ba255 100644 --- a/dlls/windowscodecs/tests/bitmap.c +++ b/dlls/windowscodecs/tests/bitmap.c @@ -529,19 +529,15 @@ static void test_CreateBitmapFromHICON(void) DeleteObject(info.hbmMask); hr = IWICImagingFactory_CreateBitmapFromHICON(factory, 0, NULL); -todo_wine ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr); hr = IWICImagingFactory_CreateBitmapFromHICON(factory, 0, &bitmap); -todo_wine ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_CURSOR_HANDLE), "expected ERROR_INVALID_CURSOR_HANDLE, got %#x\n", hr); hr = IWICImagingFactory_CreateBitmapFromHICON(factory, icon, NULL); -todo_wine ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr); hr = IWICImagingFactory_CreateBitmapFromHICON(factory, icon, &bitmap); -todo_wine ok(hr == S_OK, "CreateBitmapFromHICON error %#x\n", hr); DestroyIcon(icon); if (hr != S_OK) return;