windowscodecs: Fix the bug when the input palette hpal is NULL in ImagingFactory_CreateBitmapFromHBITMAP.
When the palette is given NULL and the format is 1/4/8bppIndexed, palette info is lost. It causes incorrect color calculation when the WIC interface is called later.
Signed-off-by: yangkun yangkun@uniontech.com Change-Id: I851373e9186dc815488235f0fc219d8fbdd91658
From: yangkun yangkun@uniontech.com
When the palette is given NULL and the format is 1/4/8bppIndexed, palette info is lost. It causes incorrect color calculation when the WIC interface is called later.
Signed-off-by: yangkun yangkun@uniontech.com Change-Id: I851373e9186dc815488235f0fc219d8fbdd91658 --- dlls/windowscodecs/imgfactory.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index e2ffd6da3f4..62acc35f9da 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -769,6 +769,34 @@ static HRESULT WINAPI ImagingFactory_CreateBitmapFromHBITMAP(IWICImagingFactory2 return E_INVALIDARG; }
+ if (!hpal && + (IsEqualGUID(&format, &GUID_WICPixelFormat1bppIndexed) || + IsEqualGUID(&format, &GUID_WICPixelFormat4bppIndexed) || + IsEqualGUID(&format, &GUID_WICPixelFormat8bppIndexed))) + { + HDC hdc_palette = CreateCompatibleDC(0); + char bmibuf_palette[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; + BITMAPINFO *bmi_palette = (BITMAPINFO *)bmibuf_palette; + bmi_palette->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi_palette->bmiHeader.biBitCount = 0; + + if(GetDIBits(hdc_palette, hbm, 0, 0, NULL, bmi_palette, DIB_RGB_COLORS)) + { + num_palette_entries = bmi_palette->bmiHeader.biClrUsed ? bmi_palette->bmiHeader.biClrUsed : (UINT)(1 << bmi_palette->bmiHeader.biBitCount); + if (GetDIBits(hdc_palette, hbm, 0, 0, (LPVOID)entry, bmi_palette, DIB_RGB_COLORS)) + { + for (UINT i = 0; i < num_palette_entries; i++) + { + entry[i].peRed = bmi_palette->bmiColors[i].rgbRed; + entry[i].peGreen = bmi_palette->bmiColors[i].rgbGreen; + entry[i].peBlue = bmi_palette->bmiColors[i].rgbBlue; + entry[i].peFlags = 0; + } + } + } + DeleteDC(hdc_palette); + } + hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, 0, &format, WICBitmapCacheOnLoad, bitmap); if (hr != S_OK) return hr;
In the function ImagingFactory_CreateBitmapFromHBITMAP, the hpal can be given NULL by application. In current wine, the color calculation is wrong for the format GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat4bppIndexed and GUID_WICPixelFormat8bppIndexed if the application does not pass palette argument. WIC bitmap can not be used in the later WIC operation, such as FormatConverter_CopyPixels. After testing the code on the Windows system, I believe it should be handled as follows: If palette is NULL, and the format needs a palette to build color. It is necessary to obtain the bmiColors of the hbitmap at the time of its creation, such as CreateDIBSection.
This is an 8bpp WIC program that does not run correctly under the current Wine.
[wincodecs_test.c](/uploads/ad8051925814bb1d92d936134c8c3c9c/wincodecs_test.c)
[wincodecs_test.exe](/uploads/53c8e520cfc415282c4221ac8789e7e6/wincodecs_test.exe)
Esme Povirk (@madewokherd) commented about dlls/windowscodecs/imgfactory.c:
- if (!hpal &&
(IsEqualGUID(&format, &GUID_WICPixelFormat1bppIndexed) ||IsEqualGUID(&format, &GUID_WICPixelFormat4bppIndexed) ||IsEqualGUID(&format, &GUID_WICPixelFormat8bppIndexed)))- {
HDC hdc_palette = CreateCompatibleDC(0);char bmibuf_palette[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];BITMAPINFO *bmi_palette = (BITMAPINFO *)bmibuf_palette;bmi_palette->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmi_palette->bmiHeader.biBitCount = 0;if(GetDIBits(hdc_palette, hbm, 0, 0, NULL, bmi_palette, DIB_RGB_COLORS)){num_palette_entries = bmi_palette->bmiHeader.biClrUsed ? bmi_palette->bmiHeader.biClrUsed : (UINT)(1 << bmi_palette->bmiHeader.biBitCount);if (GetDIBits(hdc_palette, hbm, 0, 0, (LPVOID)entry, bmi_palette, DIB_RGB_COLORS))
I'm confused about the use of `entry` here. That argument is supposed to point to bitmap bits?
Esme Povirk (@madewokherd) commented about dlls/windowscodecs/imgfactory.c:
bmi->bmiHeader.biBitCount = 0; GetDIBits(hdc, hbm, 0, 0, NULL, bmi, DIB_RGB_COLORS); bmi->bmiHeader.biHeight = -bm.bmHeight; GetDIBits(hdc, hbm, 0, bm.bmHeight, buffer, bmi, DIB_RGB_COLORS);
I think this GetDIBits call will read the palette, and it would be simpler to use that.
On Wed Nov 12 21:41:42 2025 +0000, Esme Povirk wrote:
I think this GetDIBits call will read the palette, and it would be simpler to use that.
Do you mean that I move the code which calculates num_palette_entries to line 819 and use the palette in GetDIBits in line 820? @madewokherd
On Mon Nov 17 09:39:46 2025 +0000, Kun Yang wrote:
Do you mean that I move the code which calculates num_palette_entries to line 819 and use the palette in GetDIBits in line 820? @madewokherd
Yes.