d3d9: Always pass "struct event_data" to "event_fn" in the stateblock tests.
[wine] / dlls / windowscodecs / pngformat.c
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <stdarg.h>
23
24 #ifdef HAVE_PNG_H
25 #include <png.h>
26 #endif
27
28 #define COBJMACROS
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "objbase.h"
33 #include "wincodec.h"
34
35 #include "wincodecs_private.h"
36
37 #include "wine/debug.h"
38 #include "wine/library.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
41
42 #ifdef SONAME_LIBPNG
43
44 static void *libpng_handle;
45 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
46 MAKE_FUNCPTR(png_create_read_struct);
47 MAKE_FUNCPTR(png_create_info_struct);
48 MAKE_FUNCPTR(png_destroy_read_struct);
49 MAKE_FUNCPTR(png_error);
50 MAKE_FUNCPTR(png_get_bit_depth);
51 MAKE_FUNCPTR(png_get_color_type);
52 MAKE_FUNCPTR(png_get_image_height);
53 MAKE_FUNCPTR(png_get_image_width);
54 MAKE_FUNCPTR(png_get_io_ptr);
55 MAKE_FUNCPTR(png_get_PLTE);
56 MAKE_FUNCPTR(png_get_tRNS);
57 MAKE_FUNCPTR(png_set_bgr);
58 MAKE_FUNCPTR(png_set_gray_1_2_4_to_8);
59 MAKE_FUNCPTR(png_set_gray_to_rgb);
60 MAKE_FUNCPTR(png_set_read_fn);
61 MAKE_FUNCPTR(png_set_strip_16);
62 MAKE_FUNCPTR(png_set_tRNS_to_alpha);
63 MAKE_FUNCPTR(png_read_end);
64 MAKE_FUNCPTR(png_read_image);
65 MAKE_FUNCPTR(png_read_info);
66 #undef MAKE_FUNCPTR
67
68 static void *load_libpng(void)
69 {
70     if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
71
72 #define LOAD_FUNCPTR(f) \
73     if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
74         libpng_handle = NULL; \
75         return NULL; \
76     }
77         LOAD_FUNCPTR(png_create_read_struct);
78         LOAD_FUNCPTR(png_create_info_struct);
79         LOAD_FUNCPTR(png_destroy_read_struct);
80         LOAD_FUNCPTR(png_error);
81         LOAD_FUNCPTR(png_get_bit_depth);
82         LOAD_FUNCPTR(png_get_color_type);
83         LOAD_FUNCPTR(png_get_image_height);
84         LOAD_FUNCPTR(png_get_image_width);
85         LOAD_FUNCPTR(png_get_io_ptr);
86         LOAD_FUNCPTR(png_get_PLTE);
87         LOAD_FUNCPTR(png_get_tRNS);
88         LOAD_FUNCPTR(png_set_bgr);
89         LOAD_FUNCPTR(png_set_gray_1_2_4_to_8);
90         LOAD_FUNCPTR(png_set_gray_to_rgb);
91         LOAD_FUNCPTR(png_set_read_fn);
92         LOAD_FUNCPTR(png_set_strip_16);
93         LOAD_FUNCPTR(png_set_tRNS_to_alpha);
94         LOAD_FUNCPTR(png_read_end);
95         LOAD_FUNCPTR(png_read_image);
96         LOAD_FUNCPTR(png_read_info);
97
98 #undef LOAD_FUNCPTR
99     }
100     return libpng_handle;
101 }
102
103 typedef struct {
104     const IWICBitmapDecoderVtbl *lpVtbl;
105     const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
106     LONG ref;
107     png_structp png_ptr;
108     png_infop info_ptr;
109     png_infop end_info;
110     BOOL initialized;
111     int bpp;
112     int width, height;
113     UINT stride;
114     const WICPixelFormatGUID *format;
115     BYTE *image_bits;
116 } PngDecoder;
117
118 static inline PngDecoder *impl_from_frame(IWICBitmapFrameDecode *iface)
119 {
120     return CONTAINING_RECORD(iface, PngDecoder, lpFrameVtbl);
121 }
122
123 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl;
124
125 static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
126     void **ppv)
127 {
128     PngDecoder *This = (PngDecoder*)iface;
129     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
130
131     if (!ppv) return E_INVALIDARG;
132
133     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
134     {
135         *ppv = This;
136     }
137     else
138     {
139         *ppv = NULL;
140         return E_NOINTERFACE;
141     }
142
143     IUnknown_AddRef((IUnknown*)*ppv);
144     return S_OK;
145 }
146
147 static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface)
148 {
149     PngDecoder *This = (PngDecoder*)iface;
150     ULONG ref = InterlockedIncrement(&This->ref);
151
152     TRACE("(%p) refcount=%u\n", iface, ref);
153
154     return ref;
155 }
156
157 static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
158 {
159     PngDecoder *This = (PngDecoder*)iface;
160     ULONG ref = InterlockedDecrement(&This->ref);
161
162     TRACE("(%p) refcount=%u\n", iface, ref);
163
164     if (ref == 0)
165     {
166         if (This->png_ptr)
167             ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
168         HeapFree(GetProcessHeap(), 0, This->image_bits);
169         HeapFree(GetProcessHeap(), 0, This);
170     }
171
172     return ref;
173 }
174
175 static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
176     DWORD *pdwCapability)
177 {
178     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
179     return E_NOTIMPL;
180 }
181
182 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
183 {
184     IStream *stream = ppng_get_io_ptr(png_ptr);
185     HRESULT hr;
186     ULONG bytesread;
187
188     hr = IStream_Read(stream, data, length, &bytesread);
189     if (FAILED(hr) || bytesread != length)
190     {
191         ppng_error(png_ptr, "failed reading data");
192     }
193 }
194
195 static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
196     WICDecodeOptions cacheOptions)
197 {
198     PngDecoder *This = (PngDecoder*)iface;
199     LARGE_INTEGER seek;
200     HRESULT hr;
201     png_bytep *row_pointers=NULL;
202     UINT image_size;
203     UINT i;
204     int color_type, bit_depth;
205     png_bytep trans;
206     int num_trans;
207     png_uint_32 transparency;
208     png_color_16p trans_values;
209     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
210
211     /* initialize libpng */
212     This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
213     if (!This->png_ptr) return E_FAIL;
214
215     This->info_ptr = ppng_create_info_struct(This->png_ptr);
216     if (!This->info_ptr)
217     {
218         ppng_destroy_read_struct(&This->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
219         This->png_ptr = NULL;
220         return E_FAIL;
221     }
222
223     This->end_info = ppng_create_info_struct(This->png_ptr);
224     if (!This->info_ptr)
225     {
226         ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, (png_infopp)NULL);
227         This->png_ptr = NULL;
228         return E_FAIL;
229     }
230
231     /* set up setjmp/longjmp error handling */
232     if (setjmp(png_jmpbuf(This->png_ptr)))
233     {
234         ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
235         HeapFree(GetProcessHeap(), 0, row_pointers);
236         This->png_ptr = NULL;
237         return E_FAIL;
238     }
239
240     /* seek to the start of the stream */
241     seek.QuadPart = 0;
242     hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
243     if (FAILED(hr)) return hr;
244
245     /* set up custom i/o handling */
246     ppng_set_read_fn(This->png_ptr, pIStream, user_read_data);
247
248     /* read the header */
249     ppng_read_info(This->png_ptr, This->info_ptr);
250
251     /* choose a pixel format */
252     color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
253     bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
254
255     /* check for color-keyed alpha */
256     transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
257
258     if (transparency && color_type != PNG_COLOR_TYPE_PALETTE)
259     {
260         /* expand to RGBA */
261         if (color_type == PNG_COLOR_TYPE_GRAY)
262         {
263             if (bit_depth < 8)
264             {
265                 ppng_set_gray_1_2_4_to_8(This->png_ptr);
266                 bit_depth = 8;
267             }
268             ppng_set_gray_to_rgb(This->png_ptr);
269         }
270         ppng_set_tRNS_to_alpha(This->png_ptr);
271         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
272     }
273
274     switch (color_type)
275     {
276     case PNG_COLOR_TYPE_GRAY:
277         This->bpp = bit_depth;
278         switch (bit_depth)
279         {
280         case 1: This->format = &GUID_WICPixelFormatBlackWhite; break;
281         case 2: This->format = &GUID_WICPixelFormat2bppGray; break;
282         case 4: This->format = &GUID_WICPixelFormat4bppGray; break;
283         case 8: This->format = &GUID_WICPixelFormat8bppGray; break;
284         case 16: This->format = &GUID_WICPixelFormat16bppGray; break;
285         default:
286             ERR("invalid grayscale bit depth: %i\n", bit_depth);
287             return E_FAIL;
288         }
289         break;
290     case PNG_COLOR_TYPE_GRAY_ALPHA:
291         /* WIC does not support grayscale alpha formats so use RGBA */
292         ppng_set_gray_to_rgb(This->png_ptr);
293     case PNG_COLOR_TYPE_RGB_ALPHA:
294         This->bpp = bit_depth * 4;
295         switch (bit_depth)
296         {
297         case 8:
298             ppng_set_bgr(This->png_ptr);
299             This->format = &GUID_WICPixelFormat32bppBGRA;
300             break;
301         case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break;
302         default:
303             ERR("invalid RGBA bit depth: %i\n", bit_depth);
304             return E_FAIL;
305         }
306         break;
307     case PNG_COLOR_TYPE_PALETTE:
308         This->bpp = bit_depth;
309         switch (bit_depth)
310         {
311         case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break;
312         case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break;
313         case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break;
314         case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break;
315         default:
316             ERR("invalid indexed color bit depth: %i\n", bit_depth);
317             return E_FAIL;
318         }
319         break;
320     case PNG_COLOR_TYPE_RGB:
321         This->bpp = bit_depth * 3;
322         switch (bit_depth)
323         {
324         case 8:
325             ppng_set_bgr(This->png_ptr);
326             This->format = &GUID_WICPixelFormat24bppBGR;
327             break;
328         case 16: This->format = &GUID_WICPixelFormat48bppRGB; break;
329         default:
330             ERR("invalid RGB color bit depth: %i\n", bit_depth);
331             return E_FAIL;
332         }
333         break;
334     default:
335         ERR("invalid color type %i\n", color_type);
336         return E_FAIL;
337     }
338
339     /* read the image data */
340     This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
341     This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
342     This->stride = This->width * This->bpp;
343     image_size = This->stride * This->height;
344
345     This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size);
346     if (!This->image_bits) return E_OUTOFMEMORY;
347
348     row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
349     if (!row_pointers) return E_OUTOFMEMORY;
350
351     for (i=0; i<This->height; i++)
352         row_pointers[i] = This->image_bits + i * This->stride;
353
354     ppng_read_image(This->png_ptr, row_pointers);
355
356     HeapFree(GetProcessHeap(), 0, row_pointers);
357     row_pointers = NULL;
358
359     ppng_read_end(This->png_ptr, This->end_info);
360
361     This->initialized = TRUE;
362
363     return S_OK;
364 }
365
366 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
367     GUID *pguidContainerFormat)
368 {
369     memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
370     return S_OK;
371 }
372
373 static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
374     IWICBitmapDecoderInfo **ppIDecoderInfo)
375 {
376     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
377     return E_NOTIMPL;
378 }
379
380 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
381     IWICPalette *pIPalette)
382 {
383     FIXME("(%p,%p): stub\n", iface, pIPalette);
384     return E_NOTIMPL;
385 }
386
387 static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
388     IWICMetadataQueryReader **ppIMetadataQueryReader)
389 {
390     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
391     return E_NOTIMPL;
392 }
393
394 static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface,
395     IWICBitmapSource **ppIBitmapSource)
396 {
397     FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
398     return E_NOTIMPL;
399 }
400
401 static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface,
402     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
403 {
404     FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
405     return E_NOTIMPL;
406 }
407
408 static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface,
409     IWICBitmapSource **ppIThumbnail)
410 {
411     TRACE("(%p,%p)\n", iface, ppIThumbnail);
412     return WINCODEC_ERR_CODECNOTHUMBNAIL;
413 }
414
415 static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface,
416     UINT *pCount)
417 {
418     *pCount = 1;
419     return S_OK;
420 }
421
422 static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface,
423     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
424 {
425     PngDecoder *This = (PngDecoder*)iface;
426     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
427
428     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
429
430     if (index != 0) return E_INVALIDARG;
431
432     IWICBitmapDecoder_AddRef(iface);
433
434     *ppIBitmapFrame = (void*)(&This->lpFrameVtbl);
435
436     return S_OK;
437 }
438
439 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = {
440     PngDecoder_QueryInterface,
441     PngDecoder_AddRef,
442     PngDecoder_Release,
443     PngDecoder_QueryCapability,
444     PngDecoder_Initialize,
445     PngDecoder_GetContainerFormat,
446     PngDecoder_GetDecoderInfo,
447     PngDecoder_CopyPalette,
448     PngDecoder_GetMetadataQueryReader,
449     PngDecoder_GetPreview,
450     PngDecoder_GetColorContexts,
451     PngDecoder_GetThumbnail,
452     PngDecoder_GetFrameCount,
453     PngDecoder_GetFrame
454 };
455
456 static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
457     void **ppv)
458 {
459     if (!ppv) return E_INVALIDARG;
460
461     if (IsEqualIID(&IID_IUnknown, iid) ||
462         IsEqualIID(&IID_IWICBitmapSource, iid) ||
463         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
464     {
465         *ppv = iface;
466     }
467     else
468     {
469         *ppv = NULL;
470         return E_NOINTERFACE;
471     }
472
473     IUnknown_AddRef((IUnknown*)*ppv);
474     return S_OK;
475 }
476
477 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
478 {
479     PngDecoder *This = impl_from_frame(iface);
480     return IUnknown_AddRef((IUnknown*)This);
481 }
482
483 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
484 {
485     PngDecoder *This = impl_from_frame(iface);
486     return IUnknown_Release((IUnknown*)This);
487 }
488
489 static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
490     UINT *puiWidth, UINT *puiHeight)
491 {
492     PngDecoder *This = impl_from_frame(iface);
493     *puiWidth = This->width;
494     *puiHeight = This->height;
495     TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
496     return S_OK;
497 }
498
499 static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
500     WICPixelFormatGUID *pPixelFormat)
501 {
502     PngDecoder *This = impl_from_frame(iface);
503     TRACE("(%p,%p)\n", iface, pPixelFormat);
504
505     memcpy(pPixelFormat, This->format, sizeof(GUID));
506
507     return S_OK;
508 }
509
510 static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
511     double *pDpiX, double *pDpiY)
512 {
513     FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
514     return E_NOTIMPL;
515 }
516
517 static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
518     IWICPalette *pIPalette)
519 {
520     PngDecoder *This = impl_from_frame(iface);
521     png_uint_32 ret;
522     png_colorp png_palette;
523     int num_palette;
524     WICColor palette[256];
525     png_bytep trans;
526     int num_trans;
527     png_color_16p trans_values;
528     int i;
529
530     TRACE("(%p,%p)\n", iface, pIPalette);
531
532     ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette);
533     if (!ret) return WINCODEC_ERR_PALETTEUNAVAILABLE;
534
535     if (num_palette > 256)
536     {
537         ERR("palette has %i colors?!\n", num_palette);
538         return E_FAIL;
539     }
540
541     for (i=0; i<num_palette; i++)
542     {
543         palette[i] = (0xff000000|
544                       png_palette[i].red << 16|
545                       png_palette[i].green << 8|
546                       png_palette[i].blue);
547     }
548
549     ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
550     if (ret)
551     {
552         for (i=0; i<num_trans; i++)
553         {
554             palette[trans[i]] = 0x00000000;
555         }
556     }
557
558     return IWICPalette_InitializeCustom(pIPalette, palette, num_palette);
559 }
560
561 static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
562     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
563 {
564     PngDecoder *This = impl_from_frame(iface);
565     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
566
567     return copy_pixels(This->bpp, This->image_bits,
568         This->width, This->height, This->stride,
569         prc, cbStride, cbBufferSize, pbBuffer);
570 }
571
572 static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
573     IWICMetadataQueryReader **ppIMetadataQueryReader)
574 {
575     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
576     return E_NOTIMPL;
577 }
578
579 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
580     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
581 {
582     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
583     return E_NOTIMPL;
584 }
585
586 static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
587     IWICBitmapSource **ppIThumbnail)
588 {
589     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
590     return E_NOTIMPL;
591 }
592
593 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = {
594     PngDecoder_Frame_QueryInterface,
595     PngDecoder_Frame_AddRef,
596     PngDecoder_Frame_Release,
597     PngDecoder_Frame_GetSize,
598     PngDecoder_Frame_GetPixelFormat,
599     PngDecoder_Frame_GetResolution,
600     PngDecoder_Frame_CopyPalette,
601     PngDecoder_Frame_CopyPixels,
602     PngDecoder_Frame_GetMetadataQueryReader,
603     PngDecoder_Frame_GetColorContexts,
604     PngDecoder_Frame_GetThumbnail
605 };
606
607 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
608 {
609     PngDecoder *This;
610     HRESULT ret;
611
612     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
613
614     *ppv = NULL;
615
616     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
617
618     if (!libpng_handle && !load_libpng())
619     {
620         ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
621         return E_FAIL;
622     }
623
624     This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder));
625     if (!This) return E_OUTOFMEMORY;
626
627     This->lpVtbl = &PngDecoder_Vtbl;
628     This->lpFrameVtbl = &PngDecoder_FrameVtbl;
629     This->ref = 1;
630     This->png_ptr = NULL;
631     This->info_ptr = NULL;
632     This->end_info = NULL;
633     This->initialized = FALSE;
634     This->image_bits = NULL;
635
636     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
637     IUnknown_Release((IUnknown*)This);
638
639     return ret;
640 }
641
642 #else /* !HAVE_PNG_H */
643
644 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
645 {
646     ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
647     return E_FAIL;
648 }
649
650 #endif