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