windowscodecs: Add support for palette image formats to BMP encoder.

Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Dmitry Timoshkov 2018-12-06 12:05:55 +03:00 committed by Alexandre Julliard
parent d13d34d101
commit ee6dd81e92
4 changed files with 57 additions and 13 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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
};

View File

@ -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");