From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/tests/tiffformat.c | 94 +++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/dlls/windowscodecs/tests/tiffformat.c b/dlls/windowscodecs/tests/tiffformat.c index 1bc94b03f35..b292fd4cabd 100644 --- a/dlls/windowscodecs/tests/tiffformat.c +++ b/dlls/windowscodecs/tests/tiffformat.c @@ -360,6 +360,51 @@ static const struct tiff_24bpp_data { 0x11, 0x22, 0x33 } };
+static const struct tiff_24bpp_separate_planes_data +{ + USHORT byte_order; + USHORT version; + ULONG dir_offset; + USHORT number_of_entries; + struct IFD_entry entry[14]; + ULONG next_IFD; + struct IFD_rational res; + ULONG strip_offsets[3]; + ULONG strip_byte_counts[3]; + BYTE pixel_data[12]; +} tiff_24bpp_separate_planes_data = +{ + 'I' | 'I' << 8, + 42, + FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, number_of_entries), + 14, + { + { 0xff, IFD_SHORT, 1, 0 }, /* SUBFILETYPE */ + { 0x100, IFD_LONG, 1, 4 }, /* IMAGEWIDTH */ + { 0x101, IFD_LONG, 1, 1 }, /* IMAGELENGTH */ + { 0x102, IFD_SHORT, 1, 8 }, /* BITSPERSAMPLE */ + { 0x103, IFD_SHORT, 1, 1 }, /* COMPRESSION: XP doesn't accept IFD_LONG here */ + { 0x106, IFD_SHORT, 1, 2 }, /* PHOTOMETRIC */ + { 0x111, IFD_LONG, 3, FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, strip_offsets) }, /* STRIPOFFSETS */ + { 0x115, IFD_SHORT, 1, 3 }, /* SAMPLESPERPIXEL */ + { 0x116, IFD_LONG, 1, 1 }, /* ROWSPERSTRIP */ + { 0x117, IFD_LONG, 3, FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, strip_byte_counts) }, /* STRIPBYTECOUNT */ + { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, res) }, /* XRESOLUTION */ + { 0x11b, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, res) }, /* YRESOLUTION */ + { 0x11c, IFD_SHORT, 1, 2 }, /* PLANARCONFIGURATION */ + { 0x128, IFD_SHORT, 1, 2 }, /* RESOLUTIONUNIT */ + }, + 0, + { 900, 3 }, + { + FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, pixel_data), + FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, pixel_data) + 4, + FIELD_OFFSET(struct tiff_24bpp_separate_planes_data, pixel_data) + 8, + }, + { 24, 24, 24 }, + { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc } +}; + static const struct tiff_4bps_bgra { USHORT byte_order; @@ -1569,6 +1614,54 @@ static void test_tiff_16bpp(void) free(tiff_be); }
+static void test_tiff_24bpp_separate_planes(void) +{ + static const BYTE expected_data[] = { 0x99,0x55,0x11, 0xaa,0x66,0x22, 0xbb,0x77,0x33, 0xcc,0x88,0x44 }; + UINT count, width, height, i; + IWICBitmapFrameDecode *frame; + IWICBitmapDecoder *decoder; + double dpi_x, dpi_y; + BYTE data[3*4]; + GUID format; + HRESULT hr; + + hr = create_decoder(&tiff_24bpp_separate_planes_data, sizeof(tiff_24bpp_separate_planes_data), &decoder); + todo_wine + ok(hr == S_OK, "Failed to load TIFF image data %#lx\n", hr); + if (FAILED(hr)) return; + ok(decoder != NULL, "Failed to load TIFF image data\n"); + + hr = IWICBitmapDecoder_GetFrameCount(decoder, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 1, "got %u\n", count); + + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICBitmapFrameDecode_GetSize(frame, &width, &height); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(width == 4, "got %u\n", width); + ok(height == 1, "got %u\n", height); + + hr = IWICBitmapFrameDecode_GetResolution(frame, &dpi_x, &dpi_y); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(dpi_x == 300.0, "got %f\n", dpi_x); + ok(dpi_y == 300.0, "got %f\n", dpi_y); + + hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_WICPixelFormat24bppBGR), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); + + memset(data, 0xfe, sizeof(data)); + hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, 12, sizeof(data), data); + ok(hr == S_OK, "Unexpected hr %#lx.\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; @@ -1589,6 +1682,7 @@ START_TEST(tiffformat) test_tiff_resolution(); test_tiff_24bpp(); test_tiff_16bpp(); + test_tiff_24bpp_separate_planes();
IWICImagingFactory_Release(factory); CoUninitialize();
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/libtiff.c | 115 +++++++++++++++++++++++--- dlls/windowscodecs/tests/tiffformat.c | 2 - 2 files changed, 104 insertions(+), 13 deletions(-)
diff --git a/dlls/windowscodecs/libtiff.c b/dlls/windowscodecs/libtiff.c index 584dad116ed..5b5b6aa044a 100644 --- a/dlls/windowscodecs/libtiff.c +++ b/dlls/windowscodecs/libtiff.c @@ -152,6 +152,7 @@ typedef struct { UINT tile_size; int tiled; UINT tiles_across; + UINT tiles_along; } tiff_decode_info;
struct tiff_decoder @@ -204,16 +205,11 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) decode_info->samples = samples;
if (samples == 1) - planar = 1; + planar = PLANARCONFIG_CONTIG; else { ret = TIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar); - if (!ret) planar = 1; - if (planar != 1) - { - FIXME("unhandled planar configuration %u\n", planar); - return E_FAIL; - } + if (!ret) planar = PLANARCONFIG_CONTIG; } decode_info->planar = planar;
@@ -475,6 +471,7 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8); decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride; decode_info->tiles_across = (decode_info->frame.width + decode_info->tile_width - 1) / decode_info->tile_width; + decode_info->tiles_along = (decode_info->frame.height + decode_info->tile_height - 1) / decode_info->tile_height; } else if ((ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height))) { @@ -656,19 +653,115 @@ static HRESULT CDECL tiff_decoder_get_decoder_palette(struct decoder *iface, UIN return WINCODEC_ERR_PALETTEUNAVAILABLE; }
-static HRESULT tiff_decoder_read_tile(struct tiff_decoder *This, UINT tile_x, UINT tile_y) +static HRESULT tiff_read_tile(struct tiff_decoder *decoder, UINT tile_x, UINT tile_y, UINT s, void *buffer, + size_t size, size_t *out_length) { + tiff_decode_info *info = &decoder->cached_decode_info; + unsigned int index; tsize_t ret; - tiff_decode_info *info = &This->cached_decode_info; + + *out_length = 0;
if (info->tiled) - ret = TIFFReadEncodedTile(This->tiff, tile_x + tile_y * info->tiles_across, This->cached_tile, info->tile_size); + { + index = tile_x + tile_y * info->tiles_across + info->tiles_across * info->tiles_along * s; + ret = TIFFReadEncodedTile(decoder->tiff, index, buffer, size); + } else - ret = TIFFReadEncodedStrip(This->tiff, tile_y, This->cached_tile, info->tile_size); + { + index = TIFFComputeStrip(decoder->tiff, tile_y * info->tile_height, s); + ret = TIFFReadEncodedStrip(decoder->tiff, index, buffer, size); + }
if (ret == -1) return E_FAIL;
+ *out_length = ret; + return S_OK; +} + +static HRESULT tiff_decoder_copy_planes(struct tiff_decoder *decoder, const uint8_t *srcdata) +{ + tiff_decode_info *info = &decoder->cached_decode_info; + size_t sample_size, width_bytes; + const uint8_t *src; + uint8_t *dst; + + if (info->bps % 8) + { + FIXME("Separate sample planes for %ubps are not supported.\n", info->bps); + return E_NOTIMPL; + } + + sample_size = info->bps / 8; + width_bytes = info->tile_width * sample_size; + + for (int y = 0; y < info->tile_height; y++) + { + dst = decoder->cached_tile + y * width_bytes * info->samples; + + for (int x = 0; x < info->tile_width; x++) + { + for (int s = 0; s < info->samples; s++) + { + src = srcdata + (y + s * info->tile_height) * width_bytes + x * sample_size; + + if (info->bps == 8) + *dst = *src; + else if (info->bps == 16) + *(uint16_t *)dst = *(uint16_t *)src; + else if (info->bps == 32) + *(uint32_t *)dst = *(uint32_t *)src; + else if (info->bps == 64) + *(uint64_t *)dst = *(uint64_t *)src; + else + memcpy(dst, src, sample_size); + + dst += sample_size; + } + } + } + + return S_OK; +} + +static HRESULT tiff_decoder_read_tile(struct tiff_decoder *This, UINT tile_x, UINT tile_y) +{ + tiff_decode_info *info = &This->cached_decode_info; + size_t len; + HRESULT hr; + + if (info->planar == PLANARCONFIG_CONTIG) + { + hr = tiff_read_tile(This, tile_x, tile_y, 0, This->cached_tile, info->tile_size, &len); + } + else + { + size_t offset = 0, size = info->samples * info->tile_size; + uint8_t *buffer; + + /* Read separate planes one by one, and put them together in contiguous form. */ + if (!(buffer = malloc(size))) + return E_OUTOFMEMORY; + + for (int s = 0; s < info->samples; ++s) + { + hr = tiff_read_tile(This, tile_x, tile_y, s, buffer + offset, size, &len); + if (FAILED(hr)) break; + + offset += len; + size -= len; + } + + if (SUCCEEDED(hr)) + hr = tiff_decoder_copy_planes(This, buffer); + + free(buffer); + } + + if (FAILED(hr)) + return hr; + /* 3bps RGB */ if (info->source_bpp == 3 && info->samples == 3 && info->frame.bpp == 24) { diff --git a/dlls/windowscodecs/tests/tiffformat.c b/dlls/windowscodecs/tests/tiffformat.c index b292fd4cabd..49323028857 100644 --- a/dlls/windowscodecs/tests/tiffformat.c +++ b/dlls/windowscodecs/tests/tiffformat.c @@ -1626,9 +1626,7 @@ static void test_tiff_24bpp_separate_planes(void) HRESULT hr;
hr = create_decoder(&tiff_24bpp_separate_planes_data, sizeof(tiff_24bpp_separate_planes_data), &decoder); - todo_wine ok(hr == S_OK, "Failed to load TIFF image data %#lx\n", hr); - if (FAILED(hr)) return; ok(decoder != NULL, "Failed to load TIFF image data\n");
hr = IWICBitmapDecoder_GetFrameCount(decoder, &count);