[PATCH 4/4] windowscodecs: Add support for converting to 8bppIndexed format.

Dmitry Timoshkov dmitry at baikal.ru
Wed Jan 30 19:56:11 CST 2019


Signed-off-by: Dmitry Timoshkov <dmitry at 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




More information about the wine-devel mailing list