Commit 361b0ed5 authored by Dmitry Timoshkov's avatar Dmitry Timoshkov Committed by Alexandre Julliard

windowscodecs: Move JPEG frame image data initialization from Frame::CopyPixels…

windowscodecs: Move JPEG frame image data initialization from Frame::CopyPixels to Decoder::Initialize. This is how PNG decoder does things, and it avoids image data corruption in some cases (presumably when libjpeg reuses existing scanline data). Signed-off-by: 's avatarDmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: 's avatarVincent Povirk <vincent@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 241335ce
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "wincodecs_private.h" #include "wincodecs_private.h"
#include "wine/heap.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/library.h" #include "wine/library.h"
...@@ -155,6 +156,7 @@ typedef struct { ...@@ -155,6 +156,7 @@ typedef struct {
struct jpeg_error_mgr jerr; struct jpeg_error_mgr jerr;
struct jpeg_source_mgr source_mgr; struct jpeg_source_mgr source_mgr;
BYTE source_buffer[1024]; BYTE source_buffer[1024];
UINT bpp, stride;
BYTE *image_data; BYTE *image_data;
CRITICAL_SECTION lock; CRITICAL_SECTION lock;
} JpegDecoder; } JpegDecoder;
...@@ -303,6 +305,8 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream * ...@@ -303,6 +305,8 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
int ret; int ret;
LARGE_INTEGER seek; LARGE_INTEGER seek;
jmp_buf jmpbuf; jmp_buf jmpbuf;
UINT data_size, i;
TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions); TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
EnterCriticalSection(&This->lock); EnterCriticalSection(&This->lock);
...@@ -381,6 +385,55 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream * ...@@ -381,6 +385,55 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
return E_FAIL; 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 = heap_alloc(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; This->initialized = TRUE;
LeaveCriticalSection(&This->lock); LeaveCriticalSection(&This->lock);
...@@ -590,104 +643,11 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, ...@@ -590,104 +643,11 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
{ {
JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface); JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
UINT bpp;
UINT stride;
UINT data_size;
UINT max_row_needed;
jmp_buf jmpbuf;
WICRect rect;
TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(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) TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
{
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];
UINT i;
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 + stride * first_scanline,
This->cinfo.output_width, This->cinfo.output_scanline - first_scanline,
stride);
}
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. */
while(pDwordData < pDwordDataEnd)
*pDwordData++ ^= 0xffffffff;
}
}
LeaveCriticalSection(&This->lock);
return copy_pixels(bpp, This->image_data, return copy_pixels(This->bpp, This->image_data,
This->cinfo.output_width, This->cinfo.output_height, stride, This->cinfo.output_width, This->cinfo.output_height, This->stride,
prc, cbStride, cbBufferSize, pbBuffer); prc, cbStride, cbBufferSize, pbBuffer);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment