[PATCH 3/8] windowscodecs: Add support for palette image formats to BMP encoder.

Dmitry Timoshkov dmitry at baikal.ru
Thu Dec 6 03:05:55 CST 2018


Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/windowscodecs/bmpencode.c       | 47 ++++++++++++++++++++++------
 dlls/windowscodecs/info.c            |  8 ++++-
 dlls/windowscodecs/regsvr.c          |  4 +++
 dlls/windowscodecs/tests/converter.c | 11 +++++--
 4 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/dlls/windowscodecs/bmpencode.c b/dlls/windowscodecs/bmpencode.c
index b8783a499e..8e2bbe8091 100644
--- a/dlls/windowscodecs/bmpencode.c
+++ b/dlls/windowscodecs/bmpencode.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Vincent Povirk for CodeWeavers
+ * Copyright 2016 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -37,6 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 struct bmp_pixelformat {
     const WICPixelFormatGUID *guid;
     UINT bpp;
+    UINT colors; /* palette size */
     DWORD compression;
     DWORD redmask;
     DWORD greenmask;
@@ -45,13 +47,18 @@ struct bmp_pixelformat {
 };
 
 static const struct bmp_pixelformat formats[] = {
-    {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
-    {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB},
-    {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
-    {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB},
+    {&GUID_WICPixelFormat24bppBGR, 24, 0, BI_RGB},
+    {&GUID_WICPixelFormatBlackWhite, 1, 2, BI_RGB},
+    {&GUID_WICPixelFormat1bppIndexed, 1, 2, BI_RGB},
+    {&GUID_WICPixelFormat2bppIndexed, 2, 4, BI_RGB},
+    {&GUID_WICPixelFormat4bppIndexed, 4, 16, BI_RGB},
+    {&GUID_WICPixelFormat8bppIndexed, 8, 256, BI_RGB},
+    {&GUID_WICPixelFormat16bppBGR555, 16, 0, BI_RGB},
+    {&GUID_WICPixelFormat16bppBGR565, 16, 0, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
+    {&GUID_WICPixelFormat32bppBGR, 32, 0, BI_RGB},
 #if 0
     /* Windows doesn't seem to support this one. */
-    {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
+    {&GUID_WICPixelFormat32bppBGRA, 32, 0, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
 #endif
     {NULL}
 };
@@ -182,9 +189,14 @@ static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface
 
     if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
 
+    if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormatBlackWhite))
+        *pPixelFormat = GUID_WICPixelFormat1bppIndexed;
+    else if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormat2bppIndexed))
+        *pPixelFormat = GUID_WICPixelFormat4bppIndexed;
+
     for (i=0; formats[i].guid; i++)
     {
-        if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
+        if (IsEqualGUID(formats[i].guid, pPixelFormat))
             break;
     }
 
@@ -207,6 +219,7 @@ static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
     IWICPalette *palette)
 {
     BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr;
 
     TRACE("(%p,%p)\n", iface, palette);
 
@@ -215,7 +228,14 @@ static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
     if (!This->initialized)
         return WINCODEC_ERR_NOTINITIALIZED;
 
-    return IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+    hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+    if (hr == S_OK)
+    {
+        UINT i;
+        for (i = 0; i < This->colors; i++)
+            This->palette[i] |= 0xff000000; /* BMP palette has no alpha */
+    }
+    return hr;
 }
 
 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
@@ -330,8 +350,8 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
     bih.bV5SizeImage = This->stride*This->height;
     bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
     bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
-    bih.bV5ClrUsed = 0;
-    bih.bV5ClrImportant = 0;
+    bih.bV5ClrUsed = (This->format->bpp <= 8) ? This->colors : 0;
+    bih.bV5ClrImportant = bih.bV5ClrUsed;
 
     if (This->format->compression == BI_BITFIELDS)
     {
@@ -348,6 +368,7 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
 
     bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
     bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
+    bfh.bfOffBits += bih.bV5ClrUsed * sizeof(WICColor);
 
     pos.QuadPart = 0;
     hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
@@ -361,6 +382,14 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
     if (FAILED(hr)) return hr;
     if (byteswritten != info_size) return E_FAIL;
 
+    /* write the palette */
+    if (This->format->colors)
+    {
+        hr = IStream_Write(This->stream, This->palette, This->colors * sizeof(WICColor), &byteswritten);
+        if (FAILED(hr)) return hr;
+        if (byteswritten != This->colors * sizeof(WICColor)) return E_FAIL;
+    }
+
     hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
     if (FAILED(hr)) return hr;
     if (byteswritten != bih.bV5SizeImage) return E_FAIL;
diff --git a/dlls/windowscodecs/info.c b/dlls/windowscodecs/info.c
index e131107e99..86707e1253 100644
--- a/dlls/windowscodecs/info.c
+++ b/dlls/windowscodecs/info.c
@@ -2461,6 +2461,12 @@ HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnkn
     return hr;
 }
 
+static BOOL is_1bpp_format(const WICPixelFormatGUID *format)
+{
+    return IsEqualGUID(format, &GUID_WICPixelFormatBlackWhite) ||
+           IsEqualGUID(format, &GUID_WICPixelFormat1bppIndexed);
+}
+
 HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
 {
     HRESULT res;
@@ -2476,7 +2482,7 @@ HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitma
     res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
     if (FAILED(res)) return res;
 
-    if (IsEqualGUID(&srcFormat, dstFormat))
+    if (IsEqualGUID(&srcFormat, dstFormat) || (is_1bpp_format(&srcFormat) && is_1bpp_format(dstFormat)))
     {
         IWICBitmapSource_AddRef(pISrc);
         *ppIDst = pISrc;
diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c
index ca02ff98f8..7b0fbf8089 100644
--- a/dlls/windowscodecs/regsvr.c
+++ b/dlls/windowscodecs/regsvr.c
@@ -1347,6 +1347,10 @@ static GUID const * const bmp_encode_formats[] = {
     &GUID_WICPixelFormat16bppBGR565,
     &GUID_WICPixelFormat24bppBGR,
     &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormatBlackWhite,
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat4bppIndexed,
+    &GUID_WICPixelFormat8bppIndexed,
     NULL
 };
 
diff --git a/dlls/windowscodecs/tests/converter.c b/dlls/windowscodecs/tests/converter.c
index 44a2c08147..8e0fb7759b 100644
--- a/dlls/windowscodecs/tests/converter.c
+++ b/dlls/windowscodecs/tests/converter.c
@@ -804,6 +804,8 @@ static void check_bmp_format(IStream *stream, const WICPixelFormatGUID *format)
 
     if (IsEqualGUID(format, &GUID_WICPixelFormat1bppIndexed))
     {
+        ok(bfh.bfOffBits == 0x0436, "wrong bfOffBits %02x\n", bfh.bfOffBits);
+
         ok(bih.bV5Width == 32, "wrong width %u\n", bih.bV5Width);
         ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height);
 
@@ -814,6 +816,8 @@ static void check_bmp_format(IStream *stream, const WICPixelFormatGUID *format)
     }
     else if (IsEqualGUID(format, &GUID_WICPixelFormat4bppIndexed))
     {
+        ok(bfh.bfOffBits == 0x0436, "wrong bfOffBits %02x\n", bfh.bfOffBits);
+
         ok(bih.bV5Width == 8, "wrong width %u\n", bih.bV5Width);
         ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height);
 
@@ -824,6 +828,8 @@ static void check_bmp_format(IStream *stream, const WICPixelFormatGUID *format)
     }
     else if (IsEqualGUID(format, &GUID_WICPixelFormat8bppIndexed))
     {
+        ok(bfh.bfOffBits == 0x0436, "wrong bfOffBits %02x\n", bfh.bfOffBits);
+
         ok(bih.bV5Width == 4, "wrong width %u\n", bih.bV5Width);
         ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height);
 
@@ -834,6 +840,8 @@ static void check_bmp_format(IStream *stream, const WICPixelFormatGUID *format)
     }
     else if (IsEqualGUID(format, &GUID_WICPixelFormat32bppBGR))
     {
+        ok(bfh.bfOffBits == 0x0036, "wrong bfOffBits %02x\n", bfh.bfOffBits);
+
         ok(bih.bV5Width == 4, "wrong width %u\n", bih.bV5Width);
         ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height);
 
@@ -1492,8 +1500,6 @@ START_TEST(converter)
     test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder,
                  &testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR");
 
-if (!strcmp(winetest_platform, "windows")) /* FIXME: enable once implemented in Wine */
-{
     test_encoder(&testdata_BlackWhite, &CLSID_WICBmpEncoder,
                  &testdata_1bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder BlackWhite");
     test_encoder(&testdata_1bppIndexed, &CLSID_WICBmpEncoder,
@@ -1504,7 +1510,6 @@ if (!strcmp(winetest_platform, "windows")) /* FIXME: enable once implemented in
                  &testdata_4bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 4bppIndexed");
     test_encoder(&testdata_8bppIndexed, &CLSID_WICBmpEncoder,
                  &testdata_8bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 8bppIndexed");
-}
     test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
                  &testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");
 
-- 
2.19.2




More information about the wine-devel mailing list