ReactOS  0.4.14-dev-52-g6116262
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_read_end);
336 MAKE_FUNCPTR(png_read_image);
337 MAKE_FUNCPTR(png_read_info);
338 MAKE_FUNCPTR(png_write_end);
339 MAKE_FUNCPTR(png_write_info);
340 MAKE_FUNCPTR(png_write_rows);
341 #undef MAKE_FUNCPTR
342 
343 static CRITICAL_SECTION init_png_cs;
344 static CRITICAL_SECTION_DEBUG init_png_cs_debug =
345 {
346  0, 0, &init_png_cs,
347  { &init_png_cs_debug.ProcessLocksList,
348  &init_png_cs_debug.ProcessLocksList },
349  0, 0, { (DWORD_PTR)(__FILE__ ": init_png_cs") }
350 };
351 static CRITICAL_SECTION init_png_cs = { &init_png_cs_debug, -1, 0, 0, 0, 0 };
352 
353 static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
354 static const WCHAR wszPngFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0};
355 
356 static void *load_libpng(void)
357 {
358  void *result;
359 
360  EnterCriticalSection(&init_png_cs);
361 
362  if(!libpng_handle && (libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
363 
364 #define LOAD_FUNCPTR(f) \
365  if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
366  libpng_handle = NULL; \
367  LeaveCriticalSection(&init_png_cs); \
368  return NULL; \
369  }
370  LOAD_FUNCPTR(png_create_read_struct);
371  LOAD_FUNCPTR(png_create_info_struct);
372  LOAD_FUNCPTR(png_create_write_struct);
373  LOAD_FUNCPTR(png_destroy_read_struct);
374  LOAD_FUNCPTR(png_destroy_write_struct);
375  LOAD_FUNCPTR(png_error);
376  LOAD_FUNCPTR(png_get_bit_depth);
377  LOAD_FUNCPTR(png_get_color_type);
378  LOAD_FUNCPTR(png_get_error_ptr);
379  LOAD_FUNCPTR(png_get_iCCP);
380  LOAD_FUNCPTR(png_get_image_height);
381  LOAD_FUNCPTR(png_get_image_width);
383  LOAD_FUNCPTR(png_get_pHYs);
384  LOAD_FUNCPTR(png_get_PLTE);
385  LOAD_FUNCPTR(png_get_tRNS);
386  LOAD_FUNCPTR(png_set_bgr);
387  LOAD_FUNCPTR(png_set_crc_action);
388  LOAD_FUNCPTR(png_set_error_fn);
389  LOAD_FUNCPTR(png_set_filler);
390  LOAD_FUNCPTR(png_set_filter);
391  LOAD_FUNCPTR(png_set_gray_to_rgb);
392  LOAD_FUNCPTR(png_set_interlace_handling);
393  LOAD_FUNCPTR(png_set_IHDR);
394  LOAD_FUNCPTR(png_set_pHYs);
395  LOAD_FUNCPTR(png_set_PLTE);
396  LOAD_FUNCPTR(png_set_read_fn);
397  LOAD_FUNCPTR(png_set_strip_16);
398  LOAD_FUNCPTR(png_set_tRNS);
399  LOAD_FUNCPTR(png_set_tRNS_to_alpha);
400  LOAD_FUNCPTR(png_set_write_fn);
401  LOAD_FUNCPTR(png_read_end);
402  LOAD_FUNCPTR(png_read_image);
403  LOAD_FUNCPTR(png_read_info);
404  LOAD_FUNCPTR(png_write_end);
405  LOAD_FUNCPTR(png_write_info);
406  LOAD_FUNCPTR(png_write_rows);
407 
408 #undef LOAD_FUNCPTR
409  }
410 
411  result = libpng_handle;
412 
413  LeaveCriticalSection(&init_png_cs);
414 
415  return result;
416 }
417 
418 static void user_error_fn(png_structp png_ptr, png_const_charp error_message)
419 {
420  jmp_buf *pjmpbuf;
421 
422  /* This uses setjmp/longjmp just like the default. We can't use the
423  * default because there's no way to access the jmp buffer in the png_struct
424  * that works in 1.2 and 1.4 and allows us to dynamically load libpng. */
425  WARN("PNG error: %s\n", debugstr_a(error_message));
426  pjmpbuf = ppng_get_error_ptr(png_ptr);
427  longjmp(*pjmpbuf, 1);
428 }
429 
430 static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message)
431 {
432  WARN("PNG warning: %s\n", debugstr_a(warning_message));
433 }
434 
435 typedef struct {
436  ULARGE_INTEGER ofs, len;
438 } metadata_block_info;
439 
440 typedef struct {
441  IWICBitmapDecoder IWICBitmapDecoder_iface;
442  IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
443  IWICMetadataBlockReader IWICMetadataBlockReader_iface;
444  LONG ref;
445  IStream *stream;
448  png_infop end_info;
450  int bpp;
451  int width, height;
452  UINT stride;
453  const WICPixelFormatGUID *format;
454  BYTE *image_bits;
455  CRITICAL_SECTION lock; /* must be held when png structures are accessed or initialized is set */
456  ULONG metadata_count;
457  metadata_block_info* metadata_blocks;
458 } PngDecoder;
459 
460 static inline PngDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
461 {
462  return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapDecoder_iface);
463 }
464 
465 static inline PngDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
466 {
467  return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapFrameDecode_iface);
468 }
469 
470 static inline PngDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
471 {
472  return CONTAINING_RECORD(iface, PngDecoder, IWICMetadataBlockReader_iface);
473 }
474 
475 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl;
476 
477 static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
478  void **ppv)
479 {
480  PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
481  TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
482 
483  if (!ppv) return E_INVALIDARG;
484 
485  if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
486  {
487  *ppv = &This->IWICBitmapDecoder_iface;
488  }
489  else
490  {
491  *ppv = NULL;
492  return E_NOINTERFACE;
493  }
494 
495  IUnknown_AddRef((IUnknown*)*ppv);
496  return S_OK;
497 }
498 
499 static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface)
500 {
501  PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
503 
504  TRACE("(%p) refcount=%u\n", iface, ref);
505 
506  return ref;
507 }
508 
509 static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
510 {
511  PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
513  ULONG i;
514 
515  TRACE("(%p) refcount=%u\n", iface, ref);
516 
517  if (ref == 0)
518  {
519  if (This->stream)
520  IStream_Release(This->stream);
521  if (This->png_ptr)
522  ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
523  This->lock.DebugInfo->Spare[0] = 0;
524  DeleteCriticalSection(&This->lock);
525  HeapFree(GetProcessHeap(), 0, This->image_bits);
526  for (i=0; i<This->metadata_count; i++)
527  {
528  if (This->metadata_blocks[i].reader)
529  IWICMetadataReader_Release(This->metadata_blocks[i].reader);
530  }
531  HeapFree(GetProcessHeap(), 0, This->metadata_blocks);
533  }
534 
535  return ref;
536 }
537 
538 static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
539  DWORD *capability)
540 {
541  HRESULT hr;
542 
543  TRACE("(%p,%p,%p)\n", iface, stream, capability);
544 
545  if (!stream || !capability) return E_INVALIDARG;
546 
547  hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
548  if (hr != S_OK) return hr;
549 
552  /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
553  return S_OK;
554 }
555 
556 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
557 {
558  IStream *stream = ppng_get_io_ptr(png_ptr);
559  HRESULT hr;
560  ULONG bytesread;
561 
562  hr = IStream_Read(stream, data, length, &bytesread);
563  if (FAILED(hr) || bytesread != length)
564  {
565  ppng_error(png_ptr, "failed reading data");
566  }
567 }
568 
569 static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
570  WICDecodeOptions cacheOptions)
571 {
572  PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
574  HRESULT hr=S_OK;
575  png_bytep *row_pointers=NULL;
577  UINT i;
578  int color_type, bit_depth;
579  png_bytep trans;
580  int num_trans;
581  png_uint_32 transparency;
582  png_color_16p trans_values;
583  jmp_buf jmpbuf;
584  BYTE chunk_type[4];
585  ULONG chunk_size;
586  ULARGE_INTEGER chunk_start;
587  ULONG metadata_blocks_size = 0;
588 
589  TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
590 
591  EnterCriticalSection(&This->lock);
592 
593  /* initialize libpng */
594  This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
595  if (!This->png_ptr)
596  {
597  hr = E_FAIL;
598  goto end;
599  }
600 
601  This->info_ptr = ppng_create_info_struct(This->png_ptr);
602  if (!This->info_ptr)
603  {
604  ppng_destroy_read_struct(&This->png_ptr, NULL, NULL);
605  This->png_ptr = NULL;
606  hr = E_FAIL;
607  goto end;
608  }
609 
610  This->end_info = ppng_create_info_struct(This->png_ptr);
611  if (!This->end_info)
612  {
613  ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL);
614  This->png_ptr = NULL;
615  hr = E_FAIL;
616  goto end;
617  }
618 
619  /* set up setjmp/longjmp error handling */
620  if (setjmp(jmpbuf))
621  {
622  ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
623  HeapFree(GetProcessHeap(), 0, row_pointers);
624  This->png_ptr = NULL;
626  goto end;
627  }
628  ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
629  ppng_set_crc_action(This->png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
630 
631  /* seek to the start of the stream */
632  seek.QuadPart = 0;
633  hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
634  if (FAILED(hr)) goto end;
635 
636  /* set up custom i/o handling */
637  ppng_set_read_fn(This->png_ptr, pIStream, user_read_data);
638 
639  /* read the header */
640  ppng_read_info(This->png_ptr, This->info_ptr);
641 
642  /* choose a pixel format */
643  color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
644  bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
645 
646  /* check for color-keyed alpha */
647  transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
648 
649  if (transparency && (color_type == PNG_COLOR_TYPE_RGB ||
650  (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)))
651  {
652  /* expand to RGBA */
653  if (color_type == PNG_COLOR_TYPE_GRAY)
654  ppng_set_gray_to_rgb(This->png_ptr);
655  ppng_set_tRNS_to_alpha(This->png_ptr);
656  color_type = PNG_COLOR_TYPE_RGB_ALPHA;
657  }
658 
659  switch (color_type)
660  {
662  /* WIC does not support grayscale alpha formats so use RGBA */
663  ppng_set_gray_to_rgb(This->png_ptr);
664  /* fall through */
666  This->bpp = bit_depth * 4;
667  switch (bit_depth)
668  {
669  case 8:
670  ppng_set_bgr(This->png_ptr);
671  This->format = &GUID_WICPixelFormat32bppBGRA;
672  break;
673  case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break;
674  default:
675  ERR("invalid RGBA bit depth: %i\n", bit_depth);
676  hr = E_FAIL;
677  goto end;
678  }
679  break;
680  case PNG_COLOR_TYPE_GRAY:
681  This->bpp = bit_depth;
682  if (!transparency)
683  {
684  switch (bit_depth)
685  {
686  case 1: This->format = &GUID_WICPixelFormatBlackWhite; break;
687  case 2: This->format = &GUID_WICPixelFormat2bppGray; break;
688  case 4: This->format = &GUID_WICPixelFormat4bppGray; break;
689  case 8: This->format = &GUID_WICPixelFormat8bppGray; break;
690  case 16: This->format = &GUID_WICPixelFormat16bppGray; break;
691  default:
692  ERR("invalid grayscale bit depth: %i\n", bit_depth);
693  hr = E_FAIL;
694  goto end;
695  }
696  break;
697  }
698  /* else fall through */
700  This->bpp = bit_depth;
701  switch (bit_depth)
702  {
703  case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break;
704  case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break;
705  case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break;
706  case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break;
707  default:
708  ERR("invalid indexed color bit depth: %i\n", bit_depth);
709  hr = E_FAIL;
710  goto end;
711  }
712  break;
713  case PNG_COLOR_TYPE_RGB:
714  This->bpp = bit_depth * 3;
715  switch (bit_depth)
716  {
717  case 8:
718  ppng_set_bgr(This->png_ptr);
719  This->format = &GUID_WICPixelFormat24bppBGR;
720  break;
721  case 16: This->format = &GUID_WICPixelFormat48bppRGB; break;
722  default:
723  ERR("invalid RGB color bit depth: %i\n", bit_depth);
724  hr = E_FAIL;
725  goto end;
726  }
727  break;
728  default:
729  ERR("invalid color type %i\n", color_type);
730  hr = E_FAIL;
731  goto end;
732  }
733 
734  /* read the image data */
735  This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
736  This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
737  This->stride = (This->width * This->bpp + 7) / 8;
738  image_size = This->stride * This->height;
739 
740  This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size);
741  if (!This->image_bits)
742  {
743  hr = E_OUTOFMEMORY;
744  goto end;
745  }
746 
747  row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
748  if (!row_pointers)
749  {
750  hr = E_OUTOFMEMORY;
751  goto end;
752  }
753 
754  for (i=0; i<This->height; i++)
755  row_pointers[i] = This->image_bits + i * This->stride;
756 
757  ppng_read_image(This->png_ptr, row_pointers);
758 
759  HeapFree(GetProcessHeap(), 0, row_pointers);
760  row_pointers = NULL;
761 
762  ppng_read_end(This->png_ptr, This->end_info);
763 
764  /* Find the metadata chunks in the file. */
765  seek.QuadPart = 8;
766 
767  do
768  {
769  hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, &chunk_start);
770  if (FAILED(hr)) goto end;
771 
772  hr = read_png_chunk(pIStream, chunk_type, NULL, &chunk_size);
773  if (FAILED(hr)) goto end;
774 
775  if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
776  memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
777  {
778  /* This chunk is considered metadata. */
779  if (This->metadata_count == metadata_blocks_size)
780  {
781  metadata_block_info* new_metadata_blocks;
782  ULONG new_metadata_blocks_size;
783 
784  new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
785  new_metadata_blocks = HeapAlloc(GetProcessHeap(), 0,
786  new_metadata_blocks_size * sizeof(*new_metadata_blocks));
787 
788  if (!new_metadata_blocks)
789  {
790  hr = E_OUTOFMEMORY;
791  goto end;
792  }
793 
794  memcpy(new_metadata_blocks, This->metadata_blocks,
795  This->metadata_count * sizeof(*new_metadata_blocks));
796 
797  HeapFree(GetProcessHeap(), 0, This->metadata_blocks);
798  This->metadata_blocks = new_metadata_blocks;
799  metadata_blocks_size = new_metadata_blocks_size;
800  }
801 
802  This->metadata_blocks[This->metadata_count].ofs = chunk_start;
803  This->metadata_blocks[This->metadata_count].len.QuadPart = chunk_size + 12;
804  This->metadata_blocks[This->metadata_count].reader = NULL;
805  This->metadata_count++;
806  }
807 
808  seek.QuadPart = chunk_start.QuadPart + chunk_size + 12; /* skip data and CRC */
809  } while (memcmp(chunk_type, "IEND", 4));
810 
811  This->stream = pIStream;
812  IStream_AddRef(This->stream);
813 
814  This->initialized = TRUE;
815 
816 end:
817  LeaveCriticalSection(&This->lock);
818 
819  return hr;
820 }
821 
822 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
823  GUID *pguidContainerFormat)
824 {
825  memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
826  return S_OK;
827 }
828 
829 static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
830  IWICBitmapDecoderInfo **ppIDecoderInfo)
831 {
832  TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
833 
834  return get_decoder_info(&CLSID_WICPngDecoder, ppIDecoderInfo);
835 }
836 
837 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
839 {
840  TRACE("(%p,%p)\n", iface, palette);
842 }
843 
844 static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
846 {
847  TRACE("(%p,%p)\n", iface, reader);
848 
849  if (!reader) return E_INVALIDARG;
850 
851  *reader = NULL;
853 }
854 
855 static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface,
856  IWICBitmapSource **ppIBitmapSource)
857 {
858  TRACE("(%p,%p)\n", iface, ppIBitmapSource);
859 
860  if (!ppIBitmapSource) return E_INVALIDARG;
861 
862  *ppIBitmapSource = NULL;
864 }
865 
866 static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface,
867  UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
868 {
869  TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
871 }
872 
873 static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface,
874  IWICBitmapSource **ppIThumbnail)
875 {
876  TRACE("(%p,%p)\n", iface, ppIThumbnail);
877 
878  if (!ppIThumbnail) return E_INVALIDARG;
879 
880  *ppIThumbnail = NULL;
882 }
883 
884 static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface,
885  UINT *pCount)
886 {
887  if (!pCount) return E_INVALIDARG;
888 
889  *pCount = 1;
890  return S_OK;
891 }
892 
893 static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface,
894  UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
895 {
896  PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
897  TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
898 
899  if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
900 
901  if (index != 0) return E_INVALIDARG;
902 
903  IWICBitmapDecoder_AddRef(iface);
904 
905  *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
906 
907  return S_OK;
908 }
909 
910 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = {
911  PngDecoder_QueryInterface,
912  PngDecoder_AddRef,
913  PngDecoder_Release,
914  PngDecoder_QueryCapability,
915  PngDecoder_Initialize,
916  PngDecoder_GetContainerFormat,
917  PngDecoder_GetDecoderInfo,
918  PngDecoder_CopyPalette,
919  PngDecoder_GetMetadataQueryReader,
920  PngDecoder_GetPreview,
921  PngDecoder_GetColorContexts,
922  PngDecoder_GetThumbnail,
923  PngDecoder_GetFrameCount,
924  PngDecoder_GetFrame
925 };
926 
927 static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
928  void **ppv)
929 {
930  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
931  if (!ppv) return E_INVALIDARG;
932 
933  if (IsEqualIID(&IID_IUnknown, iid) ||
934  IsEqualIID(&IID_IWICBitmapSource, iid) ||
935  IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
936  {
937  *ppv = &This->IWICBitmapFrameDecode_iface;
938  }
939  else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
940  {
941  *ppv = &This->IWICMetadataBlockReader_iface;
942  }
943  else
944  {
945  *ppv = NULL;
946  return E_NOINTERFACE;
947  }
948 
949  IUnknown_AddRef((IUnknown*)*ppv);
950  return S_OK;
951 }
952 
953 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
954 {
955  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
956  return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
957 }
958 
959 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
960 {
961  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
962  return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
963 }
964 
965 static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
966  UINT *puiWidth, UINT *puiHeight)
967 {
968  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
969  *puiWidth = This->width;
970  *puiHeight = This->height;
971  TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
972  return S_OK;
973 }
974 
975 static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
976  WICPixelFormatGUID *pPixelFormat)
977 {
978  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
979  TRACE("(%p,%p)\n", iface, pPixelFormat);
980 
981  memcpy(pPixelFormat, This->format, sizeof(GUID));
982 
983  return S_OK;
984 }
985 
986 static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
987  double *pDpiX, double *pDpiY)
988 {
989  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
990  png_uint_32 ret, xres, yres;
991  int unit_type;
992 
993  EnterCriticalSection(&This->lock);
994 
995  ret = ppng_get_pHYs(This->png_ptr, This->info_ptr, &xres, &yres, &unit_type);
996 
997  if (ret && unit_type == PNG_RESOLUTION_METER)
998  {
999  *pDpiX = xres * 0.0254;
1000  *pDpiY = yres * 0.0254;
1001  }
1002  else
1003  {
1004  WARN("no pHYs block present\n");
1005  *pDpiX = *pDpiY = 96.0;
1006  }
1007 
1008  LeaveCriticalSection(&This->lock);
1009 
1010  TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
1011 
1012  return S_OK;
1013 }
1014 
1015 static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
1016  IWICPalette *pIPalette)
1017 {
1018  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1019  png_uint_32 ret, color_type, bit_depth;
1020  png_colorp png_palette;
1021  int num_palette;
1022  WICColor palette[256];
1023  png_bytep trans_alpha;
1024  int num_trans;
1025  png_color_16p trans_values;
1026  int i;
1027  HRESULT hr=S_OK;
1028 
1029  TRACE("(%p,%p)\n", iface, pIPalette);
1030 
1031  EnterCriticalSection(&This->lock);
1032 
1033  color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
1034  bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
1035 
1036  if (color_type == PNG_COLOR_TYPE_PALETTE)
1037  {
1038  ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette);
1039  if (!ret)
1040  {
1042  goto end;
1043  }
1044 
1045  if (num_palette > 256)
1046  {
1047  ERR("palette has %i colors?!\n", num_palette);
1048  hr = E_FAIL;
1049  goto end;
1050  }
1051 
1052  ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans_alpha, &num_trans, &trans_values);
1053  if (!ret) num_trans = 0;
1054 
1055  for (i=0; i<num_palette; i++)
1056  {
1057  BYTE alpha = (i < num_trans) ? trans_alpha[i] : 0xff;
1058  palette[i] = (alpha << 24 |
1059  png_palette[i].red << 16|
1060  png_palette[i].green << 8|
1061  png_palette[i].blue);
1062  }
1063  }
1064  else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth <= 8) {
1065  ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans_alpha, &num_trans, &trans_values);
1066 
1067  if (!ret)
1068  {
1070  goto end;
1071  }
1072 
1073  num_palette = 1 << bit_depth;
1074 
1075  for (i=0; i<num_palette; i++)
1076  {
1077  BYTE alpha = (i == trans_values[0].gray) ? 0 : 0xff;
1078  BYTE val = i * 255 / (num_palette - 1);
1079  palette[i] = (alpha << 24 | val << 16 | val << 8 | val);
1080  }
1081  }
1082  else
1083  {
1085  }
1086 
1087 end:
1088 
1089  LeaveCriticalSection(&This->lock);
1090 
1091  if (SUCCEEDED(hr))
1092  hr = IWICPalette_InitializeCustom(pIPalette, palette, num_palette);
1093 
1094  return hr;
1095 }
1096 
1097 static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
1098  const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1099 {
1100  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1101  TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1102 
1103  return copy_pixels(This->bpp, This->image_bits,
1104  This->width, This->height, This->stride,
1105  prc, cbStride, cbBufferSize, pbBuffer);
1106 }
1107 
1108 static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
1109  IWICMetadataQueryReader **ppIMetadataQueryReader)
1110 {
1111  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1112 
1113  TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1114 
1115  if (!ppIMetadataQueryReader)
1116  return E_INVALIDARG;
1117 
1118  return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
1119 }
1120 
1121 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
1122  UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1123 {
1124  PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
1125  png_charp name;
1126  BYTE *profile;
1127  png_uint_32 len;
1128  int compression_type;
1129  HRESULT hr;
1130 
1131  TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1132 
1133  if (!pcActualCount) return E_INVALIDARG;
1134 
1135  EnterCriticalSection(&This->lock);
1136 
1137  if (ppng_get_iCCP(This->png_ptr, This->info_ptr, &name, &compression_type, (void *)&profile, &len))
1138  {
1139  if (cCount && ppIColorContexts)
1140  {
1141  hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, len);
1142  if (FAILED(hr))
1143  {
1144  LeaveCriticalSection(&This->lock);
1145  return hr;
1146  }
1147  }
1148  *pcActualCount = 1;
1149  }
1150  else
1151  *pcActualCount = 0;
1152 
1153  LeaveCriticalSection(&This->lock);
1154 
1155  return S_OK;
1156 }
1157 
1158 static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
1159  IWICBitmapSource **ppIThumbnail)
1160 {
1161  TRACE("(%p,%p)\n", iface, ppIThumbnail);
1162 
1163  if (!ppIThumbnail) return E_INVALIDARG;
1164 
1165  *ppIThumbnail = NULL;
1167 }
1168 
1169 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = {
1170  PngDecoder_Frame_QueryInterface,
1171  PngDecoder_Frame_AddRef,
1172  PngDecoder_Frame_Release,
1173  PngDecoder_Frame_GetSize,
1174  PngDecoder_Frame_GetPixelFormat,
1175  PngDecoder_Frame_GetResolution,
1176  PngDecoder_Frame_CopyPalette,
1177  PngDecoder_Frame_CopyPixels,
1178  PngDecoder_Frame_GetMetadataQueryReader,
1179  PngDecoder_Frame_GetColorContexts,
1180  PngDecoder_Frame_GetThumbnail
1181 };
1182 
1183 static HRESULT WINAPI PngDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid,
1184  void **ppv)
1185 {
1186  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1187  return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
1188 }
1189 
1190 static ULONG WINAPI PngDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1191 {
1192  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1193  return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1194 }
1195 
1196 static ULONG WINAPI PngDecoder_Block_Release(IWICMetadataBlockReader *iface)
1197 {
1198  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1199  return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1200 }
1201 
1202 static HRESULT WINAPI PngDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1203  GUID *pguidContainerFormat)
1204 {
1205  if (!pguidContainerFormat) return E_INVALIDARG;
1206  memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
1207  return S_OK;
1208 }
1209 
1210 static HRESULT WINAPI PngDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1211  UINT *pcCount)
1212 {
1213  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1214 
1215  TRACE("%p,%p\n", iface, pcCount);
1216 
1217  if (!pcCount) return E_INVALIDARG;
1218 
1219  *pcCount = This->metadata_count;
1220 
1221  return S_OK;
1222 }
1223 
1224 static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1225  UINT nIndex, IWICMetadataReader **ppIMetadataReader)
1226 {
1227  PngDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1228  HRESULT hr;
1230  IWICStream* stream;
1231 
1232  TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader);
1233 
1234  if (nIndex >= This->metadata_count || !ppIMetadataReader)
1235  return E_INVALIDARG;
1236 
1237  if (!This->metadata_blocks[nIndex].reader)
1238  {
1240 
1241  if (SUCCEEDED(hr))
1242  {
1243  hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream,
1244  This->metadata_blocks[nIndex].ofs, This->metadata_blocks[nIndex].len);
1245 
1246  if (SUCCEEDED(hr))
1247  hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory);
1248 
1249  if (SUCCEEDED(hr))
1250  {
1251  hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1252  &GUID_ContainerFormatPng, NULL, WICMetadataCreationAllowUnknown,
1253  (IStream*)stream, &This->metadata_blocks[nIndex].reader);
1254 
1255  IWICComponentFactory_Release(factory);
1256  }
1257 
1258  IWICStream_Release(stream);
1259  }
1260 
1261  if (FAILED(hr))
1262  {
1263  *ppIMetadataReader = NULL;
1264  return hr;
1265  }
1266  }
1267 
1268  *ppIMetadataReader = This->metadata_blocks[nIndex].reader;
1269  IWICMetadataReader_AddRef(*ppIMetadataReader);
1270 
1271  return S_OK;
1272 }
1273 
1274 static HRESULT WINAPI PngDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1275  IEnumUnknown **ppIEnumMetadata)
1276 {
1277  FIXME("%p,%p\n", iface, ppIEnumMetadata);
1278  return E_NOTIMPL;
1279 }
1280 
1281 static const IWICMetadataBlockReaderVtbl PngDecoder_BlockVtbl = {
1282  PngDecoder_Block_QueryInterface,
1283  PngDecoder_Block_AddRef,
1284  PngDecoder_Block_Release,
1285  PngDecoder_Block_GetContainerFormat,
1286  PngDecoder_Block_GetCount,
1287  PngDecoder_Block_GetReaderByIndex,
1288  PngDecoder_Block_GetEnumerator,
1289 };
1290 
1292 {
1293  PngDecoder *This;
1294  HRESULT ret;
1295 
1296  TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1297 
1298  *ppv = NULL;
1299 
1300  if (!load_libpng())
1301  {
1302  ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1303  return E_FAIL;
1304  }
1305 
1306  This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder));
1307  if (!This) return E_OUTOFMEMORY;
1308 
1309  This->IWICBitmapDecoder_iface.lpVtbl = &PngDecoder_Vtbl;
1310  This->IWICBitmapFrameDecode_iface.lpVtbl = &PngDecoder_FrameVtbl;
1311  This->IWICMetadataBlockReader_iface.lpVtbl = &PngDecoder_BlockVtbl;
1312  This->ref = 1;
1313  This->png_ptr = NULL;
1314  This->info_ptr = NULL;
1315  This->end_info = NULL;
1316  This->stream = NULL;
1317  This->initialized = FALSE;
1318  This->image_bits = NULL;
1320  This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngDecoder.lock");
1321  This->metadata_count = 0;
1322  This->metadata_blocks = NULL;
1323 
1324  ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1325  IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1326 
1327  return ret;
1328 }
1329 
1330 struct png_pixelformat {
1331  const WICPixelFormatGUID *guid;
1332  UINT bpp;
1333  int bit_depth;
1334  int color_type;
1335  BOOL remove_filler;
1336  BOOL swap_rgb;
1337 };
1338 
1339 static const struct png_pixelformat formats[] = {
1340  {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
1341  {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
1342  {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
1343  {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
1344  {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
1345  {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
1346  {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
1347  {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
1348  {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
1349  {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
1350  {&GUID_WICPixelFormat1bppIndexed, 1, 1, PNG_COLOR_TYPE_PALETTE, 0, 0},
1351  {&GUID_WICPixelFormat2bppIndexed, 2, 2, PNG_COLOR_TYPE_PALETTE, 0, 0},
1352  {&GUID_WICPixelFormat4bppIndexed, 4, 4, PNG_COLOR_TYPE_PALETTE, 0, 0},
1353  {&GUID_WICPixelFormat8bppIndexed, 8, 8, PNG_COLOR_TYPE_PALETTE, 0, 0},
1354  {NULL},
1355 };
1356 
1357 typedef struct PngEncoder {
1358  IWICBitmapEncoder IWICBitmapEncoder_iface;
1359  IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1360  LONG ref;
1361  IStream *stream;
1364  UINT frame_count;
1365  BOOL frame_initialized;
1366  const struct png_pixelformat *format;
1367  BOOL info_written;
1368  UINT width, height;
1369  double xres, yres;
1370  UINT lines_written;
1371  BOOL frame_committed;
1372  BOOL committed;
1374  BOOL interlace;
1376  BYTE *data;
1377  UINT stride;
1378  UINT passes;
1379  WICColor palette[256];
1380  UINT colors;
1381 } PngEncoder;
1382 
1383 static inline PngEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1384 {
1385  return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapEncoder_iface);
1386 }
1387 
1388 static inline PngEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1389 {
1390  return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapFrameEncode_iface);
1391 }
1392 
1393 static HRESULT WINAPI PngFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
1394  void **ppv)
1395 {
1396  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1397  TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1398 
1399  if (!ppv) return E_INVALIDARG;
1400 
1401  if (IsEqualIID(&IID_IUnknown, iid) ||
1402  IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1403  {
1404  *ppv = &This->IWICBitmapFrameEncode_iface;
1405  }
1406  else
1407  {
1408  *ppv = NULL;
1409  return E_NOINTERFACE;
1410  }
1411 
1412  IUnknown_AddRef((IUnknown*)*ppv);
1413  return S_OK;
1414 }
1415 
1416 static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1417 {
1418  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1419  return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
1420 }
1421 
1422 static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface)
1423 {
1424  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1425  return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
1426 }
1427 
1428 static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
1429  IPropertyBag2 *pIEncoderOptions)
1430 {
1431  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1433  BOOL interlace;
1434  PROPBAG2 opts[2]= {{0}};
1435  VARIANT opt_values[2];
1436  HRESULT opt_hres[2];
1437  HRESULT hr;
1438 
1439  TRACE("(%p,%p)\n", iface, pIEncoderOptions);
1440 
1441  opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption;
1442  opts[0].vt = VT_BOOL;
1443  opts[1].pstrName = (LPOLESTR)wszPngFilterOption;
1444  opts[1].vt = VT_UI1;
1445 
1446  if (pIEncoderOptions)
1447  {
1448  hr = IPropertyBag2_Read(pIEncoderOptions, ARRAY_SIZE(opts), opts, NULL, opt_values, opt_hres);
1449 
1450  if (FAILED(hr))
1451  return hr;
1452 
1453  if (V_VT(&opt_values[0]) == VT_EMPTY)
1454  interlace = FALSE;
1455  else
1456  interlace = (V_BOOL(&opt_values[0]) != 0);
1457 
1458  filter = V_UI1(&opt_values[1]);
1460  {
1461  WARN("Unrecognized filter option value %u.\n", filter);
1463  }
1464  }
1465  else
1466  {
1467  interlace = FALSE;
1469  }
1470 
1471  EnterCriticalSection(&This->lock);
1472 
1473  if (This->frame_initialized)
1474  {
1475  LeaveCriticalSection(&This->lock);
1476  return WINCODEC_ERR_WRONGSTATE;
1477  }
1478 
1479  This->interlace = interlace;
1480  This->filter = filter;
1481 
1482  This->frame_initialized = TRUE;
1483 
1484  LeaveCriticalSection(&This->lock);
1485 
1486  return S_OK;
1487 }
1488 
1489 static HRESULT WINAPI PngFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
1490  UINT uiWidth, UINT uiHeight)
1491 {
1492  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1493  TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
1494 
1495  EnterCriticalSection(&This->lock);
1496 
1497  if (!This->frame_initialized || This->info_written)
1498  {
1499  LeaveCriticalSection(&This->lock);
1500  return WINCODEC_ERR_WRONGSTATE;
1501  }
1502 
1503  This->width = uiWidth;
1504  This->height = uiHeight;
1505 
1506  LeaveCriticalSection(&This->lock);
1507 
1508  return S_OK;
1509 }
1510 
1511 static HRESULT WINAPI PngFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
1512  double dpiX, double dpiY)
1513 {
1514  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1515  TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
1516 
1517  EnterCriticalSection(&This->lock);
1518 
1519  if (!This->frame_initialized || This->info_written)
1520  {
1521  LeaveCriticalSection(&This->lock);
1522  return WINCODEC_ERR_WRONGSTATE;
1523  }
1524 
1525  This->xres = dpiX;
1526  This->yres = dpiY;
1527 
1528  LeaveCriticalSection(&This->lock);
1529 
1530  return S_OK;
1531 }
1532 
1533 static HRESULT WINAPI PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
1534  WICPixelFormatGUID *pPixelFormat)
1535 {
1536  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1537  int i;
1538  TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
1539 
1540  EnterCriticalSection(&This->lock);
1541 
1542  if (!This->frame_initialized || This->info_written)
1543  {
1544  LeaveCriticalSection(&This->lock);
1545  return WINCODEC_ERR_WRONGSTATE;
1546  }
1547 
1548  for (i=0; formats[i].guid; i++)
1549  {
1550  if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
1551  break;
1552  }
1553 
1554  if (!formats[i].guid) i = 0;
1555 
1556  This->format = &formats[i];
1557  memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
1558 
1559  LeaveCriticalSection(&This->lock);
1560 
1561  return S_OK;
1562 }
1563 
1564 static HRESULT WINAPI PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
1565  UINT cCount, IWICColorContext **ppIColorContext)
1566 {
1567  FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1568  return E_NOTIMPL;
1569 }
1570 
1571 static HRESULT WINAPI PngFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
1573 {
1574  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1575  HRESULT hr;
1576 
1577  TRACE("(%p,%p)\n", iface, palette);
1578 
1579  if (!palette) return E_INVALIDARG;
1580 
1581  EnterCriticalSection(&This->lock);
1582 
1583  if (This->frame_initialized)
1584  hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1585  else
1587 
1588  LeaveCriticalSection(&This->lock);
1589  return hr;
1590 }
1591 
1592 static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
1593  IWICBitmapSource *pIThumbnail)
1594 {
1595  FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1597 }
1598 
1599 static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
1600  UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
1601 {
1602  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1603  png_byte **row_pointers=NULL;
1604  UINT i;
1605  jmp_buf jmpbuf;
1606  TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
1607 
1608  EnterCriticalSection(&This->lock);
1609 
1610  if (!This->frame_initialized || !This->width || !This->height || !This->format)
1611  {
1612  LeaveCriticalSection(&This->lock);
1613  return WINCODEC_ERR_WRONGSTATE;
1614  }
1615 
1616  if (lineCount == 0 || lineCount + This->lines_written > This->height)
1617  {
1618  LeaveCriticalSection(&This->lock);
1619  return E_INVALIDARG;
1620  }
1621 
1622  /* set up setjmp/longjmp error handling */
1623  if (setjmp(jmpbuf))
1624  {
1625  LeaveCriticalSection(&This->lock);
1626  HeapFree(GetProcessHeap(), 0, row_pointers);
1627  return E_FAIL;
1628  }
1629  ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
1630 
1631  if (!This->info_written)
1632  {
1633  if (This->interlace)
1634  {
1635  /* libpng requires us to write all data multiple times in this case. */
1636  This->stride = (This->format->bpp * This->width + 7)/8;
1637  This->data = HeapAlloc(GetProcessHeap(), 0, This->height * This->stride);
1638  if (!This->data)
1639  {
1640  LeaveCriticalSection(&This->lock);
1641  return E_OUTOFMEMORY;
1642  }
1643  }
1644 
1645  ppng_set_IHDR(This->png_ptr, This->info_ptr, This->width, This->height,
1646  This->format->bit_depth, This->format->color_type,
1649 
1650  if (This->xres != 0.0 && This->yres != 0.0)
1651  {
1652  ppng_set_pHYs(This->png_ptr, This->info_ptr, (This->xres+0.0127) / 0.0254,
1653  (This->yres+0.0127) / 0.0254, PNG_RESOLUTION_METER);
1654  }
1655 
1656  if (This->format->color_type == PNG_COLOR_TYPE_PALETTE && This->colors)
1657  {
1658  png_color png_palette[256];
1659  png_byte trans[256];
1660  UINT i, num_trans = 0, colors;
1661 
1662  /* Newer libpng versions don't accept larger palettes than the declared
1663  * bit depth, so we need to generate the palette of the correct length.
1664  */
1665  colors = min(This->colors, 1 << This->format->bit_depth);
1666 
1667  for (i = 0; i < colors; i++)
1668  {
1669  png_palette[i].red = (This->palette[i] >> 16) & 0xff;
1670  png_palette[i].green = (This->palette[i] >> 8) & 0xff;
1671  png_palette[i].blue = This->palette[i] & 0xff;
1672  trans[i] = (This->palette[i] >> 24) & 0xff;
1673  if (trans[i] != 0xff)
1674  num_trans = i+1;
1675  }
1676 
1677  ppng_set_PLTE(This->png_ptr, This->info_ptr, png_palette, colors);
1678 
1679  if (num_trans)
1680  ppng_set_tRNS(This->png_ptr, This->info_ptr, trans, num_trans, NULL);
1681  }
1682 
1683  ppng_write_info(This->png_ptr, This->info_ptr);
1684 
1685  if (This->format->remove_filler)
1686  ppng_set_filler(This->png_ptr, 0, PNG_FILLER_AFTER);
1687 
1688  if (This->format->swap_rgb)
1689  ppng_set_bgr(This->png_ptr);
1690 
1691  if (This->interlace)
1692  This->passes = ppng_set_interlace_handling(This->png_ptr);
1693 
1694  if (This->filter != WICPngFilterUnspecified)
1695  {
1696  static const int png_filter_map[] =
1697  {
1698  /* WICPngFilterUnspecified */ PNG_NO_FILTERS,
1699  /* WICPngFilterNone */ PNG_FILTER_NONE,
1700  /* WICPngFilterSub */ PNG_FILTER_SUB,
1701  /* WICPngFilterUp */ PNG_FILTER_UP,
1702  /* WICPngFilterAverage */ PNG_FILTER_AVG,
1703  /* WICPngFilterPaeth */ PNG_FILTER_PAETH,
1704  /* WICPngFilterAdaptive */ PNG_ALL_FILTERS,
1705  };
1706 
1707  ppng_set_filter(This->png_ptr, 0, png_filter_map[This->filter]);
1708  }
1709 
1710  This->info_written = TRUE;
1711  }
1712 
1713  if (This->interlace)
1714  {
1715  /* Just store the data so we can write it in multiple passes in Commit. */
1716  for (i=0; i<lineCount; i++)
1717  memcpy(This->data + This->stride * (This->lines_written + i),
1718  pbPixels + cbStride * i,
1719  This->stride);
1720 
1721  This->lines_written += lineCount;
1722 
1723  LeaveCriticalSection(&This->lock);
1724  return S_OK;
1725  }
1726 
1727  row_pointers = HeapAlloc(GetProcessHeap(), 0, lineCount * sizeof(png_byte*));
1728  if (!row_pointers)
1729  {
1730  LeaveCriticalSection(&This->lock);
1731  return E_OUTOFMEMORY;
1732  }
1733 
1734  for (i=0; i<lineCount; i++)
1735  row_pointers[i] = pbPixels + cbStride * i;
1736 
1737  ppng_write_rows(This->png_ptr, row_pointers, lineCount);
1738  This->lines_written += lineCount;
1739 
1740  LeaveCriticalSection(&This->lock);
1741 
1742  HeapFree(GetProcessHeap(), 0, row_pointers);
1743 
1744  return S_OK;
1745 }
1746 
1747 static HRESULT WINAPI PngFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
1748  IWICBitmapSource *pIBitmapSource, WICRect *prc)
1749 {
1750  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1751  HRESULT hr;
1752  TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc));
1753 
1754  if (!This->frame_initialized)
1755  return WINCODEC_ERR_WRONGSTATE;
1756 
1757  hr = configure_write_source(iface, pIBitmapSource, prc,
1758  This->format ? This->format->guid : NULL, This->width, This->height,
1759  This->xres, This->yres);
1760 
1761  if (SUCCEEDED(hr))
1762  {
1763  hr = write_source(iface, pIBitmapSource, prc,
1764  This->format->guid, This->format->bpp, This->width, This->height);
1765  }
1766 
1767  return hr;
1768 }
1769 
1770 static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1771 {
1772  PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
1773  png_byte **row_pointers=NULL;
1774  jmp_buf jmpbuf;
1775  TRACE("(%p)\n", iface);
1776 
1777  EnterCriticalSection(&This->lock);
1778 
1779  if (!This->info_written || This->lines_written != This->height || This->frame_committed)
1780  {
1781  LeaveCriticalSection(&This->lock);
1782  return WINCODEC_ERR_WRONGSTATE;
1783  }
1784 
1785  /* set up setjmp/longjmp error handling */
1786  if (setjmp(jmpbuf))
1787  {
1788  LeaveCriticalSection(&This->lock);
1789  HeapFree(GetProcessHeap(), 0, row_pointers);
1790  return E_FAIL;
1791  }
1792  ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
1793 
1794  if (This->interlace)
1795  {
1796  int i;
1797 
1798  row_pointers = HeapAlloc(GetProcessHeap(), 0, This->height * sizeof(png_byte*));
1799  if (!row_pointers)
1800  {
1801  LeaveCriticalSection(&This->lock);
1802  return E_OUTOFMEMORY;
1803  }
1804 
1805  for (i=0; i<This->height; i++)
1806  row_pointers[i] = This->data + This->stride * i;
1807 
1808  for (i=0; i<This->passes; i++)
1809  ppng_write_rows(This->png_ptr, row_pointers, This->height);
1810  }
1811 
1812  ppng_write_end(This->png_ptr, This->info_ptr);
1813 
1814  This->frame_committed = TRUE;
1815 
1816  HeapFree(GetProcessHeap(), 0, row_pointers);
1817 
1818  LeaveCriticalSection(&This->lock);
1819 
1820  return S_OK;
1821 }
1822 
1823 static HRESULT WINAPI PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1824  IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1825 {
1826  FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1827  return E_NOTIMPL;
1828 }
1829 
1830 static const IWICBitmapFrameEncodeVtbl PngEncoder_FrameVtbl = {
1831  PngFrameEncode_QueryInterface,
1832  PngFrameEncode_AddRef,
1833  PngFrameEncode_Release,
1834  PngFrameEncode_Initialize,
1835  PngFrameEncode_SetSize,
1836  PngFrameEncode_SetResolution,
1837  PngFrameEncode_SetPixelFormat,
1838  PngFrameEncode_SetColorContexts,
1839  PngFrameEncode_SetPalette,
1840  PngFrameEncode_SetThumbnail,
1841  PngFrameEncode_WritePixels,
1842  PngFrameEncode_WriteSource,
1843  PngFrameEncode_Commit,
1844  PngFrameEncode_GetMetadataQueryWriter
1845 };
1846 
1847 static HRESULT WINAPI PngEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1848  void **ppv)
1849 {
1850  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1851  TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1852 
1853  if (!ppv) return E_INVALIDARG;
1854 
1855  if (IsEqualIID(&IID_IUnknown, iid) ||
1856  IsEqualIID(&IID_IWICBitmapEncoder, iid))
1857  {
1858  *ppv = &This->IWICBitmapEncoder_iface;
1859  }
1860  else
1861  {
1862  *ppv = NULL;
1863  return E_NOINTERFACE;
1864  }
1865 
1866  IUnknown_AddRef((IUnknown*)*ppv);
1867  return S_OK;
1868 }
1869 
1870 static ULONG WINAPI PngEncoder_AddRef(IWICBitmapEncoder *iface)
1871 {
1872  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1874 
1875  TRACE("(%p) refcount=%u\n", iface, ref);
1876 
1877  return ref;
1878 }
1879 
1880 static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface)
1881 {
1882  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1884 
1885  TRACE("(%p) refcount=%u\n", iface, ref);
1886 
1887  if (ref == 0)
1888  {
1889  This->lock.DebugInfo->Spare[0] = 0;
1890  DeleteCriticalSection(&This->lock);
1891  if (This->png_ptr)
1892  ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
1893  if (This->stream)
1894  IStream_Release(This->stream);
1895  HeapFree(GetProcessHeap(), 0, This->data);
1896  HeapFree(GetProcessHeap(), 0, This);
1897  }
1898 
1899  return ref;
1900 }
1901 
1902 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
1903 {
1904  PngEncoder *This = ppng_get_io_ptr(png_ptr);
1905  HRESULT hr;
1906  ULONG byteswritten;
1907 
1908  hr = IStream_Write(This->stream, data, length, &byteswritten);
1909  if (FAILED(hr) || byteswritten != length)
1910  {
1911  ppng_error(png_ptr, "failed writing data");
1912  }
1913 }
1914 
1915 static void user_flush(png_structp png_ptr)
1916 {
1917 }
1918 
1919 static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface,
1920  IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1921 {
1922  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
1923  jmp_buf jmpbuf;
1924 
1925  TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1926 
1927  EnterCriticalSection(&This->lock);
1928 
1929  if (This->png_ptr)
1930  {
1931  LeaveCriticalSection(&This->lock);
1932  return WINCODEC_ERR_WRONGSTATE;
1933  }
1934 
1935  /* initialize libpng */
1936  This->png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1937  if (!This->png_ptr)
1938  {
1939  LeaveCriticalSection(&This->lock);
1940  return E_FAIL;
1941  }
1942 
1943  This->info_ptr = ppng_create_info_struct(This->png_ptr);
1944  if (!This->info_ptr)
1945  {
1946  ppng_destroy_write_struct(&This->png_ptr, NULL);
1947  This->png_ptr = NULL;
1948  LeaveCriticalSection(&This->lock);
1949  return E_FAIL;
1950  }
1951 
1952  IStream_AddRef(pIStream);
1953  This->stream = pIStream;
1954 
1955  /* set up setjmp/longjmp error handling */
1956  if (setjmp(jmpbuf))
1957  {
1958  ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
1959  This->png_ptr = NULL;
1960  IStream_Release(This->stream);
1961  This->stream = NULL;
1962  LeaveCriticalSection(&This->lock);
1963  return E_FAIL;
1964  }
1965  ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
1966 
1967  /* set up custom i/o handling */
1968  ppng_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
1969 
1970  LeaveCriticalSection(&This->lock);
1971 
1972  return S_OK;
1973 }
1974 
1975 static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
1976 {
1977  TRACE("(%p,%p)\n", iface, format);
1978 
1979  if (!format)
1980  return E_INVALIDARG;
1981 
1982  memcpy(format, &GUID_ContainerFormatPng, sizeof(*format));
1983  return S_OK;
1984 }
1985 
1986 static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
1987 {
1988  IWICComponentInfo *comp_info;
1989  HRESULT hr;
1990 
1991  TRACE("%p,%p\n", iface, info);
1992 
1993  if (!info) return E_INVALIDARG;
1994 
1995  hr = CreateComponentInfo(&CLSID_WICPngEncoder, &comp_info);
1996  if (hr == S_OK)
1997  {
1998  hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
1999  IWICComponentInfo_Release(comp_info);
2000  }
2001  return hr;
2002 }
2003 
2004 static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface,
2005  UINT cCount, IWICColorContext **ppIColorContext)
2006 {
2007  FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
2008  return E_NOTIMPL;
2009 }
2010 
2011 static HRESULT WINAPI PngEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2012 {
2013  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
2014  HRESULT hr;
2015 
2016  TRACE("(%p,%p)\n", iface, palette);
2017 
2018  EnterCriticalSection(&This->lock);
2019 
2021 
2022  LeaveCriticalSection(&This->lock);
2023 
2024  return hr;
2025 }
2026 
2027 static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
2028 {
2029  TRACE("(%p,%p)\n", iface, pIThumbnail);
2031 }
2032 
2033 static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
2034 {
2035  TRACE("(%p,%p)\n", iface, pIPreview);
2037 }
2038 
2039 static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
2040  IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
2041 {
2042  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
2043  HRESULT hr;
2044  static const PROPBAG2 opts[2] =
2045  {
2046  { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszPngInterlaceOption },
2047  { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszPngFilterOption },
2048  };
2049 
2050  TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
2051 
2052  EnterCriticalSection(&This->lock);
2053 
2054  if (This->frame_count != 0)
2055  {
2056  LeaveCriticalSection(&This->lock);
2058  }
2059 
2060  if (!This->stream)
2061  {
2062  LeaveCriticalSection(&This->lock);
2064  }
2065 
2066  if (ppIEncoderOptions)
2067  {
2068  hr = CreatePropertyBag2(opts, ARRAY_SIZE(opts), ppIEncoderOptions);
2069  if (FAILED(hr))
2070  {
2071  LeaveCriticalSection(&This->lock);
2072  return hr;
2073  }
2074  }
2075 
2076  This->frame_count = 1;
2077 
2078  LeaveCriticalSection(&This->lock);
2079 
2080  IWICBitmapEncoder_AddRef(iface);
2081  *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface;
2082 
2083  return S_OK;
2084 }
2085 
2086 static HRESULT WINAPI PngEncoder_Commit(IWICBitmapEncoder *iface)
2087 {
2088  PngEncoder *This = impl_from_IWICBitmapEncoder(iface);
2089  TRACE("(%p)\n", iface);
2090 
2091  EnterCriticalSection(&This->lock);
2092 
2093  if (!This->frame_committed || This->committed)
2094  {
2095  LeaveCriticalSection(&This->lock);
2096  return WINCODEC_ERR_WRONGSTATE;
2097  }
2098 
2099  This->committed = TRUE;
2100 
2101  LeaveCriticalSection(&This->lock);
2102 
2103  return S_OK;
2104 }
2105 
2106 static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
2107  IWICMetadataQueryWriter **ppIMetadataQueryWriter)
2108 {
2109  FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
2110  return E_NOTIMPL;
2111 }
2112 
2113 static const IWICBitmapEncoderVtbl PngEncoder_Vtbl = {
2114  PngEncoder_QueryInterface,
2115  PngEncoder_AddRef,
2116  PngEncoder_Release,
2117  PngEncoder_Initialize,
2118  PngEncoder_GetContainerFormat,
2119  PngEncoder_GetEncoderInfo,
2120  PngEncoder_SetColorContexts,
2121  PngEncoder_SetPalette,
2122  PngEncoder_SetThumbnail,
2123  PngEncoder_SetPreview,
2124  PngEncoder_CreateNewFrame,
2125  PngEncoder_Commit,
2126  PngEncoder_GetMetadataQueryWriter
2127 };
2128 
2130 {
2131  PngEncoder *This;
2132  HRESULT ret;
2133 
2134  TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
2135 
2136  *ppv = NULL;
2137 
2138  if (!load_libpng())
2139  {
2140  ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG);
2141  return E_FAIL;
2142  }
2143 
2144  This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder));
2145  if (!This) return E_OUTOFMEMORY;
2146 
2147  This->IWICBitmapEncoder_iface.lpVtbl = &PngEncoder_Vtbl;
2148  This->IWICBitmapFrameEncode_iface.lpVtbl = &PngEncoder_FrameVtbl;
2149  This->ref = 1;
2150  This->png_ptr = NULL;
2151  This->info_ptr = NULL;
2152  This->stream = NULL;
2153  This->frame_count = 0;
2154  This->frame_initialized = FALSE;
2155  This->format = NULL;
2156  This->info_written = FALSE;
2157  This->width = 0;
2158  This->height = 0;
2159  This->xres = 0.0;
2160  This->yres = 0.0;
2161  This->lines_written = 0;
2162  This->frame_committed = FALSE;
2163  This->committed = FALSE;
2164  This->data = NULL;
2165  This->colors = 0;
2167  This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngEncoder.lock");
2168 
2169  ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2170  IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2171 
2172  return ret;
2173 }
2174 
2175 #else /* !HAVE_PNG_H */
2176 
2178 {
2179  ERR("Trying to load PNG picture, but PNG support is not compiled in.\n");
2180  return E_FAIL;
2181 }
2182 
2184 {
2185  ERR("Trying to save PNG picture, but PNG support is not compiled in.\n");
2186  return E_FAIL;
2187 }
2188 
2189 #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:407
#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:738
#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:440
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:395
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:8
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:848
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:2177
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:2183
#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:406
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:36
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:394
struct CFHEADER header
Definition: fdi.c:109
#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