windowscodecs: Fixes for JPEG decoder and support for CMYK to BGR conversion. Accepted

Revisions: 

Revision 2

user image hackomatic Author
18 Aug. 17

These patches fix https://bugs.winehq.org/show_bug.cgi?id=43520

v2: Properly split the 1st patch to show that besides the code move there are other fixes in the JPEG decoder.
'make test' now succeeds as well.

Single files Merged diff Tar archive
You have unsaved changes. Press CTRL + ENTER in a text field to submit your comments.

0001-windowscodecs-Fix-IWICBitmapEncoder-SetPalette-for-a.patch

From b06f1dec40b5ccca624250011608d2d0e7f247a6 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 18 Aug 2017 11:53:17 +0800
Subject: [1/6] windowscodecs: Fix IWICBitmapEncoder::SetPalette for a not
initialized case in JPEG encoder.
Content-Type: text/plain; charset=UTF-8
---
dlls/windowscodecs/jpegformat.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/jpegformat.c b/dlls/windowscodecs/jpegformat.c
index 8f2db570b1..1763b40ecd 100644
--- a/dlls/windowscodecs/jpegformat.c
+++ b/dlls/windowscodecs/jpegformat.c
@@ -1424,8 +1424,18 @@ static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface,
static HRESULT WINAPI JpegEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
{
+ JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
TRACE("(%p,%p)\n", iface, pIPalette);
- return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+
+ EnterCriticalSection(&This->lock);
+
+ hr = This->initialized ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED;
+
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
}
static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
--
2.13.4

0002-windowscodecs-Fix-IWICBitmapFrameEncode-SetPalette-f.patch

From 0a7c2654c5a582bd8c76c78416daa59ae631675a Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 18 Aug 2017 12:00:55 +0800
Subject: [2/6] windowscodecs: Fix IWICBitmapFrameEncode::SetPalette for a not
initialized case in JPEG encoder.
Content-Type: text/plain; charset=UTF-8
---
dlls/windowscodecs/jpegformat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/jpegformat.c b/dlls/windowscodecs/jpegformat.c
index 1763b40ecd..abab36ab40 100644
--- a/dlls/windowscodecs/jpegformat.c
+++ b/dlls/windowscodecs/jpegformat.c
@@ -1087,7 +1087,7 @@ static HRESULT WINAPI JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode *iface,
EnterCriticalSection(&This->lock);
- if (This->initialized)
+ if (This->frame_initialized)
hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
else
hr = WINCODEC_ERR_NOTINITIALIZED;
--
2.13.4

0003-windowscodecs-Fix-stride-calculation-in-JPEG-decoder.patch

From 52d87d081255258100523764de5050dcfbdf533f Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 18 Aug 2017 12:03:50 +0800
Subject: [3/6] windowscodecs: Fix stride calculation in JPEG decoder.
Content-Type: text/plain; charset=UTF-8
---
dlls/windowscodecs/jpegformat.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/jpegformat.c b/dlls/windowscodecs/jpegformat.c
index abab36ab40..f31239b8d7 100644
--- a/dlls/windowscodecs/jpegformat.c
+++ b/dlls/windowscodecs/jpegformat.c
@@ -628,7 +628,7 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
else if (This->cinfo.out_color_space == JCS_CMYK) bpp = 32;
else bpp = 24;
- stride = bpp * This->cinfo.output_width;
+ stride = (bpp * This->cinfo.output_width + 7) / 8;
data_size = stride * This->cinfo.output_height;
max_row_needed = prc->Y + prc->Height;
--
2.13.4

0004-windowscodecs-Move-additional-processing-out-of-the-.patch

