Vincent Povirk : windowscodecs: Implement Initialize for the PNG decoder.

Alexandre Julliard julliard at winehq.org
Fri Aug 28 10:17:56 CDT 2009


Module: wine
Branch: master
Commit: 7d74dba5b80274ea36ee5f27f9510e92ceae12f3
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=7d74dba5b80274ea36ee5f27f9510e92ceae12f3

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Thu Aug 13 17:50:16 2009 -0500

windowscodecs: Implement Initialize for the PNG decoder.

---

 dlls/windowscodecs/pngformat.c |  201 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 199 insertions(+), 2 deletions(-)

diff --git a/dlls/windowscodecs/pngformat.c b/dlls/windowscodecs/pngformat.c
index 864a5bd..bd0482b 100644
--- a/dlls/windowscodecs/pngformat.c
+++ b/dlls/windowscodecs/pngformat.c
@@ -45,6 +45,19 @@ static void *libpng_handle;
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
 MAKE_FUNCPTR(png_create_read_struct);
 MAKE_FUNCPTR(png_create_info_struct);
+MAKE_FUNCPTR(png_destroy_read_struct);
+MAKE_FUNCPTR(png_error);
+MAKE_FUNCPTR(png_get_bit_depth);
+MAKE_FUNCPTR(png_get_color_type);
+MAKE_FUNCPTR(png_get_image_height);
+MAKE_FUNCPTR(png_get_image_width);
+MAKE_FUNCPTR(png_get_io_ptr);
+MAKE_FUNCPTR(png_set_bgr);
+MAKE_FUNCPTR(png_set_gray_to_rgb);
+MAKE_FUNCPTR(png_set_read_fn);
+MAKE_FUNCPTR(png_read_end);
+MAKE_FUNCPTR(png_read_image);
+MAKE_FUNCPTR(png_read_info);
 #undef MAKE_FUNCPTR
 
 static void *load_libpng(void)
@@ -58,6 +71,19 @@ static void *load_libpng(void)
     }
         LOAD_FUNCPTR(png_create_read_struct);
         LOAD_FUNCPTR(png_create_info_struct);
+        LOAD_FUNCPTR(png_destroy_read_struct);
+        LOAD_FUNCPTR(png_error);
+        LOAD_FUNCPTR(png_get_bit_depth);
+        LOAD_FUNCPTR(png_get_color_type);
+        LOAD_FUNCPTR(png_get_image_height);
+        LOAD_FUNCPTR(png_get_image_width);
+        LOAD_FUNCPTR(png_get_io_ptr);
+        LOAD_FUNCPTR(png_set_bgr);
+        LOAD_FUNCPTR(png_set_gray_to_rgb);
+        LOAD_FUNCPTR(png_set_read_fn);
+        LOAD_FUNCPTR(png_read_end);
+        LOAD_FUNCPTR(png_read_image);
+        LOAD_FUNCPTR(png_read_info);
 
 #undef LOAD_FUNCPTR
     }
@@ -67,6 +93,15 @@ static void *load_libpng(void)
 typedef struct {
     const IWICBitmapDecoderVtbl *lpVtbl;
     LONG ref;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    png_infop end_info;
+    BOOL initialized;
+    int bpp;
+    int width, height;
+    UINT stride;
+    const WICPixelFormatGUID *format;
+    BYTE *image_bits;
 } PngDecoder;
 
 static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
@@ -110,6 +145,9 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
 
     if (ref == 0)
     {
+        if (This->png_ptr)
+            ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
+        HeapFree(GetProcessHeap(), 0, This->image_bits);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -123,11 +161,165 @@ static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStre
     return E_NOTIMPL;
 }
 
+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)
 {
-    FIXME("(%p,%p,%x): stub\n", iface, pIStream, cacheOptions);
-    return E_NOTIMPL;
+    PngDecoder *This = (PngDecoder*)iface;
+    LARGE_INTEGER seek;
+    HRESULT hr;
+    png_bytep *row_pointers=NULL;
+    UINT image_size;
+    UINT i;
+    int color_type, bit_depth;
+    TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
+
+    /* initialize libpng */
+    This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!This->png_ptr) return E_FAIL;
+
+    This->info_ptr = ppng_create_info_struct(This->png_ptr);
+    if (!This->info_ptr)
+    {
+        ppng_destroy_read_struct(&This->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+        This->png_ptr = NULL;
+        return E_FAIL;
+    }
+
+    This->end_info = ppng_create_info_struct(This->png_ptr);
+    if (!This->info_ptr)
+    {
+        ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, (png_infopp)NULL);
+        This->png_ptr = NULL;
+        return E_FAIL;
+    }
+
+    /* set up setjmp/longjmp error handling */
+    if (setjmp(png_jmpbuf(This->png_ptr)))
+    {
+        ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
+        HeapFree(GetProcessHeap(), 0, row_pointers);
+        This->png_ptr = NULL;
+        return E_FAIL;
+    }
+
+    /* seek to the start of the stream */
+    seek.QuadPart = 0;
+    hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) return hr;
+
+    /* 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);
+    bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
+
+    switch (color_type)
+    {
+    case PNG_COLOR_TYPE_GRAY:
+        This->bpp = bit_depth;
+        switch (bit_depth)
+        {
+        case 1: This->format = &GUID_WICPixelFormatBlackWhite; break;
+        case 2: This->format = &GUID_WICPixelFormat2bppGray; break;
+        case 4: This->format = &GUID_WICPixelFormat4bppGray; break;
+        case 8: This->format = &GUID_WICPixelFormat8bppGray; break;
+        case 16: This->format = &GUID_WICPixelFormat16bppGray; break;
+        default:
+            ERR("invalid grayscale bit depth: %i\n", bit_depth);
+            return E_FAIL;
+        }
+        break;
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+        /* WIC does not support grayscale alpha formats so use RGBA */
+        ppng_set_gray_to_rgb(This->png_ptr);
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+        This->bpp = bit_depth * 4;
+        switch (bit_depth)
+        {
+        case 8:
+            ppng_set_bgr(This->png_ptr);
+            This->format = &GUID_WICPixelFormat32bppBGRA;
+            break;
+        case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break;
+        default:
+            ERR("invalid RGBA bit depth: %i\n", bit_depth);
+            return E_FAIL;
+        }
+        break;
+    case PNG_COLOR_TYPE_PALETTE:
+        This->bpp = bit_depth;
+        switch (bit_depth)
+        {
+        case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break;
+        case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break;
+        case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break;
+        case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break;
+        default:
+            ERR("invalid indexed color bit depth: %i\n", bit_depth);
+            return E_FAIL;
+        }
+        break;
+    case PNG_COLOR_TYPE_RGB:
+        This->bpp = bit_depth * 3;
+        switch (bit_depth)
+        {
+        case 8:
+            ppng_set_bgr(This->png_ptr);
+            This->format = &GUID_WICPixelFormat24bppBGR;
+            break;
+        case 16: This->format = &GUID_WICPixelFormat48bppRGB; break;
+        default:
+            ERR("invalid RGB color bit depth: %i\n", bit_depth);
+            return E_FAIL;
+        }
+        break;
+    default:
+        ERR("invalid color type %i\n", color_type);
+        return E_FAIL;
+    }
+
+    /* 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;
+    image_size = This->stride * This->height;
+
+    This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size);
+    if (!This->image_bits) return E_OUTOFMEMORY;
+
+    row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
+    if (!row_pointers) return E_OUTOFMEMORY;
+
+    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;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
@@ -232,6 +424,11 @@ HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
 
     This->lpVtbl = &PngDecoder_Vtbl;
     This->ref = 1;
+    This->png_ptr = NULL;
+    This->info_ptr = NULL;
+    This->end_info = NULL;
+    This->initialized = FALSE;
+    This->image_bits = NULL;
 
     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
     IUnknown_Release((IUnknown*)This);




More information about the wine-cvs mailing list