ReactOS 0.4.15-dev-8241-g63935f8
pngformat.c
Go to the documentation of this file.
1/*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2016 Dmitry Timoshkov
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20#include "config.h"
21#include "wine/port.h"
22
23#include <stdarg.h>
24
25#ifdef HAVE_PNG_H
26#include <png.h>
27#endif
28
29#define NONAMELESSUNION
30#define COBJMACROS
31
32#include "windef.h"
33#include "winbase.h"
34#include "objbase.h"
35
36#include "wincodecs_private.h"
37
38#include "wine/debug.h"
39#include "wine/library.h"
40
42
44{
45 return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
46}
47
49{
50 BYTE header[8];
51 HRESULT hr;
52 ULONG bytesread;
53
54 hr = IStream_Read(stream, header, 8, &bytesread);
55 if (FAILED(hr) || bytesread < 8)
56 {
57 if (SUCCEEDED(hr))
58 hr = E_FAIL;
59 return hr;
60 }
61
62 *data_size = read_ulong_be(&header[0]);
63
64 memcpy(type, &header[4], 4);
65
66 if (data)
67 {
68 *data = HeapAlloc(GetProcessHeap(), 0, *data_size);
69 if (!*data)
70 return E_OUTOFMEMORY;
71
72 hr = IStream_Read(stream, *data, *data_size, &bytesread);
73
74 if (FAILED(hr) || bytesread < *data_size)
75 {
76 if (SUCCEEDED(hr))
77 hr = E_FAIL;
79 *data = NULL;
80 return hr;
81 }
82
83 /* Windows ignores CRC of the chunk */
84 }
85
86 return S_OK;
87}
88
89static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor,
90 DWORD persist_options, MetadataItem **items, DWORD *item_count)
91{
92 HRESULT hr;
93 BYTE type[4];
94 BYTE *data;
95 ULONG data_size;
96 ULONG name_len, value_len;
97 BYTE *name_end_ptr;
100
101 hr = read_png_chunk(stream, type, &data, &data_size);
102 if (FAILED(hr)) return hr;
103
104 name_end_ptr = memchr(data, 0, data_size);
105
106 name_len = name_end_ptr - data;
107
108 if (!name_end_ptr || name_len > 79)
109 {
111 return E_FAIL;
112 }
113
114 value_len = data_size - name_len - 1;
115
117 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
118 value = HeapAlloc(GetProcessHeap(), 0, value_len + 1);
119 if (!result || !name || !value)
120 {
125 return E_OUTOFMEMORY;
126 }
127
128 PropVariantInit(&result[0].schema);
129 PropVariantInit(&result[0].id);
130 PropVariantInit(&result[0].value);
131
132 memcpy(name, data, name_len + 1);
133 memcpy(value, name_end_ptr + 1, value_len);
134 value[value_len] = 0;
135
136 result[0].id.vt = VT_LPSTR;
137 result[0].id.u.pszVal = name;
138 result[0].value.vt = VT_LPSTR;
139 result[0].value.u.pszVal = value;
140
141 *items = result;
142 *item_count = 1;
143
145
146 return S_OK;
147}
148
150 0,
151 &CLSID_WICPngTextMetadataReader,
153};
154
156{
158}
159
160static HRESULT LoadGamaMetadata(IStream *stream, const GUID *preferred_vendor,
161 DWORD persist_options, MetadataItem **items, DWORD *item_count)
162{
163 HRESULT hr;
164 BYTE type[4];
165 BYTE *data;
166 ULONG data_size;
167 ULONG gamma;
168 static const WCHAR ImageGamma[] = {'I','m','a','g','e','G','a','m','m','a',0};
169 LPWSTR name;
171
172 hr = read_png_chunk(stream, type, &data, &data_size);
173 if (FAILED(hr)) return hr;
174
175 if (data_size < 4)
176 {
178 return E_FAIL;
179 }
180
181 gamma = read_ulong_be(data);
182
184
186 name = HeapAlloc(GetProcessHeap(), 0, sizeof(ImageGamma));
187 if (!result || !name)
188 {
191 return E_OUTOFMEMORY;
192 }
193
194 PropVariantInit(&result[0].schema);
195 PropVariantInit(&result[0].id);
196 PropVariantInit(&result[0].value);
197
198 memcpy(name, ImageGamma, sizeof(ImageGamma));
199
200 result[0].id.vt = VT_LPWSTR;
201 result[0].id.u.pwszVal = name;
202 result[0].value.vt = VT_UI4;
203 result[0].value.u.ulVal = gamma;
204
205 *items = result;
206 *item_count = 1;
207
208 return S_OK;
209}
210
212 0,
213 &CLSID_WICPngGamaMetadataReader,
215};
216
218{
220}
221
222static HRESULT LoadChrmMetadata(IStream *stream, const GUID *preferred_vendor,
223 DWORD persist_options, MetadataItem **items, DWORD *item_count)
224{
225 HRESULT hr;
226 BYTE type[4];
227 BYTE *data;
228 ULONG data_size;
229 static const WCHAR names[8][12] = {
230 {'W','h','i','t','e','P','o','i','n','t','X',0},
231 {'W','h','i','t','e','P','o','i','n','t','Y',0},
232 {'R','e','d','X',0},
233 {'R','e','d','Y',0},
234 {'G','r','e','e','n','X',0},
235 {'G','r','e','e','n','Y',0},
236 {'B','l','u','e','X',0},
237 {'B','l','u','e','Y',0},
238 };
239 LPWSTR dyn_names[8] = {0};
241 int i;
242
243 hr = read_png_chunk(stream, type, &data, &data_size);
244 if (FAILED(hr)) return hr;
245
246 if (data_size < 32)
247 {
249 return E_FAIL;
250 }
251
253 for (i=0; i<8; i++)
254 {
255 dyn_names[i] = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(lstrlenW(names[i])+1));
256 if (!dyn_names[i]) break;
257 }
258 if (!result || i < 8)
259 {
261 for (i=0; i<8; i++)
262 HeapFree(GetProcessHeap(), 0, dyn_names[i]);
264 return E_OUTOFMEMORY;
265 }
266
267 for (i=0; i<8; i++)
268 {
269 PropVariantInit(&result[i].schema);
270
271 PropVariantInit(&result[i].id);
272 result[i].id.vt = VT_LPWSTR;
273 result[i].id.u.pwszVal = dyn_names[i];
274 lstrcpyW(dyn_names[i], names[i]);
275
276 PropVariantInit(&result[i].value);
277 result[i].value.vt = VT_UI4;
278 result[i].value.u.ulVal = read_ulong_be(&data[i*4]);
279 }
280
281 *items = result;
282 *item_count = 8;
283
285
286 return S_OK;
287}
288
290 0,
291 &CLSID_WICPngChrmMetadataReader,
293};
294
296{
298}
299
300#ifdef SONAME_LIBPNG
301
302static void *libpng_handle;
303#define MAKE_FUNCPTR(f) static typeof(f) * p##f
304MAKE_FUNCPTR(png_create_read_struct);
305MAKE_FUNCPTR(png_create_info_struct);
306MAKE_FUNCPTR(png_create_write_struct);
307MAKE_FUNCPTR(png_destroy_read_struct);
308MAKE_FUNCPTR(png_destroy_write_struct);
309MAKE_FUNCPTR(png_error);
310MAKE_FUNCPTR(png_get_bit_depth);
311MAKE_FUNCPTR(png_get_color_type);
312MAKE_FUNCPTR(png_get_error_ptr);
313MAKE_FUNCPTR(png_get_iCCP);
314MAKE_FUNCPTR(png_get_image_height);
315MAKE_FUNCPTR(png_get_image_width);
317MAKE_FUNCPTR(png_get_pHYs);
318MAKE_FUNCPTR(png_get_PLTE);
319MAKE_FUNCPTR(png_get_tRNS);
320MAKE_FUNCPTR(png_set_bgr);
321MAKE_FUNCPTR(png_set_crc_action);
322MAKE_FUNCPTR(png_set_error_fn);
323MAKE_FUNCPTR(png_set_filler);
324MAKE_FUNCPTR(png_set_filter);
325MAKE_FUNCPTR(png_set_gray_to_rgb);
326MAKE_FUNCPTR(png_set_interlace_handling);
327MAKE_FUNCPTR(png_set_IHDR);
328MAKE_FUNCPTR(png_set_pHYs);
329MAKE_FUNCPTR(png_set_PLTE);
330MAKE_FUNCPTR(png_set_read_fn);
331MAKE_FUNCPTR(png_set_strip_16);
332MAKE_FUNCPTR(png_set_tRNS);
333MAKE_FUNCPTR(png_set_tRNS_to_alpha);
334MAKE_FUNCPTR(png_set_write_fn);
335MAKE_FUNCPTR(png_set_swap);
336MAKE_FUNCPTR(png_read_end);
337MAKE_FUNCPTR(png_read_image);
338MAKE_FUNCPTR(png_read_info);
339MAKE_FUNCPTR(png_write_end);
340MAKE_FUNCPTR(png_write_info);
341MAKE_FUNCPTR(png_write_rows);
342#undef MAKE_FUNCPTR
343
344static CRITICAL_SECTION init_png_cs;
345static CRITICAL_SECTION_DEBUG init_png_cs_debug =
346{
347 0, 0, &init_png_cs,
348 { &init_png_cs_debug.ProcessLocksList,
349 &init_png_cs_debug.ProcessLocksList },
350 0, 0, { (DWORD_PTR)(__FILE__ ": init_png_cs") }
351};
352static CRITICAL_SECTION init_png_cs = { &init_png_cs_debug, -1, 0, 0, 0, 0 };
353
354static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
355static const WCHAR wszPngFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0};
356
357static void *load_libpng(void)
358{
359 void *result;
360
361 EnterCriticalSection(&init_png_cs);
362
363 if(!libpng_handle && (libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
364
365#define LOAD_FUNCPTR(f) \
366 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
367 libpng_handle = NULL; \
368 LeaveCriticalSection(&init_png_cs); \
369 return NULL; \
370 }
371 LOAD_FUNCPTR(png_create_read_struct);
372 LOAD_FUNCPTR(png_create_info_struct);
373 LOAD_FUNCPTR(png_create_write_struct);
374 LOAD_FUNCPTR(png_destroy_read_struct);
375 LOAD_FUNCPTR(png_destroy_write_struct);
376 LOAD_FUNCPTR(png_error);
377 LOAD_FUNCPTR(png_get_bit_depth);
378 LOAD_FUNCPTR(png_get_color_type);
379 LOAD_FUNCPTR(png_get_error_ptr);
380 LOAD_FUNCPTR(png_get_iCCP);
381 LOAD_FUNCPTR(png_get_image_height);
382 LOAD_FUNCPTR(png_get_image_width);
384 LOAD_FUNCPTR(png_get_pHYs);
385 LOAD_FUNCPTR(png_get_PLTE);
386 LOAD_FUNCPTR(png_get_tRNS);
387 LOAD_FUNCPTR(png_set_bgr);
388 LOAD_FUNCPTR(png_set_crc_action);
389 LOAD_FUNCPTR(png_set_error_fn);
390 LOAD_FUNCPTR(png_set_filler);
391 LOAD_FUNCPTR(png_set_filter);
392 LOAD_FUNCPTR(png_set_gray_to_rgb);
393 LOAD_FUNCPTR(png_set_interlace_handling);
394 LOAD_FUNCPTR(png_set_IHDR);
395 LOAD_FUNCPTR(png_set_pHYs);
396 LOAD_FUNCPTR(png_set_PLTE);
397 LOAD_FUNCPTR(png_set_read_fn);
398 LOAD_FUNCPTR(png_set_strip_16);
399 LOAD_FUNCPTR(png_set_tRNS);
400 LOAD_FUNCPTR(png_set_tRNS_to_alpha);
401 LOAD_FUNCPTR(png_set_write_fn);
402 LOAD_FUNCPTR(png_set_swap);
403 LOAD_FUNCPTR(png_read_end);
404 LOAD_FUNCPTR(png_read_image);
405 LOAD_FUNCPTR(png_read_info);
406 LOAD_FUNCPTR(png_write_end);
407 LOAD_FUNCPTR(png_write_info);
408 LOAD_FUNCPTR(png_write_rows);
409
410#undef LOAD_FUNCPTR
411 }
412
413 result = libpng_handle;
414
415 LeaveCriticalSection(&init_png_cs);
416
417 return result;
418}
419
420static void user_error_fn(png_structp png_ptr, png_const_charp error_message)
421{
422 jmp_buf *pjmpbuf;
423
424 /* This uses setjmp/longjmp just like the default. We can't use the
425 * default because there's no way to access the jmp buffer in the png_struct
426 * that works in 1.2 and 1.4 and allows us to dynamically load libpng. */
427 WARN("PNG error: %s\n", debugstr_a(error_message));
428 pjmpbuf = ppng_get_error_ptr(png_ptr);
429 longjmp(*pjmpbuf, 1);
430}
431
432static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message)
433{
434 WARN("PNG warning: %s\n", debugstr_a(warning_message));
435}
436
437typedef struct {
438 ULARGE_INTEGER ofs, len;
440} metadata_block_info;
441
442typedef struct {
443 IWICBitmapDecoder IWICBitmapDecoder_iface;
444 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
445 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
446 LONG ref;
450 png_infop end_info;
452 int bpp;
453 int width, height;
454 UINT stride;
456 BYTE *image_bits;
457 CRITICAL_SECTION lock; /* must be held when png structures are accessed or initialized is set */
458 ULONG metadata_count;
459 metadata_block_info* metadata_blocks;
460} PngDecoder;
461
462static inline PngDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
463{
464 return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapDecoder_iface);
465}
466
467static inline PngDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
468{
469 return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapFrameDecode_iface);
470}
471
472static inline PngDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
473{
474 return CONTAINING_RECORD(iface, PngDecoder, IWICMetadataBlockReader_iface);
475}
476
477static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl;
478
479static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
480 void **ppv)
481{
482 PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
483 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
484
485 if (!ppv) return E_INVALIDARG;
486
487 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
488 {
489 *ppv = &This->IWICBitmapDecoder_iface;
490 }
491 else
492 {
493 *ppv = NULL;
494 return E_NOINTERFACE;
495 }
496
497 IUnknown_AddRef((IUnknown*)*ppv);
498 return S_OK;
499}
500
501static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface)
502{
503 PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
505
506 TRACE("(%p) refcount=%u\n", iface, ref);
507
508 return ref;
509}
510
511static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
512{
513 PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
515 ULONG i;
516
517 TRACE("(%p) refcount=%u\n", iface, ref);
518
519 if (ref == 0)
520 {
521 if (This->stream)
522 IStream_Release(This->stream);
523 if (This->png_ptr)
524 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
525 This->lock.DebugInfo->Spare[0] = 0;
527 HeapFree(GetProcessHeap(), 0, This->image_bits);
528 for (i=0; i<This->metadata_count; i++)
529 {
530 if (This->metadata_blocks[i].reader)
531 IWICMetadataReader_Release(This->metadata_blocks[i].reader);
532 }
533 HeapFree(GetProcessHeap(), 0, This->metadata_blocks);
535 }
536
537 return ref;
538}
539
540static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
541 DWORD *capability)
542{
543 HRESULT hr;
544
545 TRACE("(%p,%p,%p)\n", iface, stream, capability);
546
547 if (!stream || !capability) return E_INVALIDARG;
548
549 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
550 if (hr != S_OK) return hr;
551
554 /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
555 return S_OK;
556}
557
558static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
559{
560 IStream *stream = ppng_get_io_ptr(png_ptr);
561 HRESULT hr;
562 ULONG bytesread;
563
564 hr = IStream_Read(stream, data, length, &bytesread);
565 if (FAILED(hr) || bytesread != length)
566 {
567 ppng_error(png_ptr, "failed reading data");
568 }
569}
570
571static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
572 WICDecodeOptions cacheOptions)
573{
574 PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
577 png_bytep *row_pointers=NULL;
579 UINT i;
580 int color_type, bit_depth;
581 png_bytep trans;
582 int num_trans;
583 png_uint_32 transparency;
584 png_color_16p trans_values;
586 BYTE chunk_type[4];
587 ULONG chunk_size;
588 ULARGE_INTEGER chunk_start;
589 ULONG metadata_blocks_size = 0;
590
591 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
592
594
595 /* initialize libpng */
596 This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
597 if (!This->png_ptr)
598 {
599 hr = E_FAIL;
600 goto end;
601 }
602
603 This->info_ptr = ppng_create_info_struct(This->png_ptr);
604 if (!This->info_ptr)
605 {
606 ppng_destroy_read_struct(&This->png_ptr, NULL, NULL);
607 This->png_ptr = NULL;
608 hr = E_FAIL;
609 goto end;
610 }
611
612 This->end_info = ppng_create_info_struct(This->png_ptr);
613 if (!This->end_info)
614 {
615 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL);
616 This->png_ptr = NULL;
617 hr = E_FAIL;
618 goto end;
619 }
620
621 /* set up setjmp/longjmp error handling */
622 if (setjmp(jmpbuf))
623 {
624 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
625 This->png_ptr = NULL;
627 goto end;
628 }
629 ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
630 ppng_set_crc_action(This->png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
631
632 /* seek to the start of the stream */
633 seek.QuadPart = 0;
634 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
635 if (FAILED(hr)) goto end;
636
637 /* set up custom i/o handling */
638 ppng_set_read_fn(This->png_ptr, pIStream, user_read_data);
639
640 /* read the header */
641 ppng_read_info(This->png_ptr, This->info_ptr);
642
643 /* choose a pixel format */
644 color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
645 bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
646
647 /* PNGs with bit-depth greater than 8 are network byte order. Windows does not expect this. */
648 if (bit_depth > 8)
649 ppng_set_swap(This->png_ptr);
650
651 /* check for color-keyed alpha */
652 transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
653
654 if (transparency && (color_type == PNG_COLOR_TYPE_RGB ||
655 (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)))
656 {
657 /* expand to RGBA */
658 if (color_type == PNG_COLOR_TYPE_GRAY)
659 ppng_set_gray_to_rgb(This->png_ptr);
660 ppng_set_tRNS_to_alpha(This->png_ptr);
661 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
662 }
663
664 switch (color_type)
665 {
667 /* WIC does not support grayscale alpha formats so use RGBA */
668 ppng_set_gray_to_rgb(This->png_ptr);
669 /* fall through */
671 This->bpp = bit_depth * 4;
672 switch (bit_depth)
673 {
674 case 8:
675 ppng_set_bgr(This->png_ptr);
676 This->format = &GUID_WICPixelFormat32bppBGRA;
677 break;
678 case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break;
679 default:
680 ERR("invalid RGBA bit depth: %i\n", bit_depth);
681 hr = E_FAIL;
682 goto end;
683 }
684 break;
686 This->bpp = bit_depth;
687 if (!transparency)
688 {
689 switch (bit_depth)
690 {
691 case 1: This->format = &GUID_WICPixelFormatBlackWhite; break;
692 case 2: This->format = &GUID_WICPixelFormat2bppGray; break;
693 case 4: This->format = &GUID_WICPixelFormat4bppGray; break;
694 case 8: This->format = &GUID_WICPixelFormat8bppGray; break;
695 case 16: This->format = &GUID_WICPixelFormat16bppGray; break;
696 default:
697 ERR("invalid grayscale bit depth: %i\n", bit_depth);
698 hr = E_FAIL;
699 goto end;
700 }
701 break;
702 }
703 /* else fall through */
705 This->bpp = bit_depth;
706 switch (bit_depth)
707 {
708 case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break;
709 case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break;
710 case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break;
711 case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break;
712 default:
713 ERR("invalid indexed color bit depth: %i\n", bit_depth);
714 hr = E_FAIL;
715 goto end;
716 }
717 break;
719 This->bpp = bit_depth * 3;
720 switch (bit_depth)
721 {
722 case 8:
723 ppng_set_bgr(This->png_ptr);
724 This->format = &GUID_WICPixelFormat24bppBGR;
725 break;
726 case 16: This->format = &GUID_WICPixelFormat48bppRGB; break;
727 default:
728 ERR("invalid RGB color bit depth: %i\n", bit_depth);
729 hr = E_FAIL;
730 goto end;
731 }
732 break;
733 default:
734 ERR("invalid color type %i\n", color_type);
735 hr = E_FAIL;
736 goto end;
737 }
738
739 /* read the image data */
740 This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
741 This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
742 This->stride = (This->width * This->bpp + 7) / 8;
743 image_size = This->stride * This->height;
744
745 This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size);
746 if (!This->image_bits)
747 {
749 goto end;
750 }
751
752 row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
753 if (!row_pointers)
754 {
756 goto end;
757 }
758
759 for (i=0; i<This->height; i++)
760 row_pointers[i] = This->image_bits + i * This->stride;
761
762 ppng_read_image(This->png_ptr, row_pointers);
763
764 HeapFree(GetProcessHeap(), 0, row_pointers);
765 row_pointers = NULL;
766
767 ppng_read_end(This->png_ptr, This->end_info);
768
769 /* Find the metadata chunks in the file. */
770 seek.QuadPart = 8;
771
772 do
773 {
774 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, &chunk_start);
775 if (FAILED(hr)) goto end;
776
777 hr = read_png_chunk(pIStream, chunk_type, NULL, &chunk_size);
778 if (FAILED(hr)) goto end;
779
780 if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
781 memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
782 {
783 /* This chunk is considered metadata. */
784 if (This->metadata_count == metadata_blocks_size)
785 {
786 metadata_block_info* new_metadata_blocks;
787 ULONG new_metadata_blocks_size;
788
789 new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
790 new_metadata_blocks = HeapAlloc(GetProcessHeap(), 0,
791 new_metadata_blocks_size * sizeof(*new_metadata_blocks));
792
793 if (!new_metadata_blocks)
794 {
796 goto end;
797 }
798
799 memcpy(new_metadata_blocks, This->metadata_blocks,
800 This->metadata_count * sizeof(*new_metadata_blocks));
801
802 HeapFree(GetProcessHeap(), 0, This->metadata_blocks);
803 This->metadata_blocks = new_metadata_blocks;
804 metadata_blocks_size = new_metadata_blocks_size;
805 }
806
807 This->metadata_blocks[This->metadata_count].ofs = chunk_start;
808 This->metadata_blocks[This->metadata_count].len.QuadPart = chunk_size + 12;
809 This->metadata_blocks[This->metadata_count].reader = NULL;
810 This->metadata_count++;
811 }
812
813 seek.QuadPart = chunk_start.QuadPart + chunk_size + 12; /* skip data and CRC */
814 } while (memcmp(chunk_type, "IEND", 4));
815
816 This->stream = pIStream;
817 IStream_AddRef(This->stream);
818
819 This->initialized = TRUE;
820
821end:
823
824 HeapFree(GetProcessHeap(), 0, row_pointers);
825
826 return hr;
827}
828
829static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
830 GUID *pguidContainerFormat)
831{
832 memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
833 return S_OK;
834}
835
836static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
837 IWICBitmapDecoderInfo **ppIDecoderInfo)
838{
839 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
840
841 return get_decoder_info(&CLSID_WICPngDecoder, ppIDecoderInfo);
842}
843
844static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
846{
847 TRACE("(%p,%p)\n", iface, palette);
849}
850
851static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
853{
854 TRACE("(%p,%p)\n", iface, reader);
855
856 if (!reader) return E_INVALIDARG;
857
858 *reader = NULL;
860}
861
862static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface,
863 IWICBitmapSource **ppIBitmapSource)
864{
865 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
866
867 if (!ppIBitmapSource) return E_INVALIDARG;
868
869 *ppIBitmapSource = NULL;
871}
872
873static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface,
874 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
875{
876 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
878}
879
880static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface,
881 IWICBitmapSource **ppIThumbnail)
882{
883 TRACE("(%p,%p)\n", iface, ppIThumbnail);
884
885 if (!ppIThumbnail) return E_INVALIDARG;
886
887 *ppIThumbnail = NULL;
889}
890
891static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface,
892 UINT *pCount)
893{
894 if (!pCount) return E_INVALIDARG;
895
896 *pCount = 1;
897 return S_OK;
898}
899
900static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface,
901 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
902{
903 PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
904 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
905
906 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
907
908 if (index != 0) return E_INVALIDARG;
909
910 IWICBitmapDecoder_AddRef(iface);
911
912 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
913
914 return S_OK;
915}
916
917static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = {
918 PngDecoder_QueryInterface,
919 PngDecoder_AddRef,
920 PngDecoder_Release,
921 PngDecoder_QueryCapability,
922 PngDecoder_Initialize,
923 PngDecoder_GetContainerFormat,
924 PngDecoder_GetDecoderInfo,
925 PngDecoder_CopyPalette,
926 PngDecoder_GetMetadataQueryReader,
927 PngDecoder_GetPreview,
928 PngDecoder_GetColorContexts,
929 PngDecoder_GetThumbnail,
930 PngDecoder_GetFrameCount,
931 PngDecoder_GetFrame
932};
933
934static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
935 void **ppv)
936{
937 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
938 if (!ppv) return E_INVALIDARG;
939
940 if (IsEqualIID(&IID_IUnknown, iid) ||
941 IsEqualIID(&IID_IWICBitmapSource, iid) ||
942 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
943 {
944 *ppv = &This->IWICBitmapFrameDecode_iface;
945 }
946 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
947 {
948 *ppv = &This->IWICMetadataBlockReader_iface;
949 }
950 else
951 {
952 *ppv = NULL;
953 return E_NOINTERFACE;
954 }
955
956 IUnknown_AddRef((IUnknown*)*ppv);
957 return S_OK;
958}
959
960static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
961{
962 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
963 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
964}
965
966static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
967{
968 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
969 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
970}
971
972static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
973 UINT *puiWidth, UINT *puiHeight)
974{
975 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
976 *puiWidth = This->width;
977 *puiHeight = This->height;
978 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
979 return S_OK;
980}
981
982static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
983 WICPixelFormatGUID *pPixelFormat)
984{
985 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
986 TRACE("(%p,%p)\n", iface, pPixelFormat);
987
988 memcpy(pPixelFormat, This->format, sizeof(GUID));
989
990 return S_OK;
991}
992
993static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
994 double *pDpiX, double *pDpiY)
995{
996 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
997 png_uint_32 ret, xres, yres;
998 int unit_type;
999
1000 EnterCriticalSection(&This->lock);
1001
1002 ret = ppng_get_pHYs(This->png_ptr, This->info_ptr, &xres, &yres, &unit_type);
1003
1004 if (ret && unit_type == PNG_RESOLUTION_METER)
1005 {
1006 *pDpiX = xres * 0.0254;
1007 *pDpiY = yres * 0.0254;
1008 }
1009 else
1010 {
1011 WARN("no pHYs block present\n");
1012 *pDpiX = *pDpiY = 96.0;
1013 }
1014
1015 LeaveCriticalSection(&This->lock);
1016
1017 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
1018
1019 return S_OK;
1020}
1021
1022static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
1023 IWICPalette *pIPalette)
1024{
1025 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1026 png_uint_32 ret, color_type, bit_depth;
1027 png_colorp png_palette;
1028 int num_palette;
1029 WICColor palette[256];
1030 png_bytep trans_alpha;
1031 int num_trans;
1032 png_color_16p trans_values;
1033 int i;
1034 HRESULT hr=S_OK;
1035
1036 TRACE("(%p,%p)\n", iface, pIPalette);
1037
1038 EnterCriticalSection(&This->lock);
1039
1040 color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
1041 bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
1042
1043 if (color_type == PNG_COLOR_TYPE_PALETTE)
1044 {
1045 ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette);
1046 if (!ret)
1047 {
1049 goto end;
1050 }
1051
1052 if (num_palette > 256)
1053 {
1054 ERR("palette has %i colors?!\n", num_palette);
1055 hr = E_FAIL;
1056 goto end;
1057 }
1058
1059 ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans_alpha, &num_trans, &trans_values);
1060 if (!ret) num_trans = 0;
1061
1062 for (i=0; i<num_palette; i++)
1063 {
1064 BYTE alpha = (i < num_trans) ? trans_alpha[i] : 0xff;
1065 palette[i] = (alpha << 24 |
1066 png_palette[i].red << 16|
1067 png_palette[i].green << 8|
1068 png_palette[i].blue);
1069 }
1070 }
1071 else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth <= 8) {
1072 ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans_alpha, &num_trans, &trans_values);
1073
1074 if (!ret)
1075 {
1077 goto end;
1078 }
1079
1080 num_palette = 1 << bit_depth;
1081
1082 for (i=0; i<num_palette; i++)
1083 {
1084 BYTE alpha = (i == trans_values[0].gray) ? 0 : 0xff;
1085 BYTE val = i * 255 / (num_palette - 1);
1086 palette[i] = (alpha << 24 | val << 16 | val << 8 | val);
1087 }
1088 }
1089 else
1090 {
1092 }
1093
1094end:
1095
1096 LeaveCriticalSection(&This->lock);
1097
1098 if (SUCCEEDED(hr))
1099 hr = IWICPalette_InitializeCustom(pIPalette, palette, num_palette);
1100
1101 return hr;
1102}
1103
1104static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
1105 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1106{
1107 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1108 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1109
1110 return copy_pixels(This->bpp, This->image_bits,
1111 This->width, This->height, This->stride,
1112 prc, cbStride, cbBufferSize, pbBuffer);
1113}
1114
1115static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
1116 IWICMetadataQueryReader **ppIMetadataQueryReader)
1117{
1118 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1119
1120 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1121
1122 if (!ppIMetadataQueryReader)
1123 return E_INVALIDARG;
1124
1125 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
1126}
1127
1128static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
1129 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1130{
1131 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1133 BYTE *profile;
1135 int compression_type;
1136 HRESULT hr;
1137
1138 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1139
1140 if (!pcActualCount) return E_INVALIDARG;
1141
1142 EnterCriticalSection(&This->lock);
1143
1144 if (ppng_get_iCCP(This->png_ptr, This->info_ptr, &name, &compression_type, (void *)&profile, &len))
1145 {
1146 if (cCount && ppIColorContexts)
1147 {
1148 hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, len);
1149 if (FAILED(hr))
1150 {
1151 LeaveCriticalSection(&This->lock);
1152 return hr;
1153 }
1154 }
1155 *pcActualCount = 1;
1156 }
1157 else
1158 *pcActualCount = 0;
1159
1160 LeaveCriticalSection(&This->lock);
1161
1162 return S_OK;
1163}
1164
1165static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
1166 IWICBitmapSource **ppIThumbnail)
1167{
1168 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1169
1170 if (!ppIThumbnail) return E_INVALIDARG;
1171
1172 *ppIThumbnail = NULL;
1174}
1175
1176static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = {
1177 PngDecoder_Frame_QueryInterface,
1178 PngDecoder_Frame_AddRef,
1179 PngDecoder_Frame_Release,
1180 PngDecoder_Frame_GetSize,
1181 PngDecoder_Frame_GetPixelFormat,
1182 PngDecoder_Frame_GetResolution,
1183 PngDecoder_Frame_CopyPalette,
1184 PngDecoder_Frame_CopyPixels,
1185 PngDecoder_Frame_GetMetadataQueryReader,
1186 PngDecoder_Frame_GetColorContexts,
1187 PngDecoder_Frame_GetThumbnail
1188};
1189
1190static HRESULT WINAPI PngDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid,
1191 void **ppv)
1192{
1193 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1194 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
1195}
1196
1197static ULONG WINAPI PngDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1198{
1199 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1200 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1201}
1202
1203static ULONG WINAPI PngDecoder_Block_Release(IWICMetadataBlockReader *iface)
1204{
1205 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1206 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1207}
1208
1209static HRESULT WINAPI PngDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1210 GUID *pguidContainerFormat)
1211{
1212 if (!pguidContainerFormat) return E_INVALIDARG;
1213 memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
1214 return S_OK;
1215}
1216
1217static HRESULT WINAPI PngDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1218 UINT *pcCount)
1219{
1220 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1221
1222 TRACE("%p,%p\n", iface, pcCount);
1223
1224 if (!pcCount) return E_INVALIDARG;
1225
1226 *pcCount = This->metadata_count;
1227
1228 return S_OK;
1229}
1230
1231static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1232 UINT nIndex, IWICMetadataReader **ppIMetadataReader)
1233{
1234 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1235 HRESULT hr;
1238
1239 TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader);
1240
1241 if (nIndex >= This->metadata_count || !ppIMetadataReader)
1242 return E_INVALIDARG;
1243
1244 if (!This->metadata_blocks[nIndex].reader)
1245 {
1247
1248 if (SUCCEEDED(hr))
1249 {
1250 hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream,
1251 This->metadata_blocks[nIndex].ofs, This->metadata_blocks[nIndex].len);
1252
1253 if (SUCCEEDED(hr))
1254 hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory);
1255
1256 if (SUCCEEDED(hr))
1257 {
1258 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1259 &GUID_ContainerFormatPng, NULL, WICMetadataCreationAllowUnknown,
1260 (IStream*)stream, &This->metadata_blocks[nIndex].reader);
1261
1262 IWICComponentFactory_Release(factory);
1263 }
1264
1265 IWICStream_Release(stream);
1266 }
1267
1268 if (FAILED(hr))
1269 {
1270 *ppIMetadataReader = NULL;
1271 return hr;
1272 }
1273 }
1274
1275 *ppIMetadataReader = This->metadata_blocks[nIndex].reader;
1276 IWICMetadataReader_AddRef(*ppIMetadataReader);
1277
1278 return S_OK;
1279}
1280
1281static HRESULT WINAPI PngDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1282 IEnumUnknown **ppIEnumMetadata)
1283{
1284 FIXME("%p,%p\n", iface, ppIEnumMetadata);
1285 return E_NOTIMPL;
1286}
1287
1288static const IWICMetadataBlockReaderVtbl PngDecoder_BlockVtbl = {
1289 PngDecoder_Block_QueryInterface,
1290 PngDecoder_Block_AddRef,
1291 PngDecoder_Block_Release,
1292 PngDecoder_Block_GetContainerFormat,
1293 PngDecoder_Block_GetCount,
1294 PngDecoder_Block_GetReaderByIndex,
1295 PngDecoder_Block_GetEnumerator,
1296};
1297
1299{
1300 PngDecoder *This;
1301 HRESULT ret;
1302
1303 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1304
1305 *ppv = NULL;
1306
1307 if (!load_libpng())
1308 {
1309 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1310 return E_FAIL;
1311 }
1312
1313 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder));
1314 if (!This) return E_OUTOFMEMORY;
1315
1316 This->IWICBitmapDecoder_iface.lpVtbl = &PngDecoder_Vtbl;
1317 This->IWICBitmapFrameDecode_iface.lpVtbl = &PngDecoder_FrameVtbl;
1318 This->IWICMetadataBlockReader_iface.lpVtbl = &PngDecoder_BlockVtbl;
1319 This->ref = 1;
1320 This->png_ptr = NULL;
1321 This->info_ptr = NULL;
1322 This->end_info = NULL;
1323 This->stream = NULL;
1324 This->initialized = FALSE;
1325 This->image_bits = NULL;
1327 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngDecoder.lock");
1328 This->metadata_count = 0;
1329 This->metadata_blocks = NULL;
1330
1331 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1332 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1333
1334 return ret;
1335}
1336
1337struct png_pixelformat {
1338 const WICPixelFormatGUID *guid;
1339 UINT bpp;
1340 int bit_depth;
1341 int color_type;
1342 BOOL remove_filler;
1343 BOOL swap_rgb;
1344};
1345
1346static const struct png_pixelformat formats[] = {
1347 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
1348 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
1349 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
1350 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
1351 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
1352 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
1353 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
1354 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
1355 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
1356 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
1357 {&GUID_WICPixelFormat1bppIndexed, 1, 1, PNG_COLOR_TYPE_PALETTE, 0, 0},
1358 {&GUID_WICPixelFormat2bppIndexed, 2, 2, PNG_COLOR_TYPE_PALETTE, 0, 0},
1359 {&GUID_WICPixelFormat4bppIndexed, 4, 4, PNG_COLOR_TYPE_PALETTE, 0, 0},
1360 {&GUID_WICPixelFormat8bppIndexed, 8, 8, PNG_COLOR_TYPE_PALETTE, 0, 0},
1361 {NULL},
1362};
1363
1364typedef struct PngEncoder {
1365 IWICBitmapEncoder IWICBitmapEncoder_iface;
1366 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1367 LONG ref;
1368 IStream *stream;
1371 UINT frame_count;
1372 BOOL frame_initialized;
1373 const struct png_pixelformat *format;
1374 BOOL info_written;
1375 UINT width, height;
1376 double xres, yres;
1377 UINT lines_written;
1378 BOOL frame_committed;
1379 BOOL committed;
1381 BOOL interlace;
1383 BYTE *data;
1384 UINT stride;
1385 UINT passes;
1386 WICColor palette[256];
1387 UINT colors;
1388} PngEncoder;
1389
1390static inline PngEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1391{
1392 return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapEncoder_iface);
1393}
1394
1395static inline PngEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1396{
1397 return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapFrameEncode_iface);
1398}
1399
1400static HRESULT WINAPI PngFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
1401 void **ppv)
1402{
1403 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1404 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1405
1406 if (!ppv) return E_INVALIDARG;
1407
1408 if (IsEqualIID(&IID_IUnknown, iid) ||
1409 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1410 {
1411 *ppv = &This->IWICBitmapFrameEncode_iface;
1412 }
1413 else
1414 {
1415 *ppv = NULL;
1416 return E_NOINTERFACE;
1417 }
1418
1419 IUnknown_AddRef((IUnknown*)*ppv);
1420 return S_OK;
1421}
1422
1423static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1424{
1425 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1426 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
1427}
1428
1429static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface)
1430{
1431 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1432 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1433}
1434
1435static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
1436 IPropertyBag2 *pIEncoderOptions)
1437{
1438 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1440 BOOL interlace;
1441 PROPBAG2 opts[2]= {{0}};
1442 VARIANT opt_values[2];
1443 HRESULT opt_hres[2];
1444 HRESULT hr;
1445
1446 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
1447
1448 opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption;
1449 opts[0].vt = VT_BOOL;
1450 opts[1].pstrName = (LPOLESTR)wszPngFilterOption;
1451 opts[1].vt = VT_UI1;
1452
1453 if (pIEncoderOptions)
1454 {
1455 hr = IPropertyBag2_Read(pIEncoderOptions, ARRAY_SIZE(opts), opts, NULL, opt_values, opt_hres);
1456
1457 if (FAILED(hr))
1458 return hr;
1459
1460 if (V_VT(&opt_values[0]) == VT_EMPTY)
1461 interlace = FALSE;
1462 else
1463 interlace = (V_BOOL(&opt_values[0]) != 0);
1464
1465 filter = V_UI1(&opt_values[1]);
1467 {
1468 WARN("Unrecognized filter option value %u.\n", filter);
1470 }
1471 }
1472 else
1473 {
1474 interlace = FALSE;
1476 }
1477
1478 EnterCriticalSection(&This->lock);
1479
1480 if (This->frame_initialized)
1481 {
1482 LeaveCriticalSection(&This->lock);
1484 }
1485
1486 This->interlace = interlace;
1487 This->filter = filter;
1488
1489 This->frame_initialized = TRUE;
1490
1491 LeaveCriticalSection(&This->lock);
1492
1493 return S_OK;
1494}
1495
1496static HRESULT WINAPI PngFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
1497 UINT uiWidth, UINT uiHeight)
1498{
1499 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1500 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
1501
1502 EnterCriticalSection(&This->lock);
1503
1504 if (!This->frame_initialized || This->info_written)
1505 {
1506 LeaveCriticalSection(&This->lock);
1508 }
1509
1510 This->width = uiWidth;
1511 This->height = uiHeight;
1512
1513 LeaveCriticalSection(&This->lock);
1514
1515 return S_OK;
1516}
1517
1518static HRESULT WINAPI PngFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
1519 double dpiX, double dpiY)
1520{
1521 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1522 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
1523
1524 EnterCriticalSection(&This->lock);
1525
1526 if (!This->frame_initialized || This->info_written)
1527 {
1528 LeaveCriticalSection(&This->lock);
1530 }
1531
1532 This->xres = dpiX;
1533 This->yres = dpiY;
1534
1535 LeaveCriticalSection(&This->lock);
1536
1537 return S_OK;
1538}
1539
1540static HRESULT WINAPI PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
1541 WICPixelFormatGUID *pPixelFormat)
1542{
1543 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1544 int i;
1545 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
1546
1547 EnterCriticalSection(&This->lock);
1548
1549 if (!This->frame_initialized || This->info_written)
1550 {
1551 LeaveCriticalSection(&This->lock);
1553 }
1554
1555 for (i=0; formats[i].guid; i++)
1556 {
1557 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
1558 break;
1559 }
1560
1561 if (!formats[i].guid) i = 0;
1562
1563 This->format = &formats[i];
1564 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
1565
1566 LeaveCriticalSection(&This->lock);
1567
1568 return S_OK;
1569}
1570
1571static HRESULT WINAPI PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
1572 UINT cCount, IWICColorContext **ppIColorContext)
1573{
1574 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1575 return E_NOTIMPL;
1576}
1577
1578static HRESULT WINAPI PngFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
1580{
1581 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1582 HRESULT hr;
1583
1584 TRACE("(%p,%p)\n", iface, palette);
1585
1586 if (!palette) return E_INVALIDARG;
1587
1588 EnterCriticalSection(&This->lock);
1589
1590 if (This->frame_initialized)
1591 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1592 else
1594
1595 LeaveCriticalSection(&This->lock);
1596 return hr;
1597}
1598
1599static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
1600 IWICBitmapSource *pIThumbnail)
1601{
1602 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1604}
1605
1606static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
1607 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
1608{
1609 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1610 png_byte **row_pointers=NULL;
1611 UINT i;
1613 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
1614
1615 EnterCriticalSection(&This->lock);
1616
1617 if (!This->frame_initialized || !This->width || !This->height || !This->format)
1618 {
1619 LeaveCriticalSection(&This->lock);
1621 }
1622
1623 if (lineCount == 0 || lineCount + This->lines_written > This->height)
1624 {
1625 LeaveCriticalSection(&This->lock);
1626 return E_INVALIDARG;
1627 }
1628
1629 /* set up setjmp/longjmp error handling */
1630 if (setjmp(jmpbuf))
1631 {
1632 LeaveCriticalSection(&This->lock);
1633 HeapFree(GetProcessHeap(), 0, row_pointers);
1634 return E_FAIL;
1635 }
1636 ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
1637
1638 if (!This->info_written)
1639 {
1640 if (This->interlace)
1641 {
1642 /* libpng requires us to write all data multiple times in this case. */
1643 This->stride = (This->format->bpp * This->width + 7)/8;
1644 This->data = HeapAlloc(GetProcessHeap(), 0, This->height * This->stride);
1645 if (!This->data)
1646 {
1647 LeaveCriticalSection(&This->lock);
1648 return E_OUTOFMEMORY;
1649 }
1650 }
1651
1652 /* Tell PNG we need to byte swap if writing a >8-bpp image */
1653 if (This->format->bit_depth > 8)
1654 ppng_set_swap(This->png_ptr);
1655
1656 ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height,
1657 This->format->bit_depth, This->format->color_type,
1660
1661 if (This->xres != 0.0 && This->yres != 0.0)
1662 {
1663 ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254,
1664 (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER);
1665 }
1666
1667 if (This->format->color_type == PNG_COLOR_TYPE_PALETTE && This->colors)
1668 {
1669 png_color png_palette[256];
1670 png_byte trans[256];
1671 UINT i, num_trans = 0, colors;
1672
1673 /* Newer libpng versions don't accept larger palettes than the declared
1674 * bit depth, so we need to generate the palette of the correct length.
1675 */
1676 colors = min(This->colors, 1 << This->format->bit_depth);
1677
1678 for (i = 0; i < colors; i++)
1679 {
1680 png_palette[i].red = (This->palette[i] >> 16) & 0xff;
1681 png_palette[i].green = (This->palette[i] >> 8) & 0xff;
1682 png_palette[i].blue = This->palette[i] & 0xff;
1683 trans[i] = (This->palette[i] >> 24) & 0xff;
1684 if (trans[i] != 0xff)
1685 num_trans = i+1;
1686 }
1687
1688 ppng_set_PLTE(This->png_ptr, This->info_ptr, png_palette, colors);
1689
1690 if (num_trans)
1691 ppng_set_tRNS(This->png_ptr, This->info_ptr, trans, num_trans, NULL);
1692 }
1693
1694 ppng_write_info(This->png_ptr, This->info_ptr);
1695
1696 if (This->format->remove_filler)
1697 ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);
1698
1699 if (This->format->swap_rgb)
1700 ppng_set_bgr(This->png_ptr);
1701
1702 if (This->interlace)
1703 This->passes = ppng_set_interlace_handling(This->png_ptr);
1704
1705 if (This->filter != WICPngFilterUnspecified)
1706 {
1707 static const int png_filter_map[] =
1708 {
1709 /* WICPngFilterUnspecified */ PNG_NO_FILTERS,
1710 /* WICPngFilterNone */ PNG_FILTER_NONE,
1711 /* WICPngFilterSub */ PNG_FILTER_SUB,
1712 /* WICPngFilterUp */ PNG_FILTER_UP,
1713 /* WICPngFilterAverage */ PNG_FILTER_AVG,
1714 /* WICPngFilterPaeth */ PNG_FILTER_PAETH,
1715 /* WICPngFilterAdaptive */ PNG_ALL_FILTERS,
1716 };
1717
1718 ppng_set_filter(This->png_ptr, 0, png_filter_map[This->filter]);
1719 }
1720
1721 This->info_written = TRUE;
1722 }
1723
1724 if (This->interlace)
1725 {
1726 /* Just store the data so we can write it in multiple passes in Commit. */
1727 for (i=0; i<lineCount; i++)
1728 memcpy(This->data + This->stride * (This->lines_written + i),
1729 pbPixels + cbStride * i,
1730 This->stride);
1731
1732 This->lines_written += lineCount;
1733
1734 LeaveCriticalSection(&This->lock);
1735 return S_OK;
1736 }
1737
1738 row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*));
1739 if (!row_pointers)
1740 {
1741 LeaveCriticalSection(&This->lock);
1742 return E_OUTOFMEMORY;
1743 }
1744
1745 for (i=0; i<lineCount; i++)
1746 row_pointers[i] = pbPixels + cbStride * i;
1747
1748 ppng_write_rows(This->png_ptr, row_pointers, lineCount);
1749 This->lines_written += lineCount;
1750
1751 LeaveCriticalSection(&This->lock);
1752
1753 HeapFree(GetProcessHeap(), 0, row_pointers);
1754
1755 return S_OK;
1756}
1757
1758static HRESULT WINAPI PngFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
1759 IWICBitmapSource *pIBitmapSource, WICRect *prc)
1760{
1761 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1762 HRESULT hr;
1763 TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc));
1764
1765 if (!This->frame_initialized)
1767
1768 hr = configure_write_source(iface, pIBitmapSource, prc,
1769 This->format ? This->format->guid : NULL, This->width, This->height,
1770 This->xres, This->yres);
1771
1772 if (SUCCEEDED(hr))
1773 {
1774 hr = write_source(iface, pIBitmapSource, prc,
1775 This->format->guid, This->format->bpp, This->width, This->height);
1776 }
1777
1778 return hr;
1779}
1780
1781static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1782{
1783 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1784 png_byte **row_pointers=NULL;
1786 TRACE("(%p)\n", iface);
1787
1788 EnterCriticalSection(&This->lock);
1789
1790 if (!This->info_written || This->lines_written != This->height || This->frame_committed)
1791 {
1792 LeaveCriticalSection(&This->lock);
1794 }
1795
1796 /* set up setjmp/longjmp error handling */
1797 if (setjmp(jmpbuf))
1798 {
1799 LeaveCriticalSection(&This->lock);
1800 HeapFree(GetProcessHeap(), 0, row_pointers);
1801 return E_FAIL;
1802 }
1803 ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
1804
1805 if (This->interlace)
1806 {
1807 int i;
1808
1809 row_pointers = HeapAlloc(GetProcessHeap(), 0, This->height * sizeof(png_byte*));
1810 if (!row_pointers)
1811 {
1812 LeaveCriticalSection(&This->lock);
1813 return E_OUTOFMEMORY;
1814 }
1815
1816 for (i=0; i<This->height; i++)
1817 row_pointers[i] = This->data + This->stride * i;
1818
1819 for (i=0; i<This->passes; i++)
1820 ppng_write_rows(This->png_ptr, row_pointers, This->height);
1821 }
1822
1823 ppng_write_end(This->png_ptr, This->info_ptr);
1824
1825 This->frame_committed = TRUE;
1826
1827 HeapFree(GetProcessHeap(), 0, row_pointers);
1828
1829 LeaveCriticalSection(&This->lock);
1830
1831 return S_OK;
1832}
1833
1834static HRESULT WINAPI PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1835 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1836{
1837 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1838 return E_NOTIMPL;
1839}
1840
1841static const IWICBitmapFrameEncodeVtbl PngEncoder_FrameVtbl = {
1842 PngFrameEncode_QueryInterface,
1843 PngFrameEncode_AddRef,
1844 PngFrameEncode_Release,
1845 PngFrameEncode_Initialize,
1846 PngFrameEncode_SetSize,
1847 PngFrameEncode_SetResolution,
1848 PngFrameEncode_SetPixelFormat,
1849 PngFrameEncode_SetColorContexts,
1850 PngFrameEncode_SetPalette,
1851 PngFrameEncode_SetThumbnail,
1852 PngFrameEncode_WritePixels,
1853 PngFrameEncode_WriteSource,
1854 PngFrameEncode_Commit,
1855 PngFrameEncode_GetMetadataQueryWriter
1856};
1857
1858static HRESULT WINAPI PngEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1859 void **ppv)
1860{
1861 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1862 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1863
1864 if (!ppv) return E_INVALIDARG;
1865
1866 if (IsEqualIID(&IID_IUnknown, iid) ||
1867 IsEqualIID(&IID_IWICBitmapEncoder, iid))
1868 {
1869 *ppv = &This->IWICBitmapEncoder_iface;
1870 }
1871 else
1872 {
1873 *ppv = NULL;
1874 return E_NOINTERFACE;
1875 }
1876
1877 IUnknown_AddRef((IUnknown*)*ppv);
1878 return S_OK;
1879}
1880
1881static ULONG WINAPI PngEncoder_AddRef(IWICBitmapEncoder *iface)
1882{
1883 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1885
1886 TRACE("(%p) refcount=%u\n", iface, ref);
1887
1888 return ref;
1889}
1890
1891static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface)
1892{
1893 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1895
1896 TRACE("(%p) refcount=%u\n", iface, ref);
1897
1898 if (ref == 0)
1899 {
1900 This->lock.DebugInfo->Spare[0] = 0;
1902 if (This->png_ptr)
1903 ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
1904 if (This->stream)
1905 IStream_Release(This->stream);
1906 HeapFree(GetProcessHeap(), 0, This->data);
1908 }
1909
1910 return ref;
1911}
1912
1913static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
1914{
1915 PngEncoder *This = ppng_get_io_ptr(png_ptr);
1916 HRESULT hr;
1917 ULONG byteswritten;
1918
1919 hr = IStream_Write(This->stream, data, length, &byteswritten);
1920 if (FAILED(hr) || byteswritten != length)
1921 {
1922 ppng_error(png_ptr, "failed writing data");
1923 }
1924}
1925
1926static void user_flush(png_structp png_ptr)
1927{
1928}
1929
1930static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface,
1931 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1932{
1933 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1935
1936 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1937
1938 EnterCriticalSection(&This->lock);
1939
1940 if (This->png_ptr)
1941 {
1942 LeaveCriticalSection(&This->lock);
1944 }
1945
1946 /* initialize libpng */
1947 This->png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1948 if (!This->png_ptr)
1949 {
1950 LeaveCriticalSection(&This->lock);
1951 return E_FAIL;
1952 }
1953
1954 This->info_ptr = ppng_create_info_struct(This->png_ptr);
1955 if (!This->info_ptr)
1956 {
1957 ppng_destroy_write_struct(&This->png_ptr, NULL);
1958 This->png_ptr = NULL;
1959 LeaveCriticalSection(&This->lock);
1960 return E_FAIL;
1961 }
1962
1963 IStream_AddRef(pIStream);
1964 This->stream = pIStream;
1965
1966 /* set up setjmp/longjmp error handling */
1967 if (setjmp(jmpbuf))
1968 {
1969 ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
1970 This->png_ptr = NULL;
1971 IStream_Release(This->stream);
1972 This->stream = NULL;
1973 LeaveCriticalSection(&This->lock);
1974 return E_FAIL;
1975 }
1976 ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
1977
1978 /* set up custom i/o handling */
1979 ppng_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
1980
1981 LeaveCriticalSection(&This->lock);
1982
1983 return S_OK;
1984}
1985
1986static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
1987{
1988 TRACE("(%p,%p)\n", iface, format);
1989
1990 if (!format)
1991 return E_INVALIDARG;
1992
1993 memcpy(format, &GUID_ContainerFormatPng, sizeof(*format));
1994 return S_OK;
1995}
1996
1997static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
1998{
1999 IWICComponentInfo *comp_info;
2000 HRESULT hr;
2001
2002 TRACE("%p,%p\n", iface, info);
2003
2004 if (!info) return E_INVALIDARG;
2005
2006 hr = CreateComponentInfo(&CLSID_WICPngEncoder, &comp_info);
2007 if (hr == S_OK)
2008 {
2009 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
2010 IWICComponentInfo_Release(comp_info);
2011 }
2012 return hr;
2013}
2014
2015static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface,
2016 UINT cCount, IWICColorContext **ppIColorContext)
2017{
2018 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
2019 return E_NOTIMPL;
2020}
2021
2022static HRESULT WINAPI PngEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2023{
2024 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
2025 HRESULT hr;
2026
2027 TRACE("(%p,%p)\n", iface, palette);
2028
2029 EnterCriticalSection(&This->lock);
2030
2032
2033 LeaveCriticalSection(&This->lock);
2034
2035 return hr;
2036}
2037
2038static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
2039{
2040 TRACE("(%p,%p)\n", iface, pIThumbnail);
2042}
2043
2044static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
2045{
2046 TRACE("(%p,%p)\n", iface, pIPreview);
2048}
2049
2050static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
2051 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
2052{
2053 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
2054 HRESULT hr;
2055 static const PROPBAG2 opts[2] =
2056 {
2057 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszPngInterlaceOption },
2058 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszPngFilterOption },
2059 };
2060
2061 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
2062
2063 EnterCriticalSection(&This->lock);
2064
2065 if (This->frame_count != 0)
2066 {
2067 LeaveCriticalSection(&This->lock);
2069 }
2070
2071 if (!This->stream)
2072 {
2073 LeaveCriticalSection(&This->lock);
2075 }
2076
2077 if (ppIEncoderOptions)
2078 {
2079 hr = CreatePropertyBag2(opts, ARRAY_SIZE(opts), ppIEncoderOptions);
2080 if (FAILED(hr))
2081 {
2082 LeaveCriticalSection(&This->lock);
2083 return hr;
2084 }
2085 }
2086
2087 This->frame_count = 1;
2088
2089 LeaveCriticalSection(&This->lock);
2090
2091 IWICBitmapEncoder_AddRef(iface);
2092 *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface;
2093
2094 return S_OK;
2095}
2096
2097static HRESULT WINAPI PngEncoder_Commit(IWICBitmapEncoder *iface)
2098{
2099 PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
2100 TRACE("(%p)\n", iface);
2101
2102 EnterCriticalSection(&This->lock);
2103
2104 if (!This->frame_committed || This->committed)
2105 {
2106 LeaveCriticalSection(&This->lock);
2108 }
2109
2110 This->committed = TRUE;
2111
2112 LeaveCriticalSection(&This->lock);
2113
2114 return S_OK;
2115}
2116
2117static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
2118 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
2119{
2120 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
2121 return E_NOTIMPL;
2122}
2123
2124static const IWICBitmapEncoderVtbl PngEncoder_Vtbl = {
2125 PngEncoder_QueryInterface,
2126 PngEncoder_AddRef,
2127 PngEncoder_Release,
2128 PngEncoder_Initialize,
2129 PngEncoder_GetContainerFormat,
2130 PngEncoder_GetEncoderInfo,
2131 PngEncoder_SetColorContexts,
2132 PngEncoder_SetPalette,
2133 PngEncoder_SetThumbnail,
2134 PngEncoder_SetPreview,
2135 PngEncoder_CreateNewFrame,
2136 PngEncoder_Commit,
2137 PngEncoder_GetMetadataQueryWriter
2138};
2139
2141{
2142 PngEncoder *This;
2143 HRESULT ret;
2144
2145 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
2146
2147 *ppv = NULL;
2148
2149 if (!load_libpng())
2150 {
2151 ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG);
2152 return E_FAIL;
2153 }
2154
2155 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder));
2156 if (!This) return E_OUTOFMEMORY;
2157
2158 This->IWICBitmapEncoder_iface.lpVtbl = &PngEncoder_Vtbl;
2159 This->IWICBitmapFrameEncode_iface.lpVtbl = &PngEncoder_FrameVtbl;
2160 This->ref = 1;
2161 This->png_ptr = NULL;
2162 This->info_ptr = NULL;
2163 This->stream = NULL;
2164 This->frame_count = 0;
2165 This->frame_initialized = FALSE;
2166 This->format = NULL;
2167 This->info_written = FALSE;
2168 This->width = 0;
2169 This->height = 0;
2170 This->xres = 0.0;
2171 This->yres = 0.0;
2172 This->lines_written = 0;
2173 This->frame_committed = FALSE;
2174 This->committed = FALSE;
2175 This->data = NULL;
2176 This->colors = 0;
2178 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngEncoder.lock");
2179
2180 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2181 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2182
2183 return ret;
2184}
2185
2186#else /* !HAVE_PNG_H */
2187
2189{
2190 ERR("Trying to load PNG picture, but PNG support is not compiled in.\n");
2191 return E_FAIL;
2192}
2193
2195{
2196 ERR("Trying to save PNG picture, but PNG support is not compiled in.\n");
2197 return E_FAIL;
2198}
2199
2200#endif
static jmp_buf jmpbuf
Definition: NtContinue.c:24
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:33
const GUID IID_IUnknown
static BmpDecoder * impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
Definition: bmpdecode.c:88
static BmpDecoder * impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
Definition: bmpdecode.c:83
static BmpFrameEncode * impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
Definition: bmpencode.c:84
static BmpEncoder * impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
Definition: bmpencode.c:433
#define FIXME(fmt,...)
Definition: debug.h:114
#define WARN(fmt,...)
Definition: debug.h:115
#define ERR(fmt,...)
Definition: debug.h:113
#define setjmp
Definition: setjmp.h:209
_JBTYPE jmp_buf[_JBLEN]
Definition: setjmp.h:186
void copy_pixels(const BYTE *src, UINT src_row_pitch, UINT src_slice_pitch, BYTE *dst, UINT dst_row_pitch, UINT dst_slice_pitch, const struct volume *size, const struct pixel_format_desc *format) DECLSPEC_HIDDEN
Definition: surface.c:1700
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
DWORD bpp
Definition: surface.c:185
static const struct pixel_format_desc formats[]
Definition: util.c:59
void error_message(HWND hwnd, const char *msg)
Definition: main.cpp:783
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define lstrcpyW
Definition: compat.h:749
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
@ VT_LPSTR
Definition: compat.h:2324
@ VT_LPWSTR
Definition: compat.h:2325
@ VT_BOOL
Definition: compat.h:2306
@ VT_UI4
Definition: compat.h:2313
@ VT_EMPTY
Definition: compat.h:2295
@ VT_UI1
Definition: compat.h:2311
#define lstrlenW
Definition: compat.h:750
static GpStatus get_decoder_info(IStream *stream, const struct image_codec **result)
Definition: image.c:4285
static GifDecoder * impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
Definition: gifformat.c:607
HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
Definition: info.c:2075
HRESULT write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, UINT bpp, INT width, INT height)
Definition: main.c:155
HRESULT configure_write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, INT width, INT height, double xres, double yres)
Definition: main.c:123
static HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size)
Definition: pngformat.c:48
static HRESULT LoadChrmMetadata(IStream *stream, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count)
Definition: pngformat.c:222
static ULONG read_ulong_be(BYTE *data)
Definition: pngformat.c:43
HRESULT PngDecoder_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:2188
HRESULT PngEncoder_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:2194
static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count)
Definition: pngformat.c:89
HRESULT PngGamaReader_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:217
static const MetadataHandlerVtbl TextReader_Vtbl
Definition: pngformat.c:149
static const MetadataHandlerVtbl GamaReader_Vtbl
Definition: pngformat.c:211
static HRESULT LoadGamaMetadata(IStream *stream, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count)
Definition: pngformat.c:160
HRESULT PngTextReader_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:155
HRESULT PngChrmReader_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:295
static const MetadataHandlerVtbl ChrmReader_Vtbl
Definition: pngformat.c:289
HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count, IPropertyBag2 **ppPropertyBag2)
Definition: propertybag.c:281
HRESULT StreamImpl_Create(IWICStream **stream)
Definition: stream.c:1150
#define LOAD_FUNCPTR(f)
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLclampf GLclampf GLclampf alpha
Definition: gl.h:1740
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLint GLint GLsizei width
Definition: gl.h:1546
GLsizei stride
Definition: glext.h:5848
GLuint GLuint * names
Definition: glext.h:11545
GLuint index
Definition: glext.h:6031
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint GLfloat * val
Definition: glext.h:7180
GLenum GLsizei len
Definition: glext.h:6722
GLuint64EXT * result
Definition: glext.h:11304
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
HRESULT ImagingFactory_CreateInstance(REFIID iid, void **ppv)
Definition: imgfactory.c:1470
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define debugstr_guid
Definition: kernel32.h:35
#define debugstr_a
Definition: kernel32.h:31
#define profile
Definition: kernel32.h:12
void * wine_dlopen(const char *filename, int flag, char *error, size_t errorsize)
Definition: loader.c:53
HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, REFIID iid, void **ppv)
const WCHAR * schema
HRESULT MetadataQueryReader_CreateInstance(IWICMetadataBlockReader *mbr, const WCHAR *root, IWICMetadataQueryReader **out)
const GUID * guid
static GLint image_size(GLint width, GLint height, GLenum format, GLenum type)
Definition: mipmap.c:4858
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memchr(s, c, n)
Definition: mkisofs.h:875
#define for
Definition: utility.h:88
#define PNG_COLOR_TYPE_RGB
Definition: image.c:5165
#define PNG_COLOR_TYPE_RGB_ALPHA
Definition: image.c:5168
#define PNG_COLOR_TYPE_GRAY_ALPHA
Definition: image.c:5167
#define PNG_COLOR_TYPE_GRAY
Definition: image.c:5164
#define PNG_COLOR_TYPE_PALETTE
Definition: image.c:5166
static LPOLESTR
Definition: stg_prop.c:27
static HPALETTE palette
Definition: clipboard.c:1345
#define RTLD_NOW
Definition: port.h:100
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
_Out_ LPRECT prc
Definition: ntgdi.h:1658
#define V_UI1(A)
Definition: oleauto.h:266
#define V_BOOL(A)
Definition: oleauto.h:224
#define V_VT(A)
Definition: oleauto.h:211
static TCHAR * items[]
Definition: page1.c:45
long LONG
Definition: pedump.c:60
png_voidp PNGAPI png_get_io_ptr(png_const_structrp png_ptr)
Definition: png.c:686
#define PNG_FILTER_SUB
Definition: png.h:1463
#define PNG_FILTER_PAETH
Definition: png.h:1466
#define PNG_FILTER_NONE
Definition: png.h:1462
png_structrp png_ptr
Definition: png.h:1080
#define PNG_COMPRESSION_TYPE_DEFAULT
Definition: png.h:676
#define PNG_FILTER_AVG
Definition: png.h:1465
png_uint_32
Definition: png.h:1936
#define PNG_CRC_QUIET_USE
Definition: png.h:1437
#define PNG_RESOLUTION_METER
Definition: png.h:708
#define PNG_ALL_FILTERS
Definition: png.h:1468
#define PNG_FILLER_AFTER
Definition: png.h:1246
#define PNG_INTERLACE_ADAM7
Definition: png.h:685
#define PNG_FILTER_UP
Definition: png.h:1464
#define PNG_LIBPNG_VER_STRING
Definition: png.h:281
#define PNG_FILTER_TYPE_DEFAULT
Definition: png.h:681
#define PNG_NO_FILTERS
Definition: png.h:1461
#define PNG_INTERLACE_NONE
Definition: png.h:684
png_const_structrp png_const_inforp info_ptr
Definition: png.h:1937
char * png_charp
Definition: pngconf.h:589
png_byte * png_bytep
Definition: pngconf.h:579
size_t png_size_t
Definition: pngconf.h:523
const char * png_const_charp
Definition: pngconf.h:590
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
#define MAKE_FUNCPTR(f)
#define SONAME_LIBPNG
Definition: config.h:1257
int seek(void *fd, ulong off, int mode)
Definition: pe.c:51
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
LIST_ENTRY ProcessLocksList
Definition: winbase.h:883
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
Definition: main.c:439
Definition: name.c:39
png_uint_16 gray
Definition: png.h:491
png_byte blue
Definition: png.h:479
png_byte red
Definition: png.h:477
png_byte green
Definition: png.h:478
Definition: reader.h:84
Definition: send.c:48
Definition: parse.h:23
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
static BOOL initialized
Definition: syslog.c:39
rwlock_t lock
Definition: tcpcore.h:0
#define DWORD_PTR
Definition: treelist.c:76
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
Definition: pdh_main.c:94
int ret
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
WICBitmapEncoderCacheOption
Definition: wincodec.idl:69
WICPngFilterOption
Definition: wincodec.idl:179
@ WICPngFilterAdaptive
Definition: wincodec.idl:186
@ WICPngFilterUnspecified
Definition: wincodec.idl:180
WICDecodeOptions
Definition: wincodec.idl:27
@ WICDecodeMetadataCacheOnDemand
Definition: wincodec.idl:28
UINT32 WICColor
Definition: wincodec.idl:312
@ WICBitmapDecoderCapabilityCanDecodeSomeImages
Definition: wincodec.idl:50
@ WICBitmapDecoderCapabilityCanDecodeAllImages
Definition: wincodec.idl:49
static const char * debug_wic_rect(const WICRect *rect)
@ WICMetadataCreationAllowUnknown
Definition: wincodecsdk.idl:34
#define WINAPI
Definition: msvc.h:6
#define WINCODEC_ERR_WRONGSTATE
Definition: winerror.h:3281
#define WINCODEC_ERR_UNSUPPORTEDOPERATION
Definition: winerror.h:3308
#define WINCODEC_ERR_NOTINITIALIZED
Definition: winerror.h:3285
#define E_NOINTERFACE
Definition: winerror.h:2364
#define WINCODEC_ERR_PALETTEUNAVAILABLE
Definition: winerror.h:3292
#define WINCODEC_ERR_CODECNOTHUMBNAIL
Definition: winerror.h:3291
#define WINCODEC_ERR_UNKNOWNIMAGEFORMAT
Definition: winerror.h:3283
#define WINCODEC_ERR_FRAMEMISSING
Definition: winerror.h:3301
char * LPSTR
Definition: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
unsigned char BYTE
Definition: xxhash.c:193