Signed-off-by: Dmitry Timoshkov <dmitry(a)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");
--
2.20.1