From 3e9c4dad6627078cb1bb36d077a5b20676c51d4b Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Fri, 24 Apr 2020 14:56:26 +0200 Subject: [PATCH] [WINDOWSCODECS] Use upstream Wine fix for 4bps BGRA TIFF. CORE-16796 Import Wine commits by Dmitry Timoshkov: * 0cd8502b49 windowscodecs: Add support for 4bps RGBA format to TIFF decoder. * 962bb99352 windowscodecs/tests: Add a separate test for 4bps BGRA TIFF format. --- dll/win32/windowscodecs/tiffformat.c | 60 +++++----- .../winetests/windowscodecs/tiffformat.c | 104 ++++++++++++++++++ 2 files changed, 132 insertions(+), 32 deletions(-) diff --git a/dll/win32/windowscodecs/tiffformat.c b/dll/win32/windowscodecs/tiffformat.c index e7141fc3e23..b3d32eec611 100644 --- a/dll/win32/windowscodecs/tiffformat.c +++ b/dll/win32/windowscodecs/tiffformat.c @@ -1148,48 +1148,44 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT HeapFree(GetProcessHeap(), 0, srcdata); } - /* 4bpp RGBA */ + /* 4bps RGBA */ else if (This->decode_info.source_bpp == 4 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) { - BYTE *src, *dst; - DWORD count; + BYTE *srcdata, *src, *dst; + DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 3 + 7) / 8; - /* 1 source byte expands to 2 BGRA samples */ - count = (This->decode_info.tile_width * This->decode_info.tile_height + 1) / 2; + count = width_bytes * This->decode_info.tile_height; - src = This->cached_tile + count - 1; - dst = This->cached_tile + This->decode_info.tile_size; + srcdata = HeapAlloc(GetProcessHeap(), 0, count); + if (!srcdata) return E_OUTOFMEMORY; + memcpy(srcdata, This->cached_tile, count); - while (count--) + for (y = 0; y < This->decode_info.tile_height; y++) { - BYTE b = *src--; + src = srcdata + y * width_bytes; + dst = This->cached_tile + y * This->decode_info.tile_width * 4; -#ifdef __REACTOS__ - dst -= 4; - dst[2] = (b & 0x08) ? 0xff : 0; /* R */ - dst[1] = (b & 0x04) ? 0xff : 0; /* G */ - dst[0] = (b & 0x02) ? 0xff : 0; /* B */ - dst[3] = (b & 0x01) ? 0xff : 0; /* A */ - if (count || This->decode_info.tile_width % 2 == 0) + /* 1 source byte expands to 2 BGRA samples */ + + for (x = 0; x < This->decode_info.tile_width; x += 2) { - dst -= 4; - dst[2] = (b & 0x80) ? 0xff : 0; /* R */ - dst[1] = (b & 0x40) ? 0xff : 0; /* G */ - dst[0] = (b & 0x20) ? 0xff : 0; /* B */ - dst[3] = (b & 0x10) ? 0xff : 0; /* A */ + dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */ + dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */ + dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */ + dst[3] = (src[0] & 0x10) ? 0xff : 0; /* A */ + if (x + 1 < This->decode_info.tile_width) + { + dst[4] = (src[0] & 0x02) ? 0xff : 0; /* B */ + dst[5] = (src[0] & 0x04) ? 0xff : 0; /* G */ + dst[6] = (src[0] & 0x08) ? 0xff : 0; /* R */ + dst[7] = (src[0] & 0x01) ? 0xff : 0; /* A */ + } + src++; + dst += 8; } -#else - dst -= 8; - dst[2] = (b & 0x80) ? 0xff : 0; /* R */ - dst[1] = (b & 0x40) ? 0xff : 0; /* G */ - dst[0] = (b & 0x20) ? 0xff : 0; /* B */ - dst[3] = (b & 0x10) ? 0xff : 0; /* A */ - dst[6] = (b & 0x08) ? 0xff : 0; /* R */ - dst[5] = (b & 0x04) ? 0xff : 0; /* G */ - dst[4] = (b & 0x02) ? 0xff : 0; /* B */ - dst[7] = (b & 0x01) ? 0xff : 0; /* A */ -#endif } + + HeapFree(GetProcessHeap(), 0, srcdata); } /* 16bpp RGBA */ else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) diff --git a/modules/rostests/winetests/windowscodecs/tiffformat.c b/modules/rostests/winetests/windowscodecs/tiffformat.c index 8cdc0047a21..0c68904abad 100644 --- a/modules/rostests/winetests/windowscodecs/tiffformat.c +++ b/modules/rostests/winetests/windowscodecs/tiffformat.c @@ -302,6 +302,47 @@ static const struct tiff_24bpp_data { 900, 3 }, { 0x11, 0x22, 0x33 } }; + +static const struct tiff_4bps_bgra +{ + USHORT byte_order; + USHORT version; + ULONG dir_offset; + USHORT number_of_entries; + struct IFD_entry entry[14]; + ULONG next_IFD; + struct IFD_rational res; + BYTE pixel_data[4]; +} tiff_4bps_bgra = +{ +#ifdef WORDS_BIGENDIAN + 'M' | 'M' << 8, +#else + 'I' | 'I' << 8, +#endif + 42, + FIELD_OFFSET(struct tiff_4bps_bgra, number_of_entries), + 14, + { + { 0xff, IFD_SHORT, 1, 0 }, /* SUBFILETYPE */ + { 0x100, IFD_LONG, 1, 3 }, /* IMAGEWIDTH */ + { 0x101, IFD_LONG, 1, 2 }, /* IMAGELENGTH */ + { 0x102, IFD_SHORT, 1, 1 }, /* BITSPERSAMPLE */ + { 0x103, IFD_SHORT, 1, 1 }, /* COMPRESSION */ + { 0x106, IFD_SHORT, 1, 2 }, /* PHOTOMETRIC */ + { 0x111, IFD_LONG, 1, FIELD_OFFSET(struct tiff_4bps_bgra, pixel_data) }, /* STRIPOFFSETS */ + { 0x115, IFD_SHORT, 1, 4 }, /* SAMPLESPERPIXEL */ + { 0x116, IFD_LONG, 1, 2 }, /* ROWSPERSTRIP */ + { 0x117, IFD_LONG, 1, 4 }, /* STRIPBYTECOUNT */ + { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_4bps_bgra, res) }, /* XRESOLUTION */ + { 0x11b, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_4bps_bgra, res) }, /* YRESOLUTION */ + { 0x11c, IFD_SHORT, 1, 1 }, /* PLANARCONFIGURATION */ + { 0x128, IFD_SHORT, 1, 2 } /* RESOLUTIONUNIT */ + }, + 0, + { 96, 1 }, + { 0x12,0x30, 0x47,0xe0 } +}; #include "poppack.h" static IWICImagingFactory *factory; @@ -1179,6 +1220,68 @@ static void test_color_formats(void) } } +static void test_tiff_4bps_bgra(void) +{ + HRESULT hr; + IWICBitmapDecoder *decoder; + IWICBitmapFrameDecode *frame; + UINT frame_count, width, height, i; + double dpi_x, dpi_y; + IWICPalette *palette; + GUID format; + WICRect rc; + BYTE data[24]; + static const BYTE expected_data[24] = { 0,0,0,0xff, 0xff,0,0,0, 0xff,0,0,0xff, + 0,0xff,0,0, 0xff,0xff,0,0xff, 0xff,0xff,0xff,0 }; + + hr = create_decoder(&tiff_4bps_bgra, sizeof(tiff_4bps_bgra), &decoder); + ok(hr == S_OK, "Failed to load TIFF image data %#x\n", hr); + if (hr != S_OK) return; + + hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); + ok(hr == S_OK, "GetFrameCount error %#x\n", hr); + ok(frame_count == 1, "expected 1, got %u\n", frame_count); + + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + ok(hr == S_OK, "GetFrame error %#x\n", hr); + + hr = IWICBitmapFrameDecode_GetSize(frame, &width, &height); + ok(hr == S_OK, "GetSize error %#x\n", hr); + ok(width == 3, "got %u\n", width); + ok(height == 2, "got %u\n", height); + + hr = IWICBitmapFrameDecode_GetResolution(frame, &dpi_x, &dpi_y); + ok(hr == S_OK, "GetResolution error %#x\n", hr); + ok(dpi_x == 96.0, "expected 96.0, got %f\n", dpi_x); + ok(dpi_y == 96.0, "expected 96.0, got %f\n", dpi_y); + + hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &format); + ok(hr == S_OK, "GetPixelFormat error %#x\n", hr); + ok(IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGRA), + "got wrong format %s\n", wine_dbgstr_guid(&format)); + + hr = IWICImagingFactory_CreatePalette(factory, &palette); + ok(hr == S_OK, "CreatePalette error %#x\n", hr); + hr = IWICBitmapFrameDecode_CopyPalette(frame, palette); + ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, + "expected WINCODEC_ERR_PALETTEUNAVAILABLE, got %#x\n", hr); + IWICPalette_Release(palette); + + memset(data, 0xaa, sizeof(data)); + rc.X = 0; + rc.Y = 0; + rc.Width = 3; + rc.Height = 2; + hr = IWICBitmapFrameDecode_CopyPixels(frame, &rc, 12, sizeof(data), data); + ok(hr == S_OK, "CopyPixels error %#x\n", hr); + + for (i = 0; i < sizeof(data); i++) + ok(data[i] == expected_data[i], "%u: expected %02x, got %02x\n", i, expected_data[i], data[i]); + + IWICBitmapFrameDecode_Release(frame); + IWICBitmapDecoder_Release(decoder); +} + START_TEST(tiffformat) { HRESULT hr; @@ -1190,6 +1293,7 @@ START_TEST(tiffformat) ok(hr == S_OK, "CoCreateInstance error %#x\n", hr); if (FAILED(hr)) return; + test_tiff_4bps_bgra(); test_color_formats(); test_tiff_1bpp_palette(); test_tiff_8bpp_palette();