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 2009 Vincent Povirk for CodeWeavers
* Copyright 2016 Dmitry Timoshkov
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -37,6 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
struct bmp_pixelformat { struct bmp_pixelformat {
const WICPixelFormatGUID *guid; const WICPixelFormatGUID *guid;
UINT bpp; UINT bpp;
UINT colors; /* palette size */
DWORD compression; DWORD compression;
DWORD redmask; DWORD redmask;
DWORD greenmask; DWORD greenmask;
@ -45,13 +47,18 @@ struct bmp_pixelformat {
}; };
static const struct bmp_pixelformat formats[] = { static const struct bmp_pixelformat formats[] = {
{&GUID_WICPixelFormat24bppBGR, 24, BI_RGB}, {&GUID_WICPixelFormat24bppBGR, 24, 0, BI_RGB},
{&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB}, {&GUID_WICPixelFormatBlackWhite, 1, 2, BI_RGB},
{&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0}, {&GUID_WICPixelFormat1bppIndexed, 1, 2, BI_RGB},
{&GUID_WICPixelFormat32bppBGR, 32, 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 #if 0
/* Windows doesn't seem to support this one. */ /* 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 #endif
{NULL} {NULL}
}; };
@ -182,9 +189,14 @@ static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface
if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE; 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++) for (i=0; formats[i].guid; i++)
{ {
if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0) if (IsEqualGUID(formats[i].guid, pPixelFormat))
break; break;
} }
@ -207,6 +219,7 @@ static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
IWICPalette *palette) IWICPalette *palette)
{ {
BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
HRESULT hr;
TRACE("(%p,%p)\n", iface, palette); TRACE("(%p,%p)\n", iface, palette);
@ -215,7 +228,14 @@ static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
if (!This->initialized) if (!This->initialized)
return WINCODEC_ERR_NOTINITIALIZED; 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, 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.bV5SizeImage = This->stride*This->height;
bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254; bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254; bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
bih.bV5ClrUsed = 0; bih.bV5ClrUsed = (This->format->bpp <= 8) ? This->colors : 0;
bih.bV5ClrImportant = 0; bih.bV5ClrImportant = bih.bV5ClrUsed;
if (This->format->compression == BI_BITFIELDS) 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.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size; bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
bfh.bfOffBits += bih.bV5ClrUsed * sizeof(WICColor);
pos.QuadPart = 0; pos.QuadPart = 0;
hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL); 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 (FAILED(hr)) return hr;
if (byteswritten != info_size) return E_FAIL; 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); hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
if (FAILED(hr)) return hr; if (FAILED(hr)) return hr;
if (byteswritten != bih.bV5SizeImage) return E_FAIL; if (byteswritten != bih.bV5SizeImage) return E_FAIL;

View File

@ -2461,6 +2461,12 @@ HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnkn
return hr; 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 WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
{ {
HRESULT res; HRESULT res;
@ -2476,7 +2482,7 @@ HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitma
res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat); res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
if (FAILED(res)) return res; if (FAILED(res)) return res;
if (IsEqualGUID(&srcFormat, dstFormat)) if (IsEqualGUID(&srcFormat, dstFormat) || (is_1bpp_format(&srcFormat) && is_1bpp_format(dstFormat)))
{ {
IWICBitmapSource_AddRef(pISrc); IWICBitmapSource_AddRef(pISrc);
*ppIDst = pISrc; *ppIDst = pISrc;

View File

@ -1347,6 +1347,10 @@ static GUID const * const bmp_encode_formats[] = {
&GUID_WICPixelFormat16bppBGR565, &GUID_WICPixelFormat16bppBGR565,
&GUID_WICPixelFormat24bppBGR, &GUID_WICPixelFormat24bppBGR,
&GUID_WICPixelFormat32bppBGR, &GUID_WICPixelFormat32bppBGR,
&GUID_WICPixelFormatBlackWhite,
&GUID_WICPixelFormat1bppIndexed,
&GUID_WICPixelFormat4bppIndexed,
&GUID_WICPixelFormat8bppIndexed,
NULL NULL
}; };

View File

@ -804,6 +804,8 @@ static void check_bmp_format(IStream *stream, const WICPixelFormatGUID *format)
if (IsEqualGUID(format, &GUID_WICPixelFormat1bppIndexed)) 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.bV5Width == 32, "wrong width %u\n", bih.bV5Width);
ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height); 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)) 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.bV5Width == 8, "wrong width %u\n", bih.bV5Width);
ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height); 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)) 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.bV5Width == 4, "wrong width %u\n", bih.bV5Width);
ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height); 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)) 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.bV5Width == 4, "wrong width %u\n", bih.bV5Width);
ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height); ok(bih.bV5Height == 2, "wrong height %u\n", bih.bV5Height);
@ -1492,8 +1500,6 @@ START_TEST(converter)
test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder, test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder,
&testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR"); &testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR");
if (!strcmp(winetest_platform, "windows")) /* FIXME: enable once implemented in Wine */
{
test_encoder(&testdata_BlackWhite, &CLSID_WICBmpEncoder, test_encoder(&testdata_BlackWhite, &CLSID_WICBmpEncoder,
&testdata_1bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder BlackWhite"); &testdata_1bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder BlackWhite");
test_encoder(&testdata_1bppIndexed, &CLSID_WICBmpEncoder, 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"); &testdata_4bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 4bppIndexed");
test_encoder(&testdata_8bppIndexed, &CLSID_WICBmpEncoder, test_encoder(&testdata_8bppIndexed, &CLSID_WICBmpEncoder,
&testdata_8bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 8bppIndexed"); &testdata_8bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 8bppIndexed");
}
test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder, test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
&testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR"); &testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");