From d0ff4ecacffa7ce924ab8153bc57f49e029399ad Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 18 Aug 2017 12:12:16 +0800
Subject: [4/6] windowscodecs: Move additional processing out of the JPEG
decoding loop.
Content-Type: text/plain; charset=UTF-8
This avoids image corruption when libjpeg reuses existing pixel data.
---
dlls/windowscodecs/jpegformat.c | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/dlls/windowscodecs/jpegformat.c b/dlls/windowscodecs/jpegformat.c
index f31239b8d7..0023fd2bf3 100644
--- a/dlls/windowscodecs/jpegformat.c
+++ b/dlls/windowscodecs/jpegformat.c
@@ -603,7 +603,7 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
UINT bpp;
UINT stride;
- UINT data_size;
+ UINT data_size, i;
UINT max_row_needed;
jmp_buf jmpbuf;
WICRect rect;
@@ -659,7 +659,6 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
UINT first_scanline = This->cinfo.output_scanline;
UINT max_rows;
JSAMPROW out_rows[4];
- UINT i;
JDIMENSION ret;
max_rows = min(This->cinfo.output_height-first_scanline, 4);
@@ -674,19 +673,21 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
LeaveCriticalSection(&This->lock);
return E_FAIL;
}
+ }
- if (bpp == 24)
- {
- /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
- reverse_bgr8(3, This->image_data + stride * first_scanline,
- This->cinfo.output_width, This->cinfo.output_scanline - first_scanline,
- stride);
- }
+ if (bpp == 24)
+ {
+ /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
+ reverse_bgr8(3, This->image_data,
+ This->cinfo.output_width, This->cinfo.output_height,
+ stride);
+ }
- if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
- /* Adobe JPEG's have inverted CMYK data. */
- for (i=0; i<data_size; i++)
- This->image_data[i] ^= 0xff;
+ if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
+ {
+ /* Adobe JPEG's have inverted CMYK data. */
+ for (i=0; i<data_size; i++)
+ This->image_data[i] ^= 0xff;
}
LeaveCriticalSection(&This->lock);
--
2.13.4

0005-windowscodecs-Move-JPEG-frame-image-data-initializat.patch

From 4f27339a5d9c62a0a0b3ceccc949af1a9a154291 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 18 Aug 2017 12:17:52 +0800
Subject: [5/6] windowscodecs: Move JPEG frame image data initialization from
Frame::CopyPixels to Decoder::Initialize. (v2)
Content-Type: text/plain; charset=UTF-8
This is how PNG decoder does things, and it avoids image data corruption
in some cases (presumably when libjpeg reuses existing scanline data).
---
dlls/windowscodecs/jpegformat.c | 146 +++++++++++++++-------------------------
1 file changed, 55 insertions(+), 91 deletions(-)
diff --git a/dlls/windowscodecs/jpegformat.c b/dlls/windowscodecs/jpegformat.c
index 0023fd2bf3..296529cee7 100644
--- a/dlls/windowscodecs/jpegformat.c
+++ b/dlls/windowscodecs/jpegformat.c
@@ -155,6 +155,7 @@ typedef struct {
struct jpeg_error_mgr jerr;
struct jpeg_source_mgr source_mgr;
BYTE source_buffer[1024];
+ UINT bpp, stride;
BYTE *image_data;
CRITICAL_SECTION lock;
} JpegDecoder;
@@ -303,6 +304,8 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
int ret;
LARGE_INTEGER seek;
jmp_buf jmpbuf;
+ UINT data_size, i;
+
TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
EnterCriticalSection(&This->lock);
@@ -381,6 +384,55 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
return E_FAIL;
}
+ if (This->cinfo.out_color_space == JCS_GRAYSCALE) This->bpp = 8;
+ else if (This->cinfo.out_color_space == JCS_CMYK) This->bpp = 32;
+ else This->bpp = 24;
+
+ This->stride = (This->bpp * This->cinfo.output_width + 7) / 8;
+ data_size = This->stride * This->cinfo.output_height;
+
+ This->image_data = HeapAlloc(GetProcessHeap(), 0, data_size);
+ if (!This->image_data)
+ {
+ LeaveCriticalSection(&This->lock);
+ return E_OUTOFMEMORY;
+ }
+
+ while (This->cinfo.output_scanline < This->cinfo.output_height)
+ {
+ UINT first_scanline = This->cinfo.output_scanline;
+ UINT max_rows;
+ JSAMPROW out_rows[4];
+ JDIMENSION ret;
+
+ max_rows = min(This->cinfo.output_height-first_scanline, 4);
+ for (i=0; i<max_rows; i++)
+ out_rows[i] = This->image_data + This->stride * (first_scanline+i);
+
+ ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
+ if (ret == 0)
+ {
+ ERR("read_scanlines failed\n");
+ LeaveCriticalSection(&This->lock);
+ return E_FAIL;
+ }
+ }
+
+ if (This->bpp == 24)
+ {
+ /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
+ reverse_bgr8(3, This->image_data,
+ This->cinfo.output_width, This->cinfo.output_height,
+ This->stride);
+ }
+
+ if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
+ {
+ /* Adobe JPEG's have inverted CMYK data. */
+ for (i=0; i<data_size; i++)
+ This->image_data[i] ^= 0xff;
+ }
+
This->initialized = TRUE;
LeaveCriticalSection(&This->lock);
@@ -601,99 +653,11 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
{
JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
- UINT bpp;
- UINT stride;
- UINT data_size, i;
- UINT max_row_needed;
- jmp_buf jmpbuf;
- WICRect rect;
- TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
-
- if (!prc)
- {
- rect.X = 0;
- rect.Y = 0;
- rect.Width = This->cinfo.output_width;
- rect.Height = This->cinfo.output_height;
- prc = &rect;
- }
- else
- {
- if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->cinfo.output_width ||
- prc->Y+prc->Height > This->cinfo.output_height)
- return E_INVALIDARG;
- }
-
- if (This->cinfo.out_color_space == JCS_GRAYSCALE) bpp = 8;
- else if (This->cinfo.out_color_space == JCS_CMYK) bpp = 32;
- else bpp = 24;
-
- stride = (bpp * This->cinfo.output_width + 7) / 8;
- data_size = stride * This->cinfo.output_height;
-
- max_row_needed = prc->Y + prc->Height;
- if (max_row_needed > This->cinfo.output_height) return E_INVALIDARG;
- EnterCriticalSection(&This->lock);
-
- if (!This->image_data)
- {
- This->image_data = HeapAlloc(GetProcessHeap(), 0, data_size);
- if (!This->image_data)
- {
- LeaveCriticalSection(&This->lock);
- return E_OUTOFMEMORY;
- }
- }
-
- This->cinfo.client_data = jmpbuf;
-
- if (setjmp(jmpbuf))
- {
- LeaveCriticalSection(&This->lock);
- return E_FAIL;
- }
-
- while (max_row_needed > This->cinfo.output_scanline)
- {
- UINT first_scanline = This->cinfo.output_scanline;
- UINT max_rows;
- JSAMPROW out_rows[4];
- JDIMENSION ret;
-
- max_rows = min(This->cinfo.output_height-first_scanline, 4);
- for (i=0; i<max_rows; i++)
- out_rows[i] = This->image_data + stride * (first_scanline+i);
-
- ret = pjpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
-
- if (ret == 0)
- {
- ERR("read_scanlines failed\n");
- LeaveCriticalSection(&This->lock);
- return E_FAIL;
- }
- }
-
- if (bpp == 24)
- {
- /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
- reverse_bgr8(3, This->image_data,
- This->cinfo.output_width, This->cinfo.output_height,
- stride);
- }
-
- if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
- {
- /* Adobe JPEG's have inverted CMYK data. */
- for (i=0; i<data_size; i++)
- This->image_data[i] ^= 0xff;
- }
-
- LeaveCriticalSection(&This->lock);
+ TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
- return copy_pixels(bpp, This->image_data,
- This->cinfo.output_width, This->cinfo.output_height, stride,
+ return copy_pixels(This->bpp, This->image_data,
+ This->cinfo.output_width, This->cinfo.output_height, This->stride,
prc, cbStride, cbBufferSize, pbBuffer);
}
--
2.13.4

0006-windowscodecs-Add-support-for-CMYK-to-BGR-conversion.patch

From a7440161f8a784941806c12cbb57f8a6a08707a8 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Thu, 17 Aug 2017 14:57:18 +0800
Subject: [6/6] windowscodecs: Add support for CMYK to BGR conversion.
Content-Type: text/plain; charset=UTF-8
---
dlls/windowscodecs/converter.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/dlls/windowscodecs/converter.c b/dlls/windowscodecs/converter.c
index 1378c85bc2..4fb74f953e 100644
--- a/dlls/windowscodecs/converter.c
+++ b/dlls/windowscodecs/converter.c
@@ -1085,6 +1085,48 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec
}
return S_OK;
+ case format_32bppCMYK:
+ if (prc)
+ {
+ BYTE *srcdata;
+ UINT srcstride, srcdatasize;
+
+ srcstride = 4 * prc->Width;
+ srcdatasize = srcstride * prc->Height;
+
+ srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+ if (!srcdata) return E_OUTOFMEMORY;
+
+ hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+ if (SUCCEEDED(hr))
+ {
+ INT x, y;
+ BYTE *src = srcdata, *dst = pbBuffer;
+
+ for (y = 0; y < prc->Height; y++)
+ {
+ BYTE *cmyk = src;
+ BYTE *bgr = dst;
+
+ for (x = 0; x < prc->Width; x++)
+ {
+ BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
+ bgr[0] = (255 - y) * (255 - k) / 255; /* B */
+ bgr[1] = (255 - m) * (255 - k) / 255; /* G */
+ bgr[2] = (255 - c) * (255 - k) / 255; /* R */
+ cmyk += 4;
+ bgr += 3;
+ }
+ src += srcstride;
+ dst += cbStride;
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, srcdata);
+ return hr;
+ }
+ return S_OK;
+
default:
FIXME("Unimplemented conversion path!\n");
return WINCODEC_ERR_UNSUPPORTEDOPERATION;
--
2.13.4