ReactOS  0.4.14-dev-604-gcfdd483
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 
43 static inline ULONG read_ulong_be(BYTE* data)
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 
89 static 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;
98  LPSTR name, value;
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 
160 static 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 
222 static 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 
302 static void *libpng_handle;
303 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
304 MAKE_FUNCPTR(png_create_read_struct);
305 MAKE_FUNCPTR(png_create_info_struct);
306 MAKE_FUNCPTR(png_create_write_struct);
307 MAKE_FUNCPTR(png_destroy_read_struct);
308 MAKE_FUNCPTR(png_destroy_write_struct);
309 MAKE_FUNCPTR(png_error);
310 MAKE_FUNCPTR(png_get_bit_depth);
311 MAKE_FUNCPTR(png_get_color_type);
312 MAKE_FUNCPTR(png_get_error_ptr);
313 MAKE_FUNCPTR(png_get_iCCP);
314 MAKE_FUNCPTR(png_get_image_height);
315 MAKE_FUNCPTR(png_get_image_width);
317 MAKE_FUNCPTR(png_get_pHYs);
318 MAKE_FUNCPTR(png_get_PLTE);
319 MAKE_FUNCPTR(png_get_tRNS);
320 MAKE_FUNCPTR(png_set_bgr);
321 MAKE_FUNCPTR(png_set_crc_action);
322 MAKE_FUNCPTR(png_set_error_fn);
323 MAKE_FUNCPTR(png_set_filler);
324 MAKE_FUNCPTR(png_set_filter);
325 MAKE_FUNCPTR(png_set_gray_to_rgb);
326 MAKE_FUNCPTR(png_set_interlace_handling);
327 MAKE_FUNCPTR(png_set_IHDR);
328 MAKE_FUNCPTR(png_set_pHYs);
329 MAKE_FUNCPTR(png_set_PLTE);
330 MAKE_FUNCPTR(png_set_read_fn);
331 MAKE_FUNCPTR(png_set_strip_16);
332 MAKE_FUNCPTR(png_set_tRNS);
333 MAKE_FUNCPTR(png_set_tRNS_to_alpha);
334 MAKE_FUNCPTR(png_set_write_fn);
335 MAKE_FUNCPTR(png_set_swap);
336 MAKE_FUNCPTR(png_read_end);
337 MAKE_FUNCPTR(png_read_image);
338 MAKE_FUNCPTR(png_read_info);
339 MAKE_FUNCPTR(png_write_end);
340 MAKE_FUNCPTR(png_write_info);
341 MAKE_FUNCPTR(png_write_rows);
342 #undef MAKE_FUNCPTR
343 
344 static CRITICAL_SECTION init_png_cs;
345 static 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 };
352 static CRITICAL_SECTION init_png_cs = { &init_png_cs_debug, -1, 0, 0, 0, 0 };
353 
354 static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
355 static const WCHAR wszPngFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0};
356 
357 static 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 
420 static 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 
432 static 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 
437 typedef struct {
438  ULARGE_INTEGER ofs, len;
440 } metadata_block_info;
441 
442 typedef struct {
443  IWICBitmapDecoder IWICBitmapDecoder_iface;
444  IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
445  IWICMetadataBlockReader IWICMetadataBlockReader_iface;
446  LONG ref;
447  IStream *stream;
450  png_infop end_info;
452  int bpp;
453  int width, height;
454  UINT stride;
455  const WICPixelFormatGUID *format;
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 
462 static inline PngDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
463 {
464  return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapDecoder_iface);
465 }
466 
467 static inline PngDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
468 {
469  return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapFrameDecode_iface);
470 }
471 
472 static inline PngDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
473 {
474  return CONTAINING_RECORD(iface, PngDecoder, IWICMetadataBlockReader_iface);
475 }
476 
477 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl;
478 
479 static 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 
501 static 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 
511 static 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;
526  DeleteCriticalSection(&This->lock);
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 
540 static 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 
558 static 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 
571 static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
572  WICDecodeOptions cacheOptions)
573 {
574  PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
576  HRESULT hr=S_OK;
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;
585  jmp_buf jmpbuf;
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 
593  EnterCriticalSection(&This->lock);
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;
685  case PNG_COLOR_TYPE_GRAY:
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;
718  case PNG_COLOR_TYPE_RGB:
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  {
748  hr = E_OUTOFMEMORY;
749  goto end;
750  }
751 
752  row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
753  if (!row_pointers)
754  {
755  hr = E_OUTOFMEMORY;
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  {
795  hr = E_OUTOFMEMORY;
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 
821 end:
822  LeaveCriticalSection(&This->lock);
823 
824  HeapFree(GetProcessHeap(), 0, row_pointers);
825 
826  return hr;
827 }
828 
829 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
830  GUID *pguidContainerFormat)
831 {
832  memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
833  return S_OK;
834 }
835 
836 static 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 
844 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
846 {
847  TRACE("(%p,%p)\n", iface, palette);
849 }
850 
851 static 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 
862 static 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 
873 static 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 
880 static 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 
891 static 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 
900 static 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 
917 static 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 
934 static 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 
960 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
961 {
962  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
963  return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
964 }
965 
966 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
967 {
968  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
969  return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
970 }
971 
972 static 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 
982 static 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 
993 static 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 
1022 static 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 
1094 end:
1095 
1096  LeaveCriticalSection(&This->lock);
1097 
1098  if (SUCCEEDED(hr))
1099  hr = IWICPalette_InitializeCustom(pIPalette, palette, num_palette);
1100 
1101  return hr;
1102 }
1103 
1104 static 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 
1115 static 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 
1128 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
1129  UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1130 {
1131  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1132  png_charp name;
1133  BYTE *profile;
1134  png_uint_32 len;
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 
1165 static 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 
1176 static 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 
1190 static 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 
1197 static ULONG WINAPI PngDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1198 {
1199  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1200  return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1201 }
1202 
1203 static ULONG WINAPI PngDecoder_Block_Release(IWICMetadataBlockReader *iface)
1204 {
1205  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1206  return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1207 }
1208 
1209 static 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 
1217 static 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 
1231 static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1232  UINT nIndex, IWICMetadataReader **ppIMetadataReader)
1233 {
1234  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1235  HRESULT hr;
1237  IWICStream* stream;
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 
1281 static HRESULT WINAPI PngDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1282  IEnumUnknown **ppIEnumMetadata)
1283 {
1284  FIXME("%p,%p\n", iface, ppIEnumMetadata);
1285  return E_NOTIMPL;
1286 }
1287 
1288 static 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 
1337 struct 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 
1346 static 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 
1364 typedef 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 
1390 static inline PngEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1391 {
1392  return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapEncoder_iface);
1393 }
1394 
1395 static inline PngEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1396 {
1397  return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapFrameEncode_iface);
1398 }
1399 
1400 static 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 
1423 static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1424 {
1425  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1426  return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
1427 }
1428 
1429 static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface)
1430 {
1431  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1432  return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1433 }
1434 
1435 static 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);
1483  return WINCODEC_ERR_WRONGSTATE;
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 
1496 static 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);
1507  return WINCODEC_ERR_WRONGSTATE;
1508  }
1509 
1510  This->width = uiWidth;
1511  This->height = uiHeight;
1512 
1513  LeaveCriticalSection(&This->lock);
1514 
1515  return S_OK;
1516 }
1517 
1518 static 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);
1529  return WINCODEC_ERR_WRONGSTATE;
1530  }
1531 
1532  This->xres = dpiX;
1533  This->yres = dpiY;
1534 
1535  LeaveCriticalSection(&This->lock);
1536 
1537  return S_OK;
1538 }
1539 
1540 static 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);
1552  return WINCODEC_ERR_WRONGSTATE;
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 
1571 static 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 
1578 static 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 
1599 static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
1600  IWICBitmapSource *pIThumbnail)
1601 {
1602  FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1604 }
1605 
1606 static 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;
1612  jmp_buf jmpbuf;
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);
1620  return WINCODEC_ERR_WRONGSTATE;
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 
1758 static 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)
1766  return WINCODEC_ERR_WRONGSTATE;
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 
1781 static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1782 {
1783  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1784  png_byte **row_pointers=NULL;
1785  jmp_buf jmpbuf;
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);
1793  return WINCODEC_ERR_WRONGSTATE;
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 
1834 static HRESULT WINAPI PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1835  IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1836 {
1837  FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1838  return E_NOTIMPL;
1839 }
1840 
1841 static 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 
1858 static 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 
1881 static 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 
1891 static 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;
1901  DeleteCriticalSection(&This->lock);
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);
1907  HeapFree(GetProcessHeap(), 0, This);
1908  }
1909 
1910  return ref;
1911 }
1912 
1913 static 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 
1926 static void user_flush(png_structp png_ptr)
1927 {
1928 }
1929 
1930 static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface,
1931  IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1932 {
1933  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1934  jmp_buf jmpbuf;
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);
1943  return WINCODEC_ERR_WRONGSTATE;
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 
1986 static 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 
1997 static 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 
2015 static 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 
2022 static 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 
2038 static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
2039 {
2040  TRACE("(%p,%p)\n", iface, pIThumbnail);
2042 }
2043 
2044 static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
2045 {
2046  TRACE("(%p,%p)\n", iface, pIPreview);
2048 }
2049 
2050 static 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 
2097 static 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);
2107  return WINCODEC_ERR_WRONGSTATE;
2108  }
2109 
2110  This->committed = TRUE;
2111 
2112  LeaveCriticalSection(&This->lock);
2113 
2114  return S_OK;
2115 }
2116 
2117 static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
2118  IWICMetadataQueryWriter **ppIMetadataQueryWriter)
2119 {
2120  FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
2121  return E_NOTIMPL;
2122 }
2123 
2124 static 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
#define PNG_COLOR_TYPE_RGB_ALPHA
Definition: pngformat.c:701
GLint GLint GLsizei width
Definition: gl.h:1546
#define REFIID
Definition: guiddef.h:118
#define TRUE
Definition: types.h:120
#define E_NOINTERFACE
Definition: winerror.h:2364
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define PNG_FILTER_PAETH
Definition: png.h:1469
rwlock_t lock
Definition: tcpcore.h:1163
#define DWORD_PTR
Definition: treelist.c:76
const char * png_const_charp
Definition: pngconf.h:590
HRESULT hr
Definition: shlfolder.c:183
#define PNG_NO_FILTERS
Definition: png.h:1464
HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, REFIID iid, void **ppv)
#define memchr(s, c, n)
Definition: mkisofs.h:875
#define PNG_FILTER_SUB
Definition: png.h:1466
HRESULT PngTextReader_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:155
#define PNG_INTERLACE_NONE
Definition: png.h:687
#define WARN(fmt,...)
Definition: debug.h:111
static const struct pixel_format_desc formats[]
Definition: util.c:57
HRESULT PngGamaReader_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:217
#define PNG_COLOR_TYPE_GRAY
Definition: pngformat.c:697
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define PNG_INTERLACE_ADAM7
Definition: png.h:688
png_byte * png_bytep
Definition: pngconf.h:579
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
png_uint_16 gray
Definition: png.h:494
#define PNG_LIBPNG_VER_STRING
Definition: png.h:281
png_byte red
Definition: png.h:480
#define WINCODEC_ERR_NOTINITIALIZED
Definition: winerror.h:3277
GLuint GLuint end
Definition: gl.h:1545
char * png_charp
Definition: pngconf.h:589
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
char * LPSTR
Definition: xmlstorage.h:182
WICBitmapEncoderCacheOption
Definition: wincodec.idl:69
static LPOLESTR
Definition: stg_prop.c:27
#define lstrlenW
Definition: compat.h:415
#define E_FAIL
Definition: ddrawi.h:102
png_voidp PNGAPI png_get_io_ptr(png_const_structrp png_ptr)
Definition: png.c:686
HRESULT PngChrmReader_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:295
Definition: send.c:47
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLuint GLuint * names
Definition: glext.h:11545
static HRESULT LoadChrmMetadata(IStream *stream, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count)
Definition: pngformat.c:222
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
const GUID * guid
void error_message(HWND hwnd, const char *msg)
Definition: main.cpp:785
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
unsigned int BOOL
Definition: ntddk_ex.h:94
HRESULT write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, UINT bpp, INT width, INT height)
Definition: main.c:155
long LONG
Definition: pedump.c:60
Definition: main.c:438
static BmpFrameEncode * impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
Definition: bmpencode.c:84
#define WINCODEC_ERR_UNKNOWNIMAGEFORMAT
Definition: winerror.h:3275
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:110
#define PNG_COLOR_TYPE_RGB
Definition: pngformat.c:698
#define E_INVALIDARG
Definition: ddrawi.h:101
#define WINCODEC_ERR_PALETTEUNAVAILABLE
Definition: winerror.h:3284
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
smooth NULL
Definition: ftsmooth.c:416
void * wine_dlopen(const char *filename, int flag, char *error, size_t errorsize)
Definition: loader.c:53
static IWICImagingFactory * factory
Definition: pngformat.c:277
GLuint index
Definition: glext.h:6031
HRESULT ImagingFactory_CreateInstance(REFIID iid, void **ppv)
Definition: imgfactory.c:1470
#define debugstr_guid
Definition: kernel32.h:35
int longjmp(jmp_buf buf, int retval)
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
png_uint_32
Definition: png.h:1939
static HRESULT LoadGamaMetadata(IStream *stream, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count)
Definition: pngformat.c:160
GLuint GLfloat * val
Definition: glext.h:7180
HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
Definition: info.c:2075
#define PNG_FILTER_TYPE_DEFAULT
Definition: png.h:684
#define SONAME_LIBPNG
Definition: config.h:1257
#define LOAD_FUNCPTR(f)
#define TRACE(s)
Definition: solgame.cpp:4
GLsizei stride
Definition: glext.h:5848
#define GetProcessHeap()
Definition: compat.h:403
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define PNG_CRC_QUIET_USE
Definition: png.h:1440
__wchar_t WCHAR
Definition: xmlstorage.h:180
static BmpEncoder * impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
Definition: bmpencode.c:433
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define debugstr_a
Definition: kernel32.h:31
LONG HRESULT
Definition: typedefs.h:77
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
#define PNG_ALL_FILTERS
Definition: png.h:1471
const GUID IID_IUnknown
WICPngFilterOption
Definition: wincodec.idl:179
#define V_UI1(A)
Definition: oleauto.h:266
static BOOL initialized
Definition: syslog.c:39
#define WINAPI
Definition: msvc.h:6
static BmpDecoder * impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
Definition: bmpdecode.c:83
#define V_BOOL(A)
Definition: oleauto.h:224
#define for
Definition: utility.h:88
unsigned long DWORD
Definition: ntddk_ex.h:95
#define RTLD_NOW
Definition: port.h:100
png_const_structrp png_const_inforp info_ptr
Definition: png.h:1939
#define PNG_RESOLUTION_METER
Definition: png.h:711
#define WINCODEC_ERR_CODECNOTHUMBNAIL
Definition: winerror.h:3283
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define PNG_FILTER_UP
Definition: png.h:1467
#define PNG_FILTER_AVG
Definition: png.h:1468
int seek(void *fd, ulong off, int mode)
Definition: pe.c:51
int ret
#define WINCODEC_ERR_FRAMEMISSING
Definition: winerror.h:3293
#define InterlockedDecrement
Definition: armddk.h:52
Definition: parse.h:22
GLuint GLuint stream
Definition: glext.h:7522
static const char * debug_wic_rect(const WICRect *rect)
#define V_VT(A)
Definition: oleauto.h:211
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
#define WINCODEC_ERR_UNSUPPORTEDOPERATION
Definition: winerror.h:3300
LIST_ENTRY ProcessLocksList
Definition: winbase.h:855
GLsizei const GLfloat * value
Definition: glext.h:6069
static HPALETTE palette
Definition: clipboard.c:1345
HRESULT PngDecoder_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:2188
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
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:1601
png_structrp png_ptr
Definition: png.h:1083
HRESULT PngEncoder_CreateInstance(REFIID iid, void **ppv)
Definition: pngformat.c:2194
#define ERR(fmt,...)
Definition: debug.h:109
WICDecodeOptions
Definition: wincodec.idl:27
#define WINCODEC_ERR_WRONGSTATE
Definition: winerror.h:3273
#define S_OK
Definition: intsafe.h:59
static const MetadataHandlerVtbl TextReader_Vtbl
Definition: pngformat.c:149
static GpStatus get_decoder_info(IStream *stream, const struct image_codec **result)
Definition: image.c:4237
#define InterlockedIncrement
Definition: armddk.h:53
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
#define lstrcpyW
Definition: compat.h:414
static BmpDecoder * impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
Definition: bmpdecode.c:88
static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor, DWORD persist_options, MetadataItem **items, DWORD *item_count)
Definition: pngformat.c:89
HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count, IPropertyBag2 **ppPropertyBag2)
Definition: propertybag.c:281
#define PNG_COMPRESSION_TYPE_DEFAULT
Definition: png.h:679
#define ARRAY_SIZE(a)
Definition: main.h:24
#define E_NOTIMPL
Definition: ddrawi.h:99
static GifDecoder * impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
Definition: gifformat.c:607
#define MAKE_FUNCPTR(f)
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
const WCHAR * schema
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define setjmp
Definition: setjmp.h:183
#define PNG_FILLER_AFTER
Definition: png.h:1249
Definition: reader.h:83
size_t png_size_t
Definition: pngconf.h:523
static ULONG read_ulong_be(BYTE *data)
Definition: pngformat.c:43
Definition: name.c:38
GLclampf GLclampf GLclampf alpha
Definition: gl.h:1740
#define PNG_COLOR_TYPE_GRAY_ALPHA
Definition: pngformat.c:700
unsigned int ULONG
Definition: retypes.h:1
#define PNG_COLOR_TYPE_PALETTE
Definition: pngformat.c:699
static const MetadataHandlerVtbl GamaReader_Vtbl
Definition: pngformat.c:211
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs)
#define profile
Definition: kernel32.h:12
DWORD bpp
Definition: surface.c:181
#define PNG_FILTER_NONE
Definition: png.h:1465
HRESULT StreamImpl_Create(IWICStream **stream)
Definition: stream.c:1150
long jmp_buf[100]
Definition: of.h:11
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
static HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size)
Definition: pngformat.c:48
WCHAR * LPWSTR
Definition: xmlstorage.h:184
HRESULT MetadataQueryReader_CreateInstance(IWICMetadataBlockReader *mbr, const WCHAR *root, IWICMetadataQueryReader **out)
static TCHAR * items[]
Definition: page1.c:45
_Out_ LPRECT prc
Definition: ntgdi.h:1658
GLuint64EXT * result
Definition: glext.h:11304
static jmp_buf jmpbuf
Definition: NtContinue.c:20
UINT32 WICColor
Definition: wincodec.idl:250
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005
#define HeapFree(x, y, z)
Definition: compat.h:402
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
png_byte green
Definition: png.h:481
static const MetadataHandlerVtbl ChrmReader_Vtbl
Definition: pngformat.c:289
#define SUCCEEDED(hr)
Definition: intsafe.h:57
png_byte blue
Definition: png.h:482
static GLint image_size(GLint width, GLint height, GLenum format, GLenum type)
Definition: mipmap.c:4856
GLuint const GLchar * name
Definition: glext.h:6031