windowscodecs: Read PNGs sequentially.
This commit is contained in:
parent
8435e40874
commit
ea35386b2b
|
@ -56,11 +56,8 @@ MAKE_FUNCPTR(png_get_image_height);
|
||||||
MAKE_FUNCPTR(png_get_image_width);
|
MAKE_FUNCPTR(png_get_image_width);
|
||||||
MAKE_FUNCPTR(png_get_io_ptr);
|
MAKE_FUNCPTR(png_get_io_ptr);
|
||||||
MAKE_FUNCPTR(png_get_pHYs);
|
MAKE_FUNCPTR(png_get_pHYs);
|
||||||
MAKE_FUNCPTR(png_get_progressive_ptr);
|
|
||||||
MAKE_FUNCPTR(png_get_PLTE);
|
MAKE_FUNCPTR(png_get_PLTE);
|
||||||
MAKE_FUNCPTR(png_get_tRNS);
|
MAKE_FUNCPTR(png_get_tRNS);
|
||||||
MAKE_FUNCPTR(png_process_data);
|
|
||||||
MAKE_FUNCPTR(png_progressive_combine_row);
|
|
||||||
MAKE_FUNCPTR(png_set_bgr);
|
MAKE_FUNCPTR(png_set_bgr);
|
||||||
MAKE_FUNCPTR(png_set_error_fn);
|
MAKE_FUNCPTR(png_set_error_fn);
|
||||||
#if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
|
#if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
|
||||||
|
@ -72,7 +69,6 @@ MAKE_FUNCPTR(png_set_filler);
|
||||||
MAKE_FUNCPTR(png_set_gray_to_rgb);
|
MAKE_FUNCPTR(png_set_gray_to_rgb);
|
||||||
MAKE_FUNCPTR(png_set_IHDR);
|
MAKE_FUNCPTR(png_set_IHDR);
|
||||||
MAKE_FUNCPTR(png_set_pHYs);
|
MAKE_FUNCPTR(png_set_pHYs);
|
||||||
MAKE_FUNCPTR(png_set_progressive_read_fn);
|
|
||||||
MAKE_FUNCPTR(png_set_read_fn);
|
MAKE_FUNCPTR(png_set_read_fn);
|
||||||
MAKE_FUNCPTR(png_set_strip_16);
|
MAKE_FUNCPTR(png_set_strip_16);
|
||||||
MAKE_FUNCPTR(png_set_tRNS_to_alpha);
|
MAKE_FUNCPTR(png_set_tRNS_to_alpha);
|
||||||
|
@ -80,7 +76,6 @@ MAKE_FUNCPTR(png_set_write_fn);
|
||||||
MAKE_FUNCPTR(png_read_end);
|
MAKE_FUNCPTR(png_read_end);
|
||||||
MAKE_FUNCPTR(png_read_image);
|
MAKE_FUNCPTR(png_read_image);
|
||||||
MAKE_FUNCPTR(png_read_info);
|
MAKE_FUNCPTR(png_read_info);
|
||||||
MAKE_FUNCPTR(png_read_update_info);
|
|
||||||
MAKE_FUNCPTR(png_write_end);
|
MAKE_FUNCPTR(png_write_end);
|
||||||
MAKE_FUNCPTR(png_write_info);
|
MAKE_FUNCPTR(png_write_info);
|
||||||
MAKE_FUNCPTR(png_write_rows);
|
MAKE_FUNCPTR(png_write_rows);
|
||||||
|
@ -108,11 +103,8 @@ static void *load_libpng(void)
|
||||||
LOAD_FUNCPTR(png_get_image_width);
|
LOAD_FUNCPTR(png_get_image_width);
|
||||||
LOAD_FUNCPTR(png_get_io_ptr);
|
LOAD_FUNCPTR(png_get_io_ptr);
|
||||||
LOAD_FUNCPTR(png_get_pHYs);
|
LOAD_FUNCPTR(png_get_pHYs);
|
||||||
LOAD_FUNCPTR(png_get_progressive_ptr);
|
|
||||||
LOAD_FUNCPTR(png_get_PLTE);
|
LOAD_FUNCPTR(png_get_PLTE);
|
||||||
LOAD_FUNCPTR(png_get_tRNS);
|
LOAD_FUNCPTR(png_get_tRNS);
|
||||||
LOAD_FUNCPTR(png_process_data);
|
|
||||||
LOAD_FUNCPTR(png_progressive_combine_row);
|
|
||||||
LOAD_FUNCPTR(png_set_bgr);
|
LOAD_FUNCPTR(png_set_bgr);
|
||||||
LOAD_FUNCPTR(png_set_error_fn);
|
LOAD_FUNCPTR(png_set_error_fn);
|
||||||
#if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
|
#if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
|
||||||
|
@ -124,7 +116,6 @@ static void *load_libpng(void)
|
||||||
LOAD_FUNCPTR(png_set_gray_to_rgb);
|
LOAD_FUNCPTR(png_set_gray_to_rgb);
|
||||||
LOAD_FUNCPTR(png_set_IHDR);
|
LOAD_FUNCPTR(png_set_IHDR);
|
||||||
LOAD_FUNCPTR(png_set_pHYs);
|
LOAD_FUNCPTR(png_set_pHYs);
|
||||||
LOAD_FUNCPTR(png_set_progressive_read_fn);
|
|
||||||
LOAD_FUNCPTR(png_set_read_fn);
|
LOAD_FUNCPTR(png_set_read_fn);
|
||||||
LOAD_FUNCPTR(png_set_strip_16);
|
LOAD_FUNCPTR(png_set_strip_16);
|
||||||
LOAD_FUNCPTR(png_set_tRNS_to_alpha);
|
LOAD_FUNCPTR(png_set_tRNS_to_alpha);
|
||||||
|
@ -132,7 +123,6 @@ static void *load_libpng(void)
|
||||||
LOAD_FUNCPTR(png_read_end);
|
LOAD_FUNCPTR(png_read_end);
|
||||||
LOAD_FUNCPTR(png_read_image);
|
LOAD_FUNCPTR(png_read_image);
|
||||||
LOAD_FUNCPTR(png_read_info);
|
LOAD_FUNCPTR(png_read_info);
|
||||||
LOAD_FUNCPTR(png_read_update_info);
|
|
||||||
LOAD_FUNCPTR(png_write_end);
|
LOAD_FUNCPTR(png_write_end);
|
||||||
LOAD_FUNCPTR(png_write_info);
|
LOAD_FUNCPTR(png_write_info);
|
||||||
LOAD_FUNCPTR(png_write_rows);
|
LOAD_FUNCPTR(png_write_rows);
|
||||||
|
@ -165,6 +155,7 @@ typedef struct {
|
||||||
LONG ref;
|
LONG ref;
|
||||||
png_structp png_ptr;
|
png_structp png_ptr;
|
||||||
png_infop info_ptr;
|
png_infop info_ptr;
|
||||||
|
png_infop end_info;
|
||||||
BOOL initialized;
|
BOOL initialized;
|
||||||
int bpp;
|
int bpp;
|
||||||
int width, height;
|
int width, height;
|
||||||
|
@ -228,7 +219,7 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
|
||||||
if (ref == 0)
|
if (ref == 0)
|
||||||
{
|
{
|
||||||
if (This->png_ptr)
|
if (This->png_ptr)
|
||||||
ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL);
|
ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
|
||||||
This->lock.DebugInfo->Spare[0] = 0;
|
This->lock.DebugInfo->Spare[0] = 0;
|
||||||
DeleteCriticalSection(&This->lock);
|
DeleteCriticalSection(&This->lock);
|
||||||
HeapFree(GetProcessHeap(), 0, This->image_bits);
|
HeapFree(GetProcessHeap(), 0, This->image_bits);
|
||||||
|
@ -245,18 +236,86 @@ static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStre
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void info_callback(png_structp png_ptr, png_infop info)
|
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||||
{
|
{
|
||||||
|
IStream *stream = ppng_get_io_ptr(png_ptr);
|
||||||
|
HRESULT hr;
|
||||||
|
ULONG bytesread;
|
||||||
|
|
||||||
|
hr = IStream_Read(stream, data, length, &bytesread);
|
||||||
|
if (FAILED(hr) || bytesread != length)
|
||||||
|
{
|
||||||
|
ppng_error(png_ptr, "failed reading data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
|
||||||
|
WICDecodeOptions cacheOptions)
|
||||||
|
{
|
||||||
|
PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
||||||
|
LARGE_INTEGER seek;
|
||||||
|
HRESULT hr=S_OK;
|
||||||
|
png_bytep *row_pointers=NULL;
|
||||||
|
UINT image_size;
|
||||||
|
UINT i;
|
||||||
int color_type, bit_depth;
|
int color_type, bit_depth;
|
||||||
png_bytep trans;
|
png_bytep trans;
|
||||||
int num_trans;
|
int num_trans;
|
||||||
png_uint_32 transparency;
|
png_uint_32 transparency;
|
||||||
png_color_16p trans_values;
|
png_color_16p trans_values;
|
||||||
UINT image_size;
|
jmp_buf jmpbuf;
|
||||||
HRESULT hr = S_OK;
|
|
||||||
PngDecoder *This;
|
|
||||||
|
|
||||||
This = (PngDecoder*) ppng_get_progressive_ptr(png_ptr);
|
TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
|
||||||
|
|
||||||
|
EnterCriticalSection(&This->lock);
|
||||||
|
|
||||||
|
/* initialize libpng */
|
||||||
|
This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (!This->png_ptr)
|
||||||
|
{
|
||||||
|
hr = E_FAIL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
This->info_ptr = ppng_create_info_struct(This->png_ptr);
|
||||||
|
if (!This->info_ptr)
|
||||||
|
{
|
||||||
|
ppng_destroy_read_struct(&This->png_ptr, NULL, NULL);
|
||||||
|
This->png_ptr = NULL;
|
||||||
|
hr = E_FAIL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
This->end_info = ppng_create_info_struct(This->png_ptr);
|
||||||
|
if (!This->info_ptr)
|
||||||
|
{
|
||||||
|
ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL);
|
||||||
|
This->png_ptr = NULL;
|
||||||
|
hr = E_FAIL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up setjmp/longjmp error handling */
|
||||||
|
if (setjmp(jmpbuf))
|
||||||
|
{
|
||||||
|
ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
|
||||||
|
HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||||
|
This->png_ptr = NULL;
|
||||||
|
hr = E_FAIL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn);
|
||||||
|
|
||||||
|
/* seek to the start of the stream */
|
||||||
|
seek.QuadPart = 0;
|
||||||
|
hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
|
||||||
|
if (FAILED(hr)) goto end;
|
||||||
|
|
||||||
|
/* set up custom i/o handling */
|
||||||
|
ppng_set_read_fn(This->png_ptr, pIStream, user_read_data);
|
||||||
|
|
||||||
|
/* read the header */
|
||||||
|
ppng_read_info(This->png_ptr, This->info_ptr);
|
||||||
|
|
||||||
/* choose a pixel format */
|
/* choose a pixel format */
|
||||||
color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
|
color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
|
||||||
|
@ -355,6 +414,7 @@ static void info_callback(png_structp png_ptr, png_infop info)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read the image data */
|
||||||
This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
|
This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
|
||||||
This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
|
This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
|
||||||
This->stride = This->width * This->bpp;
|
This->stride = This->width * This->bpp;
|
||||||
|
@ -367,97 +427,25 @@ static void info_callback(png_structp png_ptr, png_infop info)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ppng_read_update_info(This->png_ptr, This->info_ptr);
|
row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
|
||||||
|
if (!row_pointers)
|
||||||
|
{
|
||||||
|
hr = E_OUTOFMEMORY;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<This->height; i++)
|
||||||
|
row_pointers[i] = This->image_bits + i * This->stride;
|
||||||
|
|
||||||
|
ppng_read_image(This->png_ptr, row_pointers);
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||||
|
row_pointers = NULL;
|
||||||
|
|
||||||
|
ppng_read_end(This->png_ptr, This->end_info);
|
||||||
|
|
||||||
This->initialized = TRUE;
|
This->initialized = TRUE;
|
||||||
|
|
||||||
end:
|
|
||||||
if (FAILED(hr))
|
|
||||||
ERR("PNG info parsing failed, hr=0x%08X\n", hr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void row_callback(png_structp png_ptr, png_bytep new_row,
|
|
||||||
png_uint_32 row_num, int pass)
|
|
||||||
{
|
|
||||||
png_bytep old_row;
|
|
||||||
PngDecoder *This;
|
|
||||||
|
|
||||||
This = (PngDecoder*) ppng_get_progressive_ptr(png_ptr);
|
|
||||||
if (!This->initialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
old_row = ((png_bytep)This->image_bits) + row_num*This->stride;
|
|
||||||
ppng_progressive_combine_row(png_ptr, old_row, new_row);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void end_callback(png_structp png_ptr, png_infop info)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
|
|
||||||
WICDecodeOptions cacheOptions)
|
|
||||||
{
|
|
||||||
PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
|
|
||||||
LARGE_INTEGER seek;
|
|
||||||
HRESULT hr=S_OK;
|
|
||||||
png_bytep *row_pointers=NULL;
|
|
||||||
jmp_buf jmpbuf;
|
|
||||||
BYTE buffer[8096];
|
|
||||||
ULONG bytesRead = 0;
|
|
||||||
|
|
||||||
TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
|
|
||||||
|
|
||||||
EnterCriticalSection(&This->lock);
|
|
||||||
|
|
||||||
/* initialize libpng */
|
|
||||||
This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
||||||
if (!This->png_ptr)
|
|
||||||
{
|
|
||||||
hr = E_FAIL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
This->info_ptr = ppng_create_info_struct(This->png_ptr);
|
|
||||||
if (!This->info_ptr)
|
|
||||||
{
|
|
||||||
ppng_destroy_read_struct(&This->png_ptr, NULL, NULL);
|
|
||||||
This->png_ptr = NULL;
|
|
||||||
hr = E_FAIL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set up setjmp/longjmp error handling */
|
|
||||||
if (setjmp(jmpbuf))
|
|
||||||
{
|
|
||||||
ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL);
|
|
||||||
HeapFree(GetProcessHeap(), 0, row_pointers);
|
|
||||||
This->png_ptr = NULL;
|
|
||||||
hr = E_FAIL;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
ppng_set_error_fn(This->png_ptr, &jmpbuf, user_error_fn, user_warning_fn);
|
|
||||||
|
|
||||||
/* seek to the start of the stream */
|
|
||||||
seek.QuadPart = 0;
|
|
||||||
hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
|
|
||||||
if (FAILED(hr)) goto end;
|
|
||||||
|
|
||||||
/* set up progressive loading */
|
|
||||||
ppng_set_progressive_read_fn(This->png_ptr, (void*)This,
|
|
||||||
info_callback, row_callback, end_callback);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
hr = IStream_Read(pIStream, buffer, sizeof(buffer), &bytesRead);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
ppng_process_data(This->png_ptr, This->info_ptr, buffer, bytesRead);
|
|
||||||
} while (bytesRead == sizeof(buffer));
|
|
||||||
if (hr == S_FALSE)
|
|
||||||
hr = S_OK;
|
|
||||||
if (FAILED(hr))
|
|
||||||
ERR("reading PNG file failed, error 0x%08X\n", hr);
|
|
||||||
if (!This->initialized)
|
|
||||||
hr = E_FAIL;
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
|
||||||
LeaveCriticalSection(&This->lock);
|
LeaveCriticalSection(&This->lock);
|
||||||
|
@ -780,6 +768,7 @@ HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
|
||||||
This->ref = 1;
|
This->ref = 1;
|
||||||
This->png_ptr = NULL;
|
This->png_ptr = NULL;
|
||||||
This->info_ptr = NULL;
|
This->info_ptr = NULL;
|
||||||
|
This->end_info = NULL;
|
||||||
This->initialized = FALSE;
|
This->initialized = FALSE;
|
||||||
This->image_bits = NULL;
|
This->image_bits = NULL;
|
||||||
InitializeCriticalSection(&This->lock);
|
InitializeCriticalSection(&This->lock);
|
||||||
|
|
Loading…
Reference in New Issue