From ea35386b2b11f4f74f8dfbae5f614ee49689e6af Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Tue, 4 Oct 2011 16:44:46 +0200 Subject: [PATCH] windowscodecs: Read PNGs sequentially. --- dlls/windowscodecs/pngformat.c | 185 +++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 98 deletions(-) diff --git a/dlls/windowscodecs/pngformat.c b/dlls/windowscodecs/pngformat.c index f5f6fdb5eaf..b3d92fded10 100644 --- a/dlls/windowscodecs/pngformat.c +++ b/dlls/windowscodecs/pngformat.c @@ -56,11 +56,8 @@ MAKE_FUNCPTR(png_get_image_height); MAKE_FUNCPTR(png_get_image_width); MAKE_FUNCPTR(png_get_io_ptr); MAKE_FUNCPTR(png_get_pHYs); -MAKE_FUNCPTR(png_get_progressive_ptr); MAKE_FUNCPTR(png_get_PLTE); 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_error_fn); #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_IHDR); MAKE_FUNCPTR(png_set_pHYs); -MAKE_FUNCPTR(png_set_progressive_read_fn); MAKE_FUNCPTR(png_set_read_fn); MAKE_FUNCPTR(png_set_strip_16); 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_image); MAKE_FUNCPTR(png_read_info); -MAKE_FUNCPTR(png_read_update_info); MAKE_FUNCPTR(png_write_end); MAKE_FUNCPTR(png_write_info); MAKE_FUNCPTR(png_write_rows); @@ -108,11 +103,8 @@ static void *load_libpng(void) LOAD_FUNCPTR(png_get_image_width); LOAD_FUNCPTR(png_get_io_ptr); LOAD_FUNCPTR(png_get_pHYs); - LOAD_FUNCPTR(png_get_progressive_ptr); LOAD_FUNCPTR(png_get_PLTE); 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_error_fn); #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_IHDR); LOAD_FUNCPTR(png_set_pHYs); - LOAD_FUNCPTR(png_set_progressive_read_fn); LOAD_FUNCPTR(png_set_read_fn); LOAD_FUNCPTR(png_set_strip_16); 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_image); LOAD_FUNCPTR(png_read_info); - LOAD_FUNCPTR(png_read_update_info); LOAD_FUNCPTR(png_write_end); LOAD_FUNCPTR(png_write_info); LOAD_FUNCPTR(png_write_rows); @@ -165,6 +155,7 @@ typedef struct { LONG ref; png_structp png_ptr; png_infop info_ptr; + png_infop end_info; BOOL initialized; int bpp; int width, height; @@ -228,7 +219,7 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface) if (ref == 0) { 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; DeleteCriticalSection(&This->lock); HeapFree(GetProcessHeap(), 0, This->image_bits); @@ -245,18 +236,86 @@ static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStre 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; png_bytep trans; int num_trans; png_uint_32 transparency; png_color_16p trans_values; - UINT image_size; - HRESULT hr = S_OK; - PngDecoder *This; + jmp_buf jmpbuf; + + 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 = (PngDecoder*) ppng_get_progressive_ptr(png_ptr); + 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 */ 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; } + /* read the image data */ 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->stride = This->width * This->bpp; @@ -367,96 +427,24 @@ static void info_callback(png_structp png_ptr, png_infop info) goto end; } - ppng_read_update_info(This->png_ptr, This->info_ptr); - 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) + row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height); + if (!row_pointers) { - hr = E_FAIL; + hr = E_OUTOFMEMORY; 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; - } + for (i=0; iheight; i++) + row_pointers[i] = This->image_bits + i * This->stride; - /* 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); + ppng_read_image(This->png_ptr, row_pointers); - /* seek to the start of the stream */ - seek.QuadPart = 0; - hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); - if (FAILED(hr)) goto end; + HeapFree(GetProcessHeap(), 0, row_pointers); + row_pointers = NULL; - /* set up progressive loading */ - ppng_set_progressive_read_fn(This->png_ptr, (void*)This, - info_callback, row_callback, end_callback); + ppng_read_end(This->png_ptr, This->end_info); - 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; + This->initialized = TRUE; end: @@ -780,6 +768,7 @@ HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) This->ref = 1; This->png_ptr = NULL; This->info_ptr = NULL; + This->end_info = NULL; This->initialized = FALSE; This->image_bits = NULL; InitializeCriticalSection(&This->lock); -- 2.11.4.GIT