From: Anton Romanov Subject: [PATCH v9] windowscodecs: Fix data corruption for Adobe CMYK JPEGs Message-Id: <20180217073201.9220-1-theli.ua@gmail.com> Date: Fri, 16 Feb 2018 23:32:01 -0800 Fixes https://bugs.winehq.org/show_bug.cgi?id=43520 Signed-off-by: Anton Romanov --- dlls/windowscodecs/jpegformat.c | 10 ++- dlls/windowscodecs/tests/Makefile.in | 1 + dlls/windowscodecs/tests/jpegformat.c | 145 ++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 dlls/windowscodecs/tests/jpegformat.c diff --git a/dlls/windowscodecs/jpegformat.c b/dlls/windowscodecs/jpegformat.c index ef050ba688..aab4b92740 100644 --- a/dlls/windowscodecs/jpegformat.c +++ b/dlls/windowscodecs/jpegformat.c @@ -680,9 +680,15 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, } if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker) + { + DWORD *pDwordData = (DWORD*) (This->image_data + stride * first_scanline); + DWORD *pDwordDataEnd = (DWORD*) (This->image_data + This->cinfo.output_scanline * stride); + /* Adobe JPEG's have inverted CMYK data. */ - for (i=0; iimage_data[i] ^= 0xff; + while(pDwordData < pDwordDataEnd) + *pDwordData++ ^= 0xffffffff; + } + } LeaveCriticalSection(&This->lock); diff --git a/dlls/windowscodecs/tests/Makefile.in b/dlls/windowscodecs/tests/Makefile.in index b1e78f995c..3d64210ba0 100644 --- a/dlls/windowscodecs/tests/Makefile.in +++ b/dlls/windowscodecs/tests/Makefile.in @@ -13,4 +13,5 @@ C_SRCS = \ pngformat.c \ propertybag.c \ stream.c \ + jpegformat.c \ tiffformat.c diff --git a/dlls/windowscodecs/tests/jpegformat.c b/dlls/windowscodecs/tests/jpegformat.c new file mode 100644 index 0000000000..c1e46c4869 --- /dev/null +++ b/dlls/windowscodecs/tests/jpegformat.c @@ -0,0 +1,145 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "objbase.h" +#include "wincodec.h" +#include "wine/test.h" + +static const char jpeg_adobe_cmyk_1x5[] = + "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x01\x2c" + "\x01\x2c\x00\x00\xff\xee\x00\x0e\x41\x64\x6f\x62\x65\x00\x64\x00" + "\x00\x00\x00\x02\xff\xfe\x00\x13\x43\x72\x65\x61\x74\x65\x64\x20" + "\x77\x69\x74\x68\x20\x47\x49\x4d\x50\xff\xdb\x00\x43\x00\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\xff\xdb" + "\x00\x43\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\xff\xc0\x00\x14\x08\x00\x05\x00\x01\x04\x01\x11\x00" + "\x02\x11\x01\x03\x11\x01\x04\x11\x00\xff\xc4\x00\x15\x00\x01\x01" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x08" + "\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\xff\xc4\x00\x14\x01\x01\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xff\xc4\x00\x14" + "\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\xff\xda\x00\x0e\x04\x01\x00\x02\x11\x03\x11\x04\x00\x00" + "\x3f\x00\x40\x44\x02\x1e\xa4\x1f\xff\xd9"; + +static void test_decode_adobe_cmyk(void) +{ + IWICBitmapDecoder *decoder; + IWICBitmapFrameDecode *framedecode; + HRESULT hr; + HGLOBAL hjpegdata; + char *jpegdata; + IStream *jpegstream; + GUID guidresult; + UINT count=0, width=0, height=0; + BYTE imagedata[5 * 4] = {1}; + UINT i; + + const BYTE expected_imagedata[5 * 4] = { + 0x00, 0xb0, 0xfc, 0x6d, + 0x00, 0xb0, 0xfc, 0x6d, + 0x00, 0xb0, 0xfc, 0x6d, + 0x00, 0xb0, 0xfc, 0x6d, + 0x00, 0xb0, 0xfc, 0x6d, + }; + + const BYTE expected_imagedata_24bpp[5 * 4] = { + 0x0d, 0x4b, 0x94, 0x00, + 0x0d, 0x4b, 0x94, 0x00, + 0x0d, 0x4b, 0x94, 0x00, + 0x0d, 0x4b, 0x94, 0x00, + 0x0d, 0x4b, 0x94, 0x00, + }; + + hr = CoCreateInstance(&CLSID_WICJpegDecoder, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICBitmapDecoder, (void**)&decoder); + ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr); + if (FAILED(hr)) return; + + hjpegdata = GlobalAlloc(GMEM_MOVEABLE, sizeof(jpeg_adobe_cmyk_1x5)); + ok(hjpegdata != 0, "GlobalAlloc failed\n"); + if (hjpegdata) + { + jpegdata = GlobalLock(hjpegdata); + memcpy(jpegdata, jpeg_adobe_cmyk_1x5, sizeof(jpeg_adobe_cmyk_1x5)); + GlobalUnlock(hjpegdata); + + hr = CreateStreamOnHGlobal(hjpegdata, FALSE, &jpegstream); + ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr); + if (SUCCEEDED(hr)) + { + hr = IWICBitmapDecoder_Initialize(decoder, jpegstream, WICDecodeMetadataCacheOnLoad); + ok(hr == S_OK, "Initialize failed, hr=%x\n", hr); + + hr = IWICBitmapDecoder_GetContainerFormat(decoder, &guidresult); + ok(SUCCEEDED(hr), "GetContainerFormat failed, hr=%x\n", hr); + ok(IsEqualGUID(&guidresult, &GUID_ContainerFormatJpeg), "unexpected container format\n"); + + hr = IWICBitmapDecoder_GetFrameCount(decoder, &count); + ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr); + ok(count == 1, "unexpected count %u\n", count); + + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode); + ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr); + if (SUCCEEDED(hr)) + { + hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height); + ok(SUCCEEDED(hr), "GetSize failed, hr=%x\n", hr); + ok(width == 1, "expected width=1, got %u\n", width); + ok(height == 5, "expected height=5, got %u\n", height); + + hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &guidresult); + ok(SUCCEEDED(hr), "GetPixelFormat failed, hr=%x\n", hr); + ok(IsEqualGUID(&guidresult, &GUID_WICPixelFormat32bppCMYK) || + broken(IsEqualGUID(&guidresult, &GUID_WICPixelFormat24bppBGR)), /* xp/2003 */ + "unexpected pixel format: %s\n", wine_dbgstr_guid(&guidresult)); + + /* We want to be sure our state tracking will not impact output + * data on subsequent calls */ + for(i=2; i>0; --i) + { + hr = IWICBitmapFrameDecode_CopyPixels(framedecode, NULL, 4, sizeof(imagedata), imagedata); + ok(SUCCEEDED(hr), "CopyPixels failed, hr=%x\n", hr); + ok(!memcmp(imagedata, expected_imagedata, sizeof(imagedata)) || + broken(!memcmp(imagedata, expected_imagedata_24bpp, sizeof(expected_imagedata))), /* xp/2003 */ + "unexpected image data\n"); + } + IWICBitmapFrameDecode_Release(framedecode); + } + IStream_Release(jpegstream); + } + GlobalFree(hjpegdata); + } + IWICBitmapDecoder_Release(decoder); +} + + +START_TEST(jpegformat) +{ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + test_decode_adobe_cmyk(); + + CoUninitialize(); +} -- 2.16.1