Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/windowscodecs/converter.c | 160 +++++++++++++++++++++++++++++---- 1 file changed, 143 insertions(+), 17 deletions(-)
diff --git a/dlls/windowscodecs/converter.c b/dlls/windowscodecs/converter.c index 6e7bb8e781..a6795fb706 100644 --- a/dlls/windowscodecs/converter.c +++ b/dlls/windowscodecs/converter.c @@ -76,7 +76,7 @@ typedef struct FormatConverter { const struct pixelformatinfo *dst_format, *src_format; WICBitmapDitherType dither; double alpha_threshold; - WICBitmapPaletteType palette_type; + IWICPalette *palette; CRITICAL_SECTION lock; /* must be held when initialized */ } FormatConverter;
@@ -1219,11 +1219,96 @@ static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRec return hr; }
+static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count) +{ + UINT best_diff, best_index, i; + + best_diff = ~0; + best_index = 0; + + for (i = 0; i < count; i++) + { + BYTE pal_r, pal_g, pal_b; + UINT diff_r, diff_g, diff_b, diff; + + pal_r = colors[i] >> 16; + pal_g = colors[i] >> 8; + pal_b = colors[i]; + + diff_r = bgr[2] - pal_r; + diff_g = bgr[1] - pal_g; + diff_b = bgr[0] - pal_b; + + diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b; + if (diff == 0) return i; + + if (diff < best_diff) + { + best_diff = diff; + best_index = i; + } + } + + return best_index; +} + +static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + HRESULT hr; + BYTE *srcdata; + WICColor colors[256]; + UINT srcstride, srcdatasize, count; + + if (source_format == format_8bppIndexed) + { + if (prc) + return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); + + return S_OK; + } + + if (!This->palette) return WINCODEC_ERR_WRONGSTATE; + + hr = IWICPalette_GetColors(This->palette, 256, colors, &count); + if (hr != S_OK) return hr; + if (!count) return WINCODEC_ERR_WRONGSTATE; + + srcstride = 3 * prc->Width; + srcdatasize = srcstride * prc->Height; + + srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + if (!srcdata) return E_OUTOFMEMORY; + + hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format); + if (SUCCEEDED(hr) && prc) + { + INT x, y; + BYTE *src = srcdata, *dst = pbBuffer; + + for (y = 0; y < prc->Height; y++) + { + BYTE *bgr = src; + + for (x = 0; x < prc->Width; x++) + { + dst[x] = rgb_to_palette_index(bgr, colors, count); + bgr += 3; + } + src += srcstride; + dst += cbStride; + } + } + + HeapFree(GetProcessHeap(), 0, srcdata); + return hr; +} + static const struct pixelformatinfo supported_formats[] = { {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL}, {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL}, {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL}, - {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL}, + {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed}, {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL}, {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL}, {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL}, @@ -1300,6 +1385,7 @@ static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface) This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); if (This->source) IWICBitmapSource_Release(This->source); + if (This->palette) IWICPalette_Release(This->palette); HeapFree(GetProcessHeap(), 0, This); }
@@ -1348,10 +1434,16 @@ static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface, }
static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface, - IWICPalette *pIPalette) + IWICPalette *palette) { - FIXME("(%p,%p): stub\n", iface, pIPalette); - return E_NOTIMPL; + FormatConverter *This = impl_from_IWICFormatConverter(iface); + + TRACE("(%p,%p)\n", iface, palette); + + if (!palette) return E_INVALIDARG; + if (!This->palette) return WINCODEC_ERR_WRONGSTATE; + + return IWICPalette_InitializeFromPalette(palette, This->palette); }
static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface, @@ -1384,19 +1476,52 @@ static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface, }
static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, - IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither, - IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate) + IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither, + IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type) { FormatConverter *This = impl_from_IWICFormatConverter(iface); const struct pixelformatinfo *srcinfo, *dstinfo; - static INT fixme=0; GUID srcFormat; - HRESULT res=S_OK; + HRESULT res; + + TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat), + dither, palette, alpha_threshold, palette_type); + + if (!palette) + { + res = PaletteImpl_Create(&palette); + if (res != S_OK) return res; + + switch (palette_type) + { + case WICBitmapPaletteTypeCustom: + IWICPalette_Release(palette); + palette = NULL; + res = S_OK; + break; + + case WICBitmapPaletteTypeMedianCut: + { + UINT bpp; + res = get_pixelformat_bpp(dstFormat, &bpp); + if (res == S_OK && bpp <= 8) + res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE); + break; + }
- TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat), - dither, pIPalette, alphaThresholdPercent, paletteTranslate); + default: + res = IWICPalette_InitializePredefined(palette, palette_type, FALSE); + break; + }
- if (pIPalette && !fixme++) FIXME("ignoring palette\n"); + if (res != S_OK) + { + IWICPalette_Release(palette); + return res; + } + } + else + IWICPalette_AddRef(palette);
EnterCriticalSection(&This->lock);
@@ -1406,7 +1531,7 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, goto end; }
- res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat); + res = IWICBitmapSource_GetPixelFormat(source, &srcFormat); if (FAILED(res)) goto end;
srcinfo = get_formatinfo(&srcFormat); @@ -1427,13 +1552,13 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
if (dstinfo->copy_function) { - IWICBitmapSource_AddRef(pISource); + IWICBitmapSource_AddRef(source); This->src_format = srcinfo; This->dst_format = dstinfo; This->dither = dither; - This->alpha_threshold = alphaThresholdPercent; - This->palette_type = paletteTranslate; - This->source = pISource; + This->alpha_threshold = alpha_threshold; + This->palette = palette; + This->source = source; } else { @@ -1512,6 +1637,7 @@ HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv) This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl; This->ref = 1; This->source = NULL; + This->palette = NULL; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
+ srcstride = 3 * prc->Width; + srcdatasize = srcstride * prc->Height;
I think this will crash if called from CanConvert which uses a NULL prc.