wininet: Trace more parameters to HTTP_GetCustomHeaderIndex.
[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_create_write_struct);
49 MAKE_FUNCPTR(png_destroy_read_struct);
50 MAKE_FUNCPTR(png_destroy_write_struct);
51 MAKE_FUNCPTR(png_error);
52 MAKE_FUNCPTR(png_get_bit_depth);
53 MAKE_FUNCPTR(png_get_color_type);
54 MAKE_FUNCPTR(png_get_image_height);
55 MAKE_FUNCPTR(png_get_image_width);
56 MAKE_FUNCPTR(png_get_io_ptr);
57 MAKE_FUNCPTR(png_get_pHYs);
58 MAKE_FUNCPTR(png_get_PLTE);
59 MAKE_FUNCPTR(png_get_tRNS);
60 MAKE_FUNCPTR(png_set_bgr);
61 MAKE_FUNCPTR(png_set_filler);
62 MAKE_FUNCPTR(png_set_gray_1_2_4_to_8);
63 MAKE_FUNCPTR(png_set_gray_to_rgb);
64 MAKE_FUNCPTR(png_set_IHDR);
65 MAKE_FUNCPTR(png_set_pHYs);
66 MAKE_FUNCPTR(png_set_read_fn);
67 MAKE_FUNCPTR(png_set_strip_16);
68 MAKE_FUNCPTR(png_set_tRNS_to_alpha);
69 MAKE_FUNCPTR(png_set_write_fn);
70 MAKE_FUNCPTR(png_read_end);
71 MAKE_FUNCPTR(png_read_image);
72 MAKE_FUNCPTR(png_read_info);
73 MAKE_FUNCPTR(png_write_end);
74 MAKE_FUNCPTR(png_write_info);
75 MAKE_FUNCPTR(png_write_rows);
76 #undef MAKE_FUNCPTR
77
78 static void *load_libpng(void)
79 {
80     if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
81
82 #define LOAD_FUNCPTR(f) \
83     if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
84         libpng_handle = NULL; \
85         return NULL; \
86     }
87         LOAD_FUNCPTR(png_create_read_struct);
88         LOAD_FUNCPTR(png_create_info_struct);
89         LOAD_FUNCPTR(png_create_write_struct);
90         LOAD_FUNCPTR(png_destroy_read_struct);
91         LOAD_FUNCPTR(png_destroy_write_struct);
92         LOAD_FUNCPTR(png_error);
93         LOAD_FUNCPTR(png_get_bit_depth);
94         LOAD_FUNCPTR(png_get_color_type);
95         LOAD_FUNCPTR(png_get_image_height);
96         LOAD_FUNCPTR(png_get_image_width);
97         LOAD_FUNCPTR(png_get_io_ptr);
98         LOAD_FUNCPTR(png_get_pHYs);
99         LOAD_FUNCPTR(png_get_PLTE);
100         LOAD_FUNCPTR(png_get_tRNS);
101         LOAD_FUNCPTR(png_set_bgr);
102         LOAD_FUNCPTR(png_set_filler);
103         LOAD_FUNCPTR(png_set_gray_1_2_4_to_8);
104         LOAD_FUNCPTR(png_set_gray_to_rgb);
105         LOAD_FUNCPTR(png_set_IHDR);
106         LOAD_FUNCPTR(png_set_pHYs);
107         LOAD_FUNCPTR(png_set_read_fn);
108         LOAD_FUNCPTR(png_set_strip_16);
109         LOAD_FUNCPTR(png_set_tRNS_to_alpha);
110         LOAD_FUNCPTR(png_set_write_fn);
111         LOAD_FUNCPTR(png_read_end);
112         LOAD_FUNCPTR(png_read_image);
113         LOAD_FUNCPTR(png_read_info);
114         LOAD_FUNCPTR(png_write_end);
115         LOAD_FUNCPTR(png_write_info);
116         LOAD_FUNCPTR(png_write_rows);
117
118 #undef LOAD_FUNCPTR
119     }
120     return libpng_handle;
121 }
122
123 typedef struct {
124     const IWICBitmapDecoderVtbl *lpVtbl;
125     const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
126     LONG ref;
127     png_structp png_ptr;
128     png_infop info_ptr;
129     png_infop end_info;
130     BOOL initialized;
131     int bpp;
132     int width, height;
133     UINT stride;
134     const WICPixelFormatGUID *format;
135     BYTE *image_bits;
136 } PngDecoder;
137
138 static inline PngDecoder *impl_from_frame(IWICBitmapFrameDecode *iface)
139 {
140     return CONTAINING_RECORD(iface, PngDecoder, lpFrameVtbl);
141 }
142
143 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl;
144
145 static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
146     void **ppv)
147 {
148     PngDecoder *This = (PngDecoder*)iface;
149     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
150
151     if (!ppv) return E_INVALIDARG;
152
153     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
154     {
155         *ppv = This;
156     }
157     else
158     {
159         *ppv = NULL;
160         return E_NOINTERFACE;
161     }
162
163     IUnknown_AddRef((IUnknown*)*ppv);
164     return S_OK;
165 }
166
167 static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface)
168 {
169     PngDecoder *This = (PngDecoder*)iface;
170     ULONG ref = InterlockedIncrement(&This->ref);
171
172     TRACE("(%p) refcount=%u\n", iface, ref);
173
174     return ref;
175 }
176
177 static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
178 {
179     PngDecoder *This = (PngDecoder*)iface;
180     ULONG ref = InterlockedDecrement(&This->ref);
181
182     TRACE("(%p) refcount=%u\n", iface, ref);
183
184     if (ref == 0)
185     {
186         if (This->png_ptr)
187             ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
188         HeapFree(GetProcessHeap(), 0, This->image_bits);
189         HeapFree(GetProcessHeap(), 0, This);
190     }
191
192     return ref;
193 }
194
195 static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
196     DWORD *pdwCapability)
197 {
198     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
199     return E_NOTIMPL;
200 }
201
202 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
203 {
204     IStream *stream = ppng_get_io_ptr(png_ptr);
205     HRESULT hr;
206     ULONG bytesread;
207
208     hr = IStream_Read(stream, data, length, &bytesread);
209     if (FAILED(hr) || bytesread != length)
210     {
211         ppng_error(png_ptr, "failed reading data");
212     }
213 }
214
215 static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
216     WICDecodeOptions cacheOptions)
217 {
218     PngDecoder *This = (PngDecoder*)iface;
219     LARGE_INTEGER seek;
220     HRESULT hr;
221     png_bytep *row_pointers=NULL;
222     UINT image_size;
223     UINT i;
224     int color_type, bit_depth;
225     png_bytep trans;
226     int num_trans;
227     png_uint_32 transparency;
228     png_color_16p trans_values;
229     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
230
231     /* initialize libpng */
232     This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
233     if (!This->png_ptr) return E_FAIL;
234
235     This->info_ptr = ppng_create_info_struct(This->png_ptr);
236     if (!This->info_ptr)
237     {
238         ppng_destroy_read_struct(&This->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
239         This->png_ptr = NULL;
240         return E_FAIL;
241     }
242
243     This->end_info = ppng_create_info_struct(This->png_ptr);
244     if (!This->info_ptr)
245     {
246         ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, (png_infopp)NULL);
247         This->png_ptr = NULL;
248         return E_FAIL;
249     }
250
251     /* set up setjmp/longjmp error handling */
252     if (setjmp(png_jmpbuf(This->png_ptr)))
253     {
254         ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
255         HeapFree(GetProcessHeap(), 0, row_pointers);
256         This->png_ptr = NULL;
257         return E_FAIL;
258     }
259
260     /* seek to the start of the stream */
261     seek.QuadPart = 0;
262     hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
263     if (FAILED(hr)) return hr;
264
265     /* set up custom i/o handling */
266     ppng_set_read_fn(This->png_ptr, pIStream, user_read_data);
267
268     /* read the header */
269     ppng_read_info(This->png_ptr, This->info_ptr);
270
271     /* choose a pixel format */
272     color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
273     bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
274
275     /* check for color-keyed alpha */
276     transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
277
278     if (transparency && color_type != PNG_COLOR_TYPE_PALETTE)
279     {
280         /* expand to RGBA */
281         if (color_type == PNG_COLOR_TYPE_GRAY)
282         {
283             if (bit_depth < 8)
284             {
285                 ppng_set_gray_1_2_4_to_8(This->png_ptr);
286                 bit_depth = 8;
287             }
288             ppng_set_gray_to_rgb(This->png_ptr);
289         }
290         ppng_set_tRNS_to_alpha(This->png_ptr);
291         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
292     }
293
294     switch (color_type)
295     {
296     case PNG_COLOR_TYPE_GRAY:
297         This->bpp = bit_depth;
298         switch (bit_depth)
299         {
300         case 1: This->format = &GUID_WICPixelFormatBlackWhite; break;
301         case 2: This->format = &GUID_WICPixelFormat2bppGray; break;
302         case 4: This->format = &GUID_WICPixelFormat4bppGray; break;
303         case 8: This->format = &GUID_WICPixelFormat8bppGray; break;
304         case 16: This->format = &GUID_WICPixelFormat16bppGray; break;
305         default:
306             ERR("invalid grayscale bit depth: %i\n", bit_depth);
307             return E_FAIL;
308         }
309         break;
310     case PNG_COLOR_TYPE_GRAY_ALPHA:
311         /* WIC does not support grayscale alpha formats so use RGBA */
312         ppng_set_gray_to_rgb(This->png_ptr);
313     case PNG_COLOR_TYPE_RGB_ALPHA:
314         This->bpp = bit_depth * 4;
315         switch (bit_depth)
316         {
317         case 8:
318             ppng_set_bgr(This->png_ptr);
319             This->format = &GUID_WICPixelFormat32bppBGRA;
320             break;
321         case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break;
322         default:
323             ERR("invalid RGBA bit depth: %i\n", bit_depth);
324             return E_FAIL;
325         }
326         break;
327     case PNG_COLOR_TYPE_PALETTE:
328         This->bpp = bit_depth;
329         switch (bit_depth)
330         {
331         case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break;
332         case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break;
333         case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break;
334         case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break;
335         default:
336             ERR("invalid indexed color bit depth: %i\n", bit_depth);
337             return E_FAIL;
338         }
339         break;
340     case PNG_COLOR_TYPE_RGB:
341         This->bpp = bit_depth * 3;
342         switch (bit_depth)
343         {
344         case 8:
345             ppng_set_bgr(This->png_ptr);
346             This->format = &GUID_WICPixelFormat24bppBGR;
347             break;
348         case 16: This->format = &GUID_WICPixelFormat48bppRGB; break;
349         default:
350             ERR("invalid RGB color bit depth: %i\n", bit_depth);
351             return E_FAIL;
352         }
353         break;
354     default:
355         ERR("invalid color type %i\n", color_type);
356         return E_FAIL;
357     }
358
359     /* read the image data */
360     This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
361     This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
362     This->stride = This->width * This->bpp;
363     image_size = This->stride * This->height;
364
365     This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size);
366     if (!This->image_bits) return E_OUTOFMEMORY;
367
368     row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
369     if (!row_pointers) return E_OUTOFMEMORY;
370
371     for (i=0; i<This->height; i++)
372         row_pointers[i] = This->image_bits + i * This->stride;
373
374     ppng_read_image(This->png_ptr, row_pointers);
375
376     HeapFree(GetProcessHeap(), 0, row_pointers);
377     row_pointers = NULL;
378
379     ppng_read_end(This->png_ptr, This->end_info);
380
381     This->initialized = TRUE;
382
383     return S_OK;
384 }
385
386 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
387     GUID *pguidContainerFormat)
388 {
389     memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
390     return S_OK;
391 }
392
393 static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
394     IWICBitmapDecoderInfo **ppIDecoderInfo)
395 {
396     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
397     return E_NOTIMPL;
398 }
399
400 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
401     IWICPalette *pIPalette)
402 {
403     FIXME("(%p,%p): stub\n", iface, pIPalette);
404     return E_NOTIMPL;
405 }
406
407 static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
408     IWICMetadataQueryReader **ppIMetadataQueryReader)
409 {
410     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
411     return E_NOTIMPL;
412 }
413
414 static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface,
415     IWICBitmapSource **ppIBitmapSource)
416 {
417     FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
418     return E_NOTIMPL;
419 }
420
421 static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface,
422     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
423 {
424     FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
425     return E_NOTIMPL;
426 }
427
428 static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface,
429     IWICBitmapSource **ppIThumbnail)
430 {
431     TRACE("(%p,%p)\n", iface, ppIThumbnail);
432     return WINCODEC_ERR_CODECNOTHUMBNAIL;
433 }
434
435 static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface,
436     UINT *pCount)
437 {
438     *pCount = 1;
439     return S_OK;
440 }
441
442 static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface,
443     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
444 {
445     PngDecoder *This = (PngDecoder*)iface;
446     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
447
448     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
449
450     if (index != 0) return E_INVALIDARG;
451
452     IWICBitmapDecoder_AddRef(iface);
453
454     *ppIBitmapFrame = (void*)(&This->lpFrameVtbl);
455
456     return S_OK;
457 }
458
459 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = {
460     PngDecoder_QueryInterface,
461     PngDecoder_AddRef,
462     PngDecoder_Release,
463     PngDecoder_QueryCapability,
464     PngDecoder_Initialize,
465     PngDecoder_GetContainerFormat,
466     PngDecoder_GetDecoderInfo,
467     PngDecoder_CopyPalette,
468     PngDecoder_GetMetadataQueryReader,
469     PngDecoder_GetPreview,
470     PngDecoder_GetColorContexts,
471     PngDecoder_GetThumbnail,
472     PngDecoder_GetFrameCount,
473     PngDecoder_GetFrame
474 };
475
476 static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
477     void **ppv)
478 {
479     if (!ppv) return E_INVALIDARG;
480
481     if (IsEqualIID(&IID_IUnknown, iid) ||
482         IsEqualIID(&IID_IWICBitmapSource, iid) ||
483         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
484     {
485         *ppv = iface;
486     }
487     else
488     {
489         *ppv = NULL;
490         return E_NOINTERFACE;
491     }
492
493     IUnknown_AddRef((IUnknown*)*ppv);
494     return S_OK;
495 }
496
497 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
498 {
499     PngDecoder *This = impl_from_frame(iface);
500     return IUnknown_AddRef((IUnknown*)This);
501 }
502
503 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
504 {
505     PngDecoder *This = impl_from_frame(iface);
506     return IUnknown_Release((IUnknown*)This);
507 }
508
509 static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
510     UINT *puiWidth, UINT *puiHeight)
511 {
512     PngDecoder *This = impl_from_frame(iface);
513     *puiWidth = This->width;
514     *puiHeight = This->height;
515     TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
516     return S_OK;
517 }
518
519 static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
520     WICPixelFormatGUID *pPixelFormat)
521 {
522     PngDecoder *This = impl_from_frame(iface);
523     TRACE("(%p,%p)\n", iface, pPixelFormat);
524
525     memcpy(pPixelFormat, This->format, sizeof(GUID));
526
527     return S_OK;
528 }
529
530 static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
531     double *pDpiX, double *pDpiY)
532 {
533     PngDecoder *This = impl_from_frame(iface);
534     png_uint_32 ret, xres, yres;
535     int unit_type;
536
537     ret = ppng_get_pHYs(This->png_ptr, This->info_ptr, &xres, &yres, &unit_type);
538
539     if (ret && unit_type == PNG_RESOLUTION_METER)
540     {
541         *pDpiX = xres * 0.0254;
542         *pDpiY = yres * 0.0254;
543     }
544     else
545     {
546         WARN("no pHYs block present\n");
547         *pDpiX = *pDpiY = 96.0;
548     }
549
550     TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
551
552     return S_OK;
553 }
554
555 static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
556     IWICPalette *pIPalette)
557 {
558     PngDecoder *This = impl_from_frame(iface);
559     png_uint_32 ret;
560     png_colorp png_palette;
561     int num_palette;
562     WICColor palette[256];
563     png_bytep trans;
564     int num_trans;
565     png_color_16p trans_values;
566     int i;
567
568     TRACE("(%p,%p)\n", iface, pIPalette);
569
570     ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette);
571     if (!ret) return WINCODEC_ERR_PALETTEUNAVAILABLE;
572
573     if (num_palette > 256)
574     {
575         ERR("palette has %i colors?!\n", num_palette);
576         return E_FAIL;
577     }
578
579     for (i=0; i<num_palette; i++)
580     {
581         palette[i] = (0xff000000|
582                       png_palette[i].red << 16|
583                       png_palette[i].green << 8|
584                       png_palette[i].blue);
585     }
586
587     ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
588     if (ret)
589     {
590         for (i=0; i<num_trans; i++)
591         {
592             palette[trans[i]] = 0x00000000;
593         }
594     }
595
596     return IWICPalette_InitializeCustom(pIPalette, palette, num_palette);
597 }
598
599 static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
600     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
601 {
602     PngDecoder *This = impl_from_frame(iface);
603     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
604
605     return copy_pixels(This->bpp, This->image_bits,
606         This->width, This->height, This->stride,
607         prc, cbStride, cbBufferSize, pbBuffer);
608 }
609
610 static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
611     IWICMetadataQueryReader **ppIMetadataQueryReader)
612 {
613     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
614     return E_NOTIMPL;
615 }
616
617 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
618     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
619 {
620     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
625     IWICBitmapSource **ppIThumbnail)
626 {
627     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
628     return E_NOTIMPL;
629 }
630
631 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = {
632     PngDecoder_Frame_QueryInterface,
633     PngDecoder_Frame_AddRef,
634     PngDecoder_Frame_Release,
635     PngDecoder_Frame_GetSize,
636     PngDecoder_Frame_GetPixelFormat,
637     PngDecoder_Frame_GetResolution,
638     PngDecoder_Frame_CopyPalette,
639     PngDecoder_Frame_CopyPixels,
640     PngDecoder_Frame_GetMetadataQueryReader,
641     PngDecoder_Frame_GetColorContexts,
642     PngDecoder_Frame_GetThumbnail
643 };
644
645 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
646 {
647     PngDecoder *This;
648     HRESULT ret;
649
650     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
651
652     *ppv = NULL;
653
654     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
655
656     if (!libpng_handle && !load_libpng())
657     {
658         ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
659         return E_FAIL;
660     }
661
662     This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder));
663     if (!This) return E_OUTOFMEMORY;
664
665     This->lpVtbl = &PngDecoder_Vtbl;
666     This->lpFrameVtbl = &PngDecoder_FrameVtbl;
667     This->ref = 1;
668     This->png_ptr = NULL;
669     This->info_ptr = NULL;
670     This->end_info = NULL;
671     This->initialized = FALSE;
672     This->image_bits = NULL;
673
674     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
675     IUnknown_Release((IUnknown*)This);
676
677     return ret;
678 }
679
680 struct png_pixelformat {
681     const WICPixelFormatGUID *guid;
682     UINT bpp;
683     int bit_depth;
684     int color_type;
685     BOOL remove_filler;
686     BOOL swap_rgb;
687 };
688
689 static const struct png_pixelformat formats[] = {
690     {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
691     {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
692     {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
693     {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
694     {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
695     {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
696     {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
697     {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
698     {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
699     {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
700     {NULL},
701 };
702
703 typedef struct PngEncoder {
704     const IWICBitmapEncoderVtbl *lpVtbl;
705     const IWICBitmapFrameEncodeVtbl *lpFrameVtbl;
706     LONG ref;
707     IStream *stream;
708     png_structp png_ptr;
709     png_infop info_ptr;
710     UINT frame_count;
711     BOOL frame_initialized;
712     const struct png_pixelformat *format;
713     BOOL info_written;
714     UINT width, height;
715     double xres, yres;
716     UINT lines_written;
717     BOOL frame_committed;
718     BOOL committed;
719 } PngEncoder;
720
721 static inline PngEncoder *encoder_from_frame(IWICBitmapFrameEncode *iface)
722 {
723     return CONTAINING_RECORD(iface, PngEncoder, lpFrameVtbl);
724 }
725
726 static HRESULT WINAPI PngFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
727     void **ppv)
728 {
729     PngEncoder *This = encoder_from_frame(iface);
730     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
731
732     if (!ppv) return E_INVALIDARG;
733
734     if (IsEqualIID(&IID_IUnknown, iid) ||
735         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
736     {
737         *ppv = &This->lpFrameVtbl;
738     }
739     else
740     {
741         *ppv = NULL;
742         return E_NOINTERFACE;
743     }
744
745     IUnknown_AddRef((IUnknown*)*ppv);
746     return S_OK;
747 }
748
749 static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
750 {
751     PngEncoder *This = encoder_from_frame(iface);
752     return IUnknown_AddRef((IUnknown*)This);
753 }
754
755 static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface)
756 {
757     PngEncoder *This = encoder_from_frame(iface);
758     return IUnknown_Release((IUnknown*)This);
759 }
760
761 static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
762     IPropertyBag2 *pIEncoderOptions)
763 {
764     PngEncoder *This = encoder_from_frame(iface);
765     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
766
767     if (This->frame_initialized) return WINCODEC_ERR_WRONGSTATE;
768
769     This->frame_initialized = TRUE;
770
771     return S_OK;
772 }
773
774 static HRESULT WINAPI PngFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
775     UINT uiWidth, UINT uiHeight)
776 {
777     PngEncoder *This = encoder_from_frame(iface);
778     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
779
780     if (!This->frame_initialized || This->info_written) return WINCODEC_ERR_WRONGSTATE;
781
782     This->width = uiWidth;
783     This->height = uiHeight;
784
785     return S_OK;
786 }
787
788 static HRESULT WINAPI PngFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
789     double dpiX, double dpiY)
790 {
791     PngEncoder *This = encoder_from_frame(iface);
792     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
793
794     if (!This->frame_initialized || This->info_written) return WINCODEC_ERR_WRONGSTATE;
795
796     This->xres = dpiX;
797     This->yres = dpiY;
798
799     return S_OK;
800 }
801
802 static HRESULT WINAPI PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
803     WICPixelFormatGUID *pPixelFormat)
804 {
805     PngEncoder *This = encoder_from_frame(iface);
806     int i;
807     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
808
809     if (!This->frame_initialized || This->info_written) return WINCODEC_ERR_WRONGSTATE;
810
811     for (i=0; formats[i].guid; i++)
812     {
813         if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
814             break;
815     }
816
817     if (!formats[i].guid) i = 0;
818
819     This->format = &formats[i];
820     memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
821
822     return S_OK;
823 }
824
825 static HRESULT WINAPI PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
826     UINT cCount, IWICColorContext **ppIColorContext)
827 {
828     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
829     return E_NOTIMPL;
830 }
831
832 static HRESULT WINAPI PngFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
833     IWICPalette *pIPalette)
834 {
835     FIXME("(%p,%p): stub\n", iface, pIPalette);
836     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
837 }
838
839 static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
840     IWICBitmapSource *pIThumbnail)
841 {
842     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
843     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
844 }
845
846 static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
847     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
848 {
849     PngEncoder *This = encoder_from_frame(iface);
850     png_byte **row_pointers=NULL;
851     UINT i;
852     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
853
854     if (!This->frame_initialized || !This->width || !This->height || !This->format)
855         return WINCODEC_ERR_WRONGSTATE;
856
857     if (lineCount == 0 || lineCount + This->lines_written > This->height)
858         return E_INVALIDARG;
859
860     /* set up setjmp/longjmp error handling */
861     if (setjmp(png_jmpbuf(This->png_ptr)))
862     {
863         HeapFree(GetProcessHeap(), 0, row_pointers);
864         return E_FAIL;
865     }
866
867     if (!This->info_written)
868     {
869         ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height,
870             This->format->bit_depth, This->format->color_type, PNG_INTERLACE_NONE,
871             PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
872
873         if (This->xres != 0.0 && This->yres != 0.0)
874         {
875             ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254,
876                 (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER);
877         }
878
879         ppng_write_info(This->png_ptr, This->info_ptr);
880
881         if (This->format->remove_filler)
882             ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);
883
884         if (This->format->swap_rgb)
885             ppng_set_bgr(This->png_ptr);
886
887         This->info_written = TRUE;
888     }
889
890     row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*));
891     if (!row_pointers)
892         return E_OUTOFMEMORY;
893
894     for (i=0; i<lineCount; i++)
895         row_pointers[i] = pbPixels + cbStride * i;
896
897     ppng_write_rows(This->png_ptr, row_pointers, lineCount);
898     This->lines_written += lineCount;
899
900     HeapFree(GetProcessHeap(), 0, row_pointers);
901
902     return S_OK;
903 }
904
905 static HRESULT WINAPI PngFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
906     IWICBitmapSource *pIBitmapSource, WICRect *prc)
907 {
908     PngEncoder *This = encoder_from_frame(iface);
909     HRESULT hr;
910     WICRect rc;
911     WICPixelFormatGUID guid;
912     UINT stride;
913     BYTE *pixeldata;
914     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
915
916     if (!This->frame_initialized || !This->width || !This->height)
917         return WINCODEC_ERR_WRONGSTATE;
918
919     if (!This->format)
920     {
921         hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
922         if (FAILED(hr)) return hr;
923         hr = IWICBitmapFrameEncode_SetPixelFormat(iface, &guid);
924         if (FAILED(hr)) return hr;
925     }
926
927     hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
928     if (FAILED(hr)) return hr;
929     if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
930     {
931         /* FIXME: should use WICConvertBitmapSource to convert */
932         ERR("format %s unsupported\n", debugstr_guid(&guid));
933         return E_FAIL;
934     }
935
936     if (This->xres == 0.0 || This->yres == 0.0)
937     {
938         double xres, yres;
939         hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
940         if (FAILED(hr)) return hr;
941         hr = IWICBitmapFrameEncode_SetResolution(iface, xres, yres);
942         if (FAILED(hr)) return hr;
943     }
944
945     if (!prc)
946     {
947         UINT width, height;
948         hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
949         if (FAILED(hr)) return hr;
950         rc.X = 0;
951         rc.Y = 0;
952         rc.Width = width;
953         rc.Height = height;
954         prc = &rc;
955     }
956
957     if (prc->Width != This->width) return E_INVALIDARG;
958
959     stride = (This->format->bpp * This->width + 7)/8;
960
961     pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
962     if (!pixeldata) return E_OUTOFMEMORY;
963
964     hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
965         stride*prc->Height, pixeldata);
966
967     if (SUCCEEDED(hr))
968     {
969         hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
970             stride*prc->Height, pixeldata);
971     }
972
973     HeapFree(GetProcessHeap(), 0, pixeldata);
974
975     return hr;
976 }
977
978 static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
979 {
980     PngEncoder *This = encoder_from_frame(iface);
981     TRACE("(%p)\n", iface);
982
983     if (!This->info_written || This->lines_written != This->height || This->frame_committed)
984         return WINCODEC_ERR_WRONGSTATE;
985
986     /* set up setjmp/longjmp error handling */
987     if (setjmp(png_jmpbuf(This->png_ptr)))
988     {
989         return E_FAIL;
990     }
991
992     ppng_write_end(This->png_ptr, This->info_ptr);
993
994     This->frame_committed = TRUE;
995
996     return S_OK;
997 }
998
999 static HRESULT WINAPI PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1000     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1001 {
1002     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1003     return E_NOTIMPL;
1004 }
1005
1006 static const IWICBitmapFrameEncodeVtbl PngEncoder_FrameVtbl = {
1007     PngFrameEncode_QueryInterface,
1008     PngFrameEncode_AddRef,
1009     PngFrameEncode_Release,
1010     PngFrameEncode_Initialize,
1011     PngFrameEncode_SetSize,
1012     PngFrameEncode_SetResolution,
1013     PngFrameEncode_SetPixelFormat,
1014     PngFrameEncode_SetColorContexts,
1015     PngFrameEncode_SetPalette,
1016     PngFrameEncode_SetThumbnail,
1017     PngFrameEncode_WritePixels,
1018     PngFrameEncode_WriteSource,
1019     PngFrameEncode_Commit,
1020     PngFrameEncode_GetMetadataQueryWriter
1021 };
1022
1023 static HRESULT WINAPI PngEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1024     void **ppv)
1025 {
1026     PngEncoder *This = (PngEncoder*)iface;
1027     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1028
1029     if (!ppv) return E_INVALIDARG;
1030
1031     if (IsEqualIID(&IID_IUnknown, iid) ||
1032         IsEqualIID(&IID_IWICBitmapEncoder, iid))
1033     {
1034         *ppv = This;
1035     }
1036     else
1037     {
1038         *ppv = NULL;
1039         return E_NOINTERFACE;
1040     }
1041
1042     IUnknown_AddRef((IUnknown*)*ppv);
1043     return S_OK;
1044 }
1045
1046 static ULONG WINAPI PngEncoder_AddRef(IWICBitmapEncoder *iface)
1047 {
1048     PngEncoder *This = (PngEncoder*)iface;
1049     ULONG ref = InterlockedIncrement(&This->ref);
1050
1051     TRACE("(%p) refcount=%u\n", iface, ref);
1052
1053     return ref;
1054 }
1055
1056 static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface)
1057 {
1058     PngEncoder *This = (PngEncoder*)iface;
1059     ULONG ref = InterlockedDecrement(&This->ref);
1060
1061     TRACE("(%p) refcount=%u\n", iface, ref);
1062
1063     if (ref == 0)
1064     {
1065         if (This->png_ptr)
1066             ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
1067         if (This->stream)
1068             IStream_Release(This->stream);
1069         HeapFree(GetProcessHeap(), 0, This);
1070     }
1071
1072     return ref;
1073 }
1074
1075 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
1076 {
1077     PngEncoder *This = ppng_get_io_ptr(png_ptr);
1078     HRESULT hr;
1079     ULONG byteswritten;
1080
1081     hr = IStream_Write(This->stream, data, length, &byteswritten);
1082     if (FAILED(hr) || byteswritten != length)
1083     {
1084         ppng_error(png_ptr, "failed writing data");
1085     }
1086 }
1087
1088 static void user_flush(png_structp png_ptr)
1089 {
1090 }
1091
1092 static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface,
1093     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1094 {
1095     PngEncoder *This = (PngEncoder*)iface;
1096
1097     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1098
1099     if (This->png_ptr)
1100         return WINCODEC_ERR_WRONGSTATE;
1101
1102     /* initialize libpng */
1103     This->png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1104     if (!This->png_ptr)
1105         return E_FAIL;
1106
1107     This->info_ptr = ppng_create_info_struct(This->png_ptr);
1108     if (!This->info_ptr)
1109     {
1110         ppng_destroy_write_struct(&This->png_ptr, (png_infopp)NULL);
1111         This->png_ptr = NULL;
1112         return E_FAIL;
1113     }
1114
1115     IStream_AddRef(pIStream);
1116     This->stream = pIStream;
1117
1118     /* set up setjmp/longjmp error handling */
1119     if (setjmp(png_jmpbuf(This->png_ptr)))
1120     {
1121         ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
1122         This->png_ptr = NULL;
1123         IStream_Release(This->stream);
1124         This->stream = NULL;
1125         return E_FAIL;
1126     }
1127
1128     /* set up custom i/o handling */
1129     ppng_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
1130
1131     return S_OK;
1132 }
1133
1134 static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
1135     GUID *pguidContainerFormat)
1136 {
1137     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
1138     return E_NOTIMPL;
1139 }
1140
1141 static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
1142     IWICBitmapEncoderInfo **ppIEncoderInfo)
1143 {
1144     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
1145     return E_NOTIMPL;
1146 }
1147
1148 static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1149     UINT cCount, IWICColorContext **ppIColorContext)
1150 {
1151     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1152     return E_NOTIMPL;
1153 }
1154
1155 static HRESULT WINAPI PngEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
1156 {
1157     TRACE("(%p,%p)\n", iface, pIPalette);
1158     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1159 }
1160
1161 static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1162 {
1163     TRACE("(%p,%p)\n", iface, pIThumbnail);
1164     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1165 }
1166
1167 static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1168 {
1169     TRACE("(%p,%p)\n", iface, pIPreview);
1170     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1171 }
1172
1173 static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1174     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1175 {
1176     PngEncoder *This = (PngEncoder*)iface;
1177     HRESULT hr;
1178     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
1179
1180     if (This->frame_count != 0)
1181         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1182
1183     if (!This->stream)
1184         return WINCODEC_ERR_NOTINITIALIZED;
1185
1186     hr = CreatePropertyBag2(ppIEncoderOptions);
1187     if (FAILED(hr)) return hr;
1188
1189     This->frame_count = 1;
1190
1191     IWICBitmapEncoder_AddRef(iface);
1192     *ppIFrameEncode = (IWICBitmapFrameEncode*)&This->lpFrameVtbl;
1193
1194     return S_OK;
1195 }
1196
1197 static HRESULT WINAPI PngEncoder_Commit(IWICBitmapEncoder *iface)
1198 {
1199     PngEncoder *This = (PngEncoder*)iface;
1200     TRACE("(%p)\n", iface);
1201
1202     if (!This->frame_committed || This->committed)
1203         return WINCODEC_ERR_WRONGSTATE;
1204
1205     This->committed = TRUE;
1206
1207     return S_OK;
1208 }
1209
1210 static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1211     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1212 {
1213     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1214     return E_NOTIMPL;
1215 }
1216
1217 static const IWICBitmapEncoderVtbl PngEncoder_Vtbl = {
1218     PngEncoder_QueryInterface,
1219     PngEncoder_AddRef,
1220     PngEncoder_Release,
1221     PngEncoder_Initialize,
1222     PngEncoder_GetContainerFormat,
1223     PngEncoder_GetEncoderInfo,
1224     PngEncoder_SetColorContexts,
1225     PngEncoder_SetPalette,
1226     PngEncoder_SetThumbnail,
1227     PngEncoder_SetPreview,
1228     PngEncoder_CreateNewFrame,
1229     PngEncoder_Commit,
1230     PngEncoder_GetMetadataQueryWriter
1231 };
1232
1233 HRESULT PngEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1234 {
1235     PngEncoder *This;
1236     HRESULT ret;
1237
1238     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1239
1240     *ppv = NULL;
1241
1242     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1243
1244     if (!libpng_handle && !load_libpng())
1245     {
1246         ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG);
1247         return E_FAIL;
1248     }
1249
1250     This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder));
1251     if (!This) return E_OUTOFMEMORY;
1252
1253     This->lpVtbl = &PngEncoder_Vtbl;
1254     This->lpFrameVtbl = &PngEncoder_FrameVtbl;
1255     This->ref = 1;
1256     This->png_ptr = NULL;
1257     This->info_ptr = NULL;
1258     This->stream = NULL;
1259     This->frame_count = 0;
1260     This->frame_initialized = FALSE;
1261     This->format = NULL;
1262     This->info_written = FALSE;
1263     This->width = 0;
1264     This->height = 0;
1265     This->xres = 0.0;
1266     This->yres = 0.0;
1267     This->lines_written = 0;
1268     This->frame_committed = FALSE;
1269     This->committed = FALSE;
1270
1271     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
1272     IUnknown_Release((IUnknown*)This);
1273
1274     return ret;
1275 }
1276
1277 #else /* !HAVE_PNG_H */
1278
1279 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1280 {
1281     ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1282     return E_FAIL;
1283 }
1284
1285 HRESULT PngEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1286 {
1287     ERR("Trying to save PNG picture, but PNG supported not compiled in.\n");
1288     return E_FAIL;
1289 }
1290
1291 #endif