2 * Copyright 2009 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
35 #include "wincodecs_private.h"
37 #include "wine/debug.h"
38 #include "wine/library.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
44 static void *libpng_handle
;
45 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
46 MAKE_FUNCPTR(png_create_read_struct
);
47 MAKE_FUNCPTR(png_create_info_struct
);
48 MAKE_FUNCPTR(png_create_write_struct
);
49 MAKE_FUNCPTR(png_destroy_read_struct
);
50 MAKE_FUNCPTR(png_destroy_write_struct
);
51 MAKE_FUNCPTR(png_error
);
52 MAKE_FUNCPTR(png_get_bit_depth
);
53 MAKE_FUNCPTR(png_get_color_type
);
54 MAKE_FUNCPTR(png_get_error_ptr
);
55 MAKE_FUNCPTR(png_get_image_height
);
56 MAKE_FUNCPTR(png_get_image_width
);
57 MAKE_FUNCPTR(png_get_io_ptr
);
58 MAKE_FUNCPTR(png_get_pHYs
);
59 MAKE_FUNCPTR(png_get_PLTE
);
60 MAKE_FUNCPTR(png_get_tRNS
);
61 MAKE_FUNCPTR(png_set_bgr
);
62 MAKE_FUNCPTR(png_set_error_fn
);
63 #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
64 MAKE_FUNCPTR(png_set_expand_gray_1_2_4_to_8
);
66 MAKE_FUNCPTR(png_set_gray_1_2_4_to_8
);
68 MAKE_FUNCPTR(png_set_filler
);
69 MAKE_FUNCPTR(png_set_gray_to_rgb
);
70 MAKE_FUNCPTR(png_set_IHDR
);
71 MAKE_FUNCPTR(png_set_pHYs
);
72 MAKE_FUNCPTR(png_set_read_fn
);
73 MAKE_FUNCPTR(png_set_strip_16
);
74 MAKE_FUNCPTR(png_set_tRNS_to_alpha
);
75 MAKE_FUNCPTR(png_set_write_fn
);
76 MAKE_FUNCPTR(png_read_end
);
77 MAKE_FUNCPTR(png_read_image
);
78 MAKE_FUNCPTR(png_read_info
);
79 MAKE_FUNCPTR(png_write_end
);
80 MAKE_FUNCPTR(png_write_info
);
81 MAKE_FUNCPTR(png_write_rows
);
84 static void *load_libpng(void)
86 if((libpng_handle
= wine_dlopen(SONAME_LIBPNG
, RTLD_NOW
, NULL
, 0)) != NULL
) {
88 #define LOAD_FUNCPTR(f) \
89 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
90 libpng_handle = NULL; \
93 LOAD_FUNCPTR(png_create_read_struct
);
94 LOAD_FUNCPTR(png_create_info_struct
);
95 LOAD_FUNCPTR(png_create_write_struct
);
96 LOAD_FUNCPTR(png_destroy_read_struct
);
97 LOAD_FUNCPTR(png_destroy_write_struct
);
98 LOAD_FUNCPTR(png_error
);
99 LOAD_FUNCPTR(png_get_bit_depth
);
100 LOAD_FUNCPTR(png_get_color_type
);
101 LOAD_FUNCPTR(png_get_error_ptr
);
102 LOAD_FUNCPTR(png_get_image_height
);
103 LOAD_FUNCPTR(png_get_image_width
);
104 LOAD_FUNCPTR(png_get_io_ptr
);
105 LOAD_FUNCPTR(png_get_pHYs
);
106 LOAD_FUNCPTR(png_get_PLTE
);
107 LOAD_FUNCPTR(png_get_tRNS
);
108 LOAD_FUNCPTR(png_set_bgr
);
109 LOAD_FUNCPTR(png_set_error_fn
);
110 #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
111 LOAD_FUNCPTR(png_set_expand_gray_1_2_4_to_8
);
113 LOAD_FUNCPTR(png_set_gray_1_2_4_to_8
);
115 LOAD_FUNCPTR(png_set_filler
);
116 LOAD_FUNCPTR(png_set_gray_to_rgb
);
117 LOAD_FUNCPTR(png_set_IHDR
);
118 LOAD_FUNCPTR(png_set_pHYs
);
119 LOAD_FUNCPTR(png_set_read_fn
);
120 LOAD_FUNCPTR(png_set_strip_16
);
121 LOAD_FUNCPTR(png_set_tRNS_to_alpha
);
122 LOAD_FUNCPTR(png_set_write_fn
);
123 LOAD_FUNCPTR(png_read_end
);
124 LOAD_FUNCPTR(png_read_image
);
125 LOAD_FUNCPTR(png_read_info
);
126 LOAD_FUNCPTR(png_write_end
);
127 LOAD_FUNCPTR(png_write_info
);
128 LOAD_FUNCPTR(png_write_rows
);
132 return libpng_handle
;
135 static void user_error_fn(png_structp png_ptr
, png_const_charp error_message
)
139 /* This uses setjmp/longjmp just like the default. We can't use the
140 * default because there's no way to access the jmp buffer in the png_struct
141 * that works in 1.2 and 1.4 and allows us to dynamically load libpng. */
142 WARN("PNG error: %s\n", debugstr_a(error_message
));
143 pjmpbuf
= ppng_get_error_ptr(png_ptr
);
144 longjmp(*pjmpbuf
, 1);
147 static void user_warning_fn(png_structp png_ptr
, png_const_charp warning_message
)
149 WARN("PNG warning: %s\n", debugstr_a(warning_message
));
153 IWICBitmapDecoder IWICBitmapDecoder_iface
;
154 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
163 const WICPixelFormatGUID
*format
;
165 CRITICAL_SECTION lock
; /* must be held when png structures are accessed or initialized is set */
168 static inline PngDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
170 return CONTAINING_RECORD(iface
, PngDecoder
, IWICBitmapDecoder_iface
);
173 static inline PngDecoder
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
175 return CONTAINING_RECORD(iface
, PngDecoder
, IWICBitmapFrameDecode_iface
);
178 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl
;
180 static HRESULT WINAPI
PngDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
183 PngDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
184 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
186 if (!ppv
) return E_INVALIDARG
;
188 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
195 return E_NOINTERFACE
;
198 IUnknown_AddRef((IUnknown
*)*ppv
);
202 static ULONG WINAPI
PngDecoder_AddRef(IWICBitmapDecoder
*iface
)
204 PngDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
205 ULONG ref
= InterlockedIncrement(&This
->ref
);
207 TRACE("(%p) refcount=%u\n", iface
, ref
);
212 static ULONG WINAPI
PngDecoder_Release(IWICBitmapDecoder
*iface
)
214 PngDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
215 ULONG ref
= InterlockedDecrement(&This
->ref
);
217 TRACE("(%p) refcount=%u\n", iface
, ref
);
222 ppng_destroy_read_struct(&This
->png_ptr
, &This
->info_ptr
, &This
->end_info
);
223 This
->lock
.DebugInfo
->Spare
[0] = 0;
224 DeleteCriticalSection(&This
->lock
);
225 HeapFree(GetProcessHeap(), 0, This
->image_bits
);
226 HeapFree(GetProcessHeap(), 0, This
);
232 static HRESULT WINAPI
PngDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
233 DWORD
*pdwCapability
)
235 FIXME("(%p,%p,%p): stub\n", iface
, pIStream
, pdwCapability
);
239 static void user_read_data(png_structp png_ptr
, png_bytep data
, png_size_t length
)
241 IStream
*stream
= ppng_get_io_ptr(png_ptr
);
245 hr
= IStream_Read(stream
, data
, length
, &bytesread
);
246 if (FAILED(hr
) || bytesread
!= length
)
248 ppng_error(png_ptr
, "failed reading data");
252 static HRESULT WINAPI
PngDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
253 WICDecodeOptions cacheOptions
)
255 PngDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
258 png_bytep
*row_pointers
=NULL
;
261 int color_type
, bit_depth
;
264 png_uint_32 transparency
;
265 png_color_16p trans_values
;
268 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
270 EnterCriticalSection(&This
->lock
);
272 /* initialize libpng */
273 This
->png_ptr
= ppng_create_read_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
280 This
->info_ptr
= ppng_create_info_struct(This
->png_ptr
);
283 ppng_destroy_read_struct(&This
->png_ptr
, NULL
, NULL
);
284 This
->png_ptr
= NULL
;
289 This
->end_info
= ppng_create_info_struct(This
->png_ptr
);
292 ppng_destroy_read_struct(&This
->png_ptr
, &This
->info_ptr
, NULL
);
293 This
->png_ptr
= NULL
;
298 /* set up setjmp/longjmp error handling */
301 ppng_destroy_read_struct(&This
->png_ptr
, &This
->info_ptr
, &This
->end_info
);
302 HeapFree(GetProcessHeap(), 0, row_pointers
);
303 This
->png_ptr
= NULL
;
307 ppng_set_error_fn(This
->png_ptr
, &jmpbuf
, user_error_fn
, user_warning_fn
);
309 /* seek to the start of the stream */
311 hr
= IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
312 if (FAILED(hr
)) goto end
;
314 /* set up custom i/o handling */
315 ppng_set_read_fn(This
->png_ptr
, pIStream
, user_read_data
);
317 /* read the header */
318 ppng_read_info(This
->png_ptr
, This
->info_ptr
);
320 /* choose a pixel format */
321 color_type
= ppng_get_color_type(This
->png_ptr
, This
->info_ptr
);
322 bit_depth
= ppng_get_bit_depth(This
->png_ptr
, This
->info_ptr
);
324 /* check for color-keyed alpha */
325 transparency
= ppng_get_tRNS(This
->png_ptr
, This
->info_ptr
, &trans
, &num_trans
, &trans_values
);
327 if (transparency
&& color_type
!= PNG_COLOR_TYPE_PALETTE
)
330 if (color_type
== PNG_COLOR_TYPE_GRAY
)
334 #if HAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8
335 ppng_set_expand_gray_1_2_4_to_8(This
->png_ptr
);
337 ppng_set_gray_1_2_4_to_8(This
->png_ptr
);
341 ppng_set_gray_to_rgb(This
->png_ptr
);
343 ppng_set_tRNS_to_alpha(This
->png_ptr
);
344 color_type
= PNG_COLOR_TYPE_RGB_ALPHA
;
349 case PNG_COLOR_TYPE_GRAY
:
350 This
->bpp
= bit_depth
;
353 case 1: This
->format
= &GUID_WICPixelFormatBlackWhite
; break;
354 case 2: This
->format
= &GUID_WICPixelFormat2bppGray
; break;
355 case 4: This
->format
= &GUID_WICPixelFormat4bppGray
; break;
356 case 8: This
->format
= &GUID_WICPixelFormat8bppGray
; break;
357 case 16: This
->format
= &GUID_WICPixelFormat16bppGray
; break;
359 ERR("invalid grayscale bit depth: %i\n", bit_depth
);
364 case PNG_COLOR_TYPE_GRAY_ALPHA
:
365 /* WIC does not support grayscale alpha formats so use RGBA */
366 ppng_set_gray_to_rgb(This
->png_ptr
);
368 case PNG_COLOR_TYPE_RGB_ALPHA
:
369 This
->bpp
= bit_depth
* 4;
373 ppng_set_bgr(This
->png_ptr
);
374 This
->format
= &GUID_WICPixelFormat32bppBGRA
;
376 case 16: This
->format
= &GUID_WICPixelFormat64bppRGBA
; break;
378 ERR("invalid RGBA bit depth: %i\n", bit_depth
);
383 case PNG_COLOR_TYPE_PALETTE
:
384 This
->bpp
= bit_depth
;
387 case 1: This
->format
= &GUID_WICPixelFormat1bppIndexed
; break;
388 case 2: This
->format
= &GUID_WICPixelFormat2bppIndexed
; break;
389 case 4: This
->format
= &GUID_WICPixelFormat4bppIndexed
; break;
390 case 8: This
->format
= &GUID_WICPixelFormat8bppIndexed
; break;
392 ERR("invalid indexed color bit depth: %i\n", bit_depth
);
397 case PNG_COLOR_TYPE_RGB
:
398 This
->bpp
= bit_depth
* 3;
402 ppng_set_bgr(This
->png_ptr
);
403 This
->format
= &GUID_WICPixelFormat24bppBGR
;
405 case 16: This
->format
= &GUID_WICPixelFormat48bppRGB
; break;
407 ERR("invalid RGB color bit depth: %i\n", bit_depth
);
413 ERR("invalid color type %i\n", color_type
);
418 /* read the image data */
419 This
->width
= ppng_get_image_width(This
->png_ptr
, This
->info_ptr
);
420 This
->height
= ppng_get_image_height(This
->png_ptr
, This
->info_ptr
);
421 This
->stride
= This
->width
* This
->bpp
;
422 image_size
= This
->stride
* This
->height
;
424 This
->image_bits
= HeapAlloc(GetProcessHeap(), 0, image_size
);
425 if (!This
->image_bits
)
431 row_pointers
= HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep
)*This
->height
);
438 for (i
=0; i
<This
->height
; i
++)
439 row_pointers
[i
] = This
->image_bits
+ i
* This
->stride
;
441 ppng_read_image(This
->png_ptr
, row_pointers
);
443 HeapFree(GetProcessHeap(), 0, row_pointers
);
446 ppng_read_end(This
->png_ptr
, This
->end_info
);
448 This
->initialized
= TRUE
;
452 LeaveCriticalSection(&This
->lock
);
457 static HRESULT WINAPI
PngDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
458 GUID
*pguidContainerFormat
)
460 memcpy(pguidContainerFormat
, &GUID_ContainerFormatPng
, sizeof(GUID
));
464 static HRESULT WINAPI
PngDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
465 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
468 IWICComponentInfo
*compinfo
;
470 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
472 hr
= CreateComponentInfo(&CLSID_WICPngDecoder
, &compinfo
);
473 if (FAILED(hr
)) return hr
;
475 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
476 (void**)ppIDecoderInfo
);
478 IWICComponentInfo_Release(compinfo
);
483 static HRESULT WINAPI
PngDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
484 IWICPalette
*pIPalette
)
486 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
490 static HRESULT WINAPI
PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
491 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
493 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
497 static HRESULT WINAPI
PngDecoder_GetPreview(IWICBitmapDecoder
*iface
,
498 IWICBitmapSource
**ppIBitmapSource
)
500 FIXME("(%p,%p): stub\n", iface
, ppIBitmapSource
);
504 static HRESULT WINAPI
PngDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
505 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
507 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
511 static HRESULT WINAPI
PngDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
512 IWICBitmapSource
**ppIThumbnail
)
514 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
515 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
518 static HRESULT WINAPI
PngDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
525 static HRESULT WINAPI
PngDecoder_GetFrame(IWICBitmapDecoder
*iface
,
526 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
528 PngDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
529 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
531 if (!This
->initialized
) return WINCODEC_ERR_NOTINITIALIZED
;
533 if (index
!= 0) return E_INVALIDARG
;
535 IWICBitmapDecoder_AddRef(iface
);
537 *ppIBitmapFrame
= &This
->IWICBitmapFrameDecode_iface
;
542 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl
= {
543 PngDecoder_QueryInterface
,
546 PngDecoder_QueryCapability
,
547 PngDecoder_Initialize
,
548 PngDecoder_GetContainerFormat
,
549 PngDecoder_GetDecoderInfo
,
550 PngDecoder_CopyPalette
,
551 PngDecoder_GetMetadataQueryReader
,
552 PngDecoder_GetPreview
,
553 PngDecoder_GetColorContexts
,
554 PngDecoder_GetThumbnail
,
555 PngDecoder_GetFrameCount
,
559 static HRESULT WINAPI
PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
562 if (!ppv
) return E_INVALIDARG
;
564 if (IsEqualIID(&IID_IUnknown
, iid
) ||
565 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
566 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
573 return E_NOINTERFACE
;
576 IUnknown_AddRef((IUnknown
*)*ppv
);
580 static ULONG WINAPI
PngDecoder_Frame_AddRef(IWICBitmapFrameDecode
*iface
)
582 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
583 return IUnknown_AddRef((IUnknown
*)This
);
586 static ULONG WINAPI
PngDecoder_Frame_Release(IWICBitmapFrameDecode
*iface
)
588 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
589 return IUnknown_Release((IUnknown
*)This
);
592 static HRESULT WINAPI
PngDecoder_Frame_GetSize(IWICBitmapFrameDecode
*iface
,
593 UINT
*puiWidth
, UINT
*puiHeight
)
595 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
596 *puiWidth
= This
->width
;
597 *puiHeight
= This
->height
;
598 TRACE("(%p)->(%u,%u)\n", iface
, *puiWidth
, *puiHeight
);
602 static HRESULT WINAPI
PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
603 WICPixelFormatGUID
*pPixelFormat
)
605 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
606 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
608 memcpy(pPixelFormat
, This
->format
, sizeof(GUID
));
613 static HRESULT WINAPI
PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode
*iface
,
614 double *pDpiX
, double *pDpiY
)
616 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
617 png_uint_32 ret
, xres
, yres
;
620 EnterCriticalSection(&This
->lock
);
622 ret
= ppng_get_pHYs(This
->png_ptr
, This
->info_ptr
, &xres
, &yres
, &unit_type
);
624 if (ret
&& unit_type
== PNG_RESOLUTION_METER
)
626 *pDpiX
= xres
* 0.0254;
627 *pDpiY
= yres
* 0.0254;
631 WARN("no pHYs block present\n");
632 *pDpiX
= *pDpiY
= 96.0;
635 LeaveCriticalSection(&This
->lock
);
637 TRACE("(%p)->(%0.2f,%0.2f)\n", iface
, *pDpiX
, *pDpiY
);
642 static HRESULT WINAPI
PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode
*iface
,
643 IWICPalette
*pIPalette
)
645 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
647 png_colorp png_palette
;
649 WICColor palette
[256];
652 png_color_16p trans_values
;
656 TRACE("(%p,%p)\n", iface
, pIPalette
);
658 EnterCriticalSection(&This
->lock
);
660 ret
= ppng_get_PLTE(This
->png_ptr
, This
->info_ptr
, &png_palette
, &num_palette
);
663 hr
= WINCODEC_ERR_PALETTEUNAVAILABLE
;
667 if (num_palette
> 256)
669 ERR("palette has %i colors?!\n", num_palette
);
674 for (i
=0; i
<num_palette
; i
++)
676 palette
[i
] = (0xff000000|
677 png_palette
[i
].red
<< 16|
678 png_palette
[i
].green
<< 8|
679 png_palette
[i
].blue
);
682 ret
= ppng_get_tRNS(This
->png_ptr
, This
->info_ptr
, &trans
, &num_trans
, &trans_values
);
685 for (i
=0; i
<num_trans
; i
++)
687 palette
[trans
[i
]] = 0x00000000;
693 LeaveCriticalSection(&This
->lock
);
696 hr
= IWICPalette_InitializeCustom(pIPalette
, palette
, num_palette
);
701 static HRESULT WINAPI
PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode
*iface
,
702 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
704 PngDecoder
*This
= impl_from_IWICBitmapFrameDecode(iface
);
705 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
707 return copy_pixels(This
->bpp
, This
->image_bits
,
708 This
->width
, This
->height
, This
->stride
,
709 prc
, cbStride
, cbBufferSize
, pbBuffer
);
712 static HRESULT WINAPI
PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
713 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
715 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
719 static HRESULT WINAPI
PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode
*iface
,
720 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
722 FIXME("(%p,%u,%p,%p): stub\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
726 static HRESULT WINAPI
PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode
*iface
,
727 IWICBitmapSource
**ppIThumbnail
)
729 FIXME("(%p,%p): stub\n", iface
, ppIThumbnail
);
733 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl
= {
734 PngDecoder_Frame_QueryInterface
,
735 PngDecoder_Frame_AddRef
,
736 PngDecoder_Frame_Release
,
737 PngDecoder_Frame_GetSize
,
738 PngDecoder_Frame_GetPixelFormat
,
739 PngDecoder_Frame_GetResolution
,
740 PngDecoder_Frame_CopyPalette
,
741 PngDecoder_Frame_CopyPixels
,
742 PngDecoder_Frame_GetMetadataQueryReader
,
743 PngDecoder_Frame_GetColorContexts
,
744 PngDecoder_Frame_GetThumbnail
747 HRESULT
PngDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
752 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
756 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
758 if (!libpng_handle
&& !load_libpng())
760 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG
);
764 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder
));
765 if (!This
) return E_OUTOFMEMORY
;
767 This
->IWICBitmapDecoder_iface
.lpVtbl
= &PngDecoder_Vtbl
;
768 This
->IWICBitmapFrameDecode_iface
.lpVtbl
= &PngDecoder_FrameVtbl
;
770 This
->png_ptr
= NULL
;
771 This
->info_ptr
= NULL
;
772 This
->end_info
= NULL
;
773 This
->initialized
= FALSE
;
774 This
->image_bits
= NULL
;
775 InitializeCriticalSection(&This
->lock
);
776 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PngDecoder.lock");
778 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
779 IUnknown_Release((IUnknown
*)This
);
784 struct png_pixelformat
{
785 const WICPixelFormatGUID
*guid
;
793 static const struct png_pixelformat formats
[] = {
794 {&GUID_WICPixelFormat24bppBGR
, 24, 8, PNG_COLOR_TYPE_RGB
, 0, 1},
795 {&GUID_WICPixelFormatBlackWhite
, 1, 1, PNG_COLOR_TYPE_GRAY
, 0, 0},
796 {&GUID_WICPixelFormat2bppGray
, 2, 2, PNG_COLOR_TYPE_GRAY
, 0, 0},
797 {&GUID_WICPixelFormat4bppGray
, 4, 4, PNG_COLOR_TYPE_GRAY
, 0, 0},
798 {&GUID_WICPixelFormat8bppGray
, 8, 8, PNG_COLOR_TYPE_GRAY
, 0, 0},
799 {&GUID_WICPixelFormat16bppGray
, 16, 16, PNG_COLOR_TYPE_GRAY
, 0, 0},
800 {&GUID_WICPixelFormat32bppBGR
, 32, 8, PNG_COLOR_TYPE_RGB
, 1, 1},
801 {&GUID_WICPixelFormat32bppBGRA
, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA
, 0, 1},
802 {&GUID_WICPixelFormat48bppRGB
, 48, 16, PNG_COLOR_TYPE_RGB
, 0, 0},
803 {&GUID_WICPixelFormat64bppRGBA
, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA
, 0, 0},
807 typedef struct PngEncoder
{
808 IWICBitmapEncoder IWICBitmapEncoder_iface
;
809 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
815 BOOL frame_initialized
;
816 const struct png_pixelformat
*format
;
821 BOOL frame_committed
;
823 CRITICAL_SECTION lock
;
826 static inline PngEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
828 return CONTAINING_RECORD(iface
, PngEncoder
, IWICBitmapEncoder_iface
);
831 static inline PngEncoder
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
833 return CONTAINING_RECORD(iface
, PngEncoder
, IWICBitmapFrameEncode_iface
);
836 static HRESULT WINAPI
PngFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
839 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
840 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
842 if (!ppv
) return E_INVALIDARG
;
844 if (IsEqualIID(&IID_IUnknown
, iid
) ||
845 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
847 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
852 return E_NOINTERFACE
;
855 IUnknown_AddRef((IUnknown
*)*ppv
);
859 static ULONG WINAPI
PngFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
861 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
862 return IUnknown_AddRef((IUnknown
*)This
);
865 static ULONG WINAPI
PngFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
867 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
868 return IUnknown_Release((IUnknown
*)This
);
871 static HRESULT WINAPI
PngFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
872 IPropertyBag2
*pIEncoderOptions
)
874 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
875 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
877 EnterCriticalSection(&This
->lock
);
879 if (This
->frame_initialized
)
881 LeaveCriticalSection(&This
->lock
);
882 return WINCODEC_ERR_WRONGSTATE
;
885 This
->frame_initialized
= TRUE
;
887 LeaveCriticalSection(&This
->lock
);
892 static HRESULT WINAPI
PngFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
893 UINT uiWidth
, UINT uiHeight
)
895 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
896 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
898 EnterCriticalSection(&This
->lock
);
900 if (!This
->frame_initialized
|| This
->info_written
)
902 LeaveCriticalSection(&This
->lock
);
903 return WINCODEC_ERR_WRONGSTATE
;
906 This
->width
= uiWidth
;
907 This
->height
= uiHeight
;
909 LeaveCriticalSection(&This
->lock
);
914 static HRESULT WINAPI
PngFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
915 double dpiX
, double dpiY
)
917 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
918 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
920 EnterCriticalSection(&This
->lock
);
922 if (!This
->frame_initialized
|| This
->info_written
)
924 LeaveCriticalSection(&This
->lock
);
925 return WINCODEC_ERR_WRONGSTATE
;
931 LeaveCriticalSection(&This
->lock
);
936 static HRESULT WINAPI
PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
937 WICPixelFormatGUID
*pPixelFormat
)
939 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
941 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
943 EnterCriticalSection(&This
->lock
);
945 if (!This
->frame_initialized
|| This
->info_written
)
947 LeaveCriticalSection(&This
->lock
);
948 return WINCODEC_ERR_WRONGSTATE
;
951 for (i
=0; formats
[i
].guid
; i
++)
953 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
957 if (!formats
[i
].guid
) i
= 0;
959 This
->format
= &formats
[i
];
960 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
962 LeaveCriticalSection(&This
->lock
);
967 static HRESULT WINAPI
PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
968 UINT cCount
, IWICColorContext
**ppIColorContext
)
970 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
974 static HRESULT WINAPI
PngFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
975 IWICPalette
*pIPalette
)
977 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
978 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
981 static HRESULT WINAPI
PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
982 IWICBitmapSource
*pIThumbnail
)
984 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
985 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
988 static HRESULT WINAPI
PngFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
989 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
991 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
992 png_byte
**row_pointers
=NULL
;
995 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
997 EnterCriticalSection(&This
->lock
);
999 if (!This
->frame_initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1001 LeaveCriticalSection(&This
->lock
);
1002 return WINCODEC_ERR_WRONGSTATE
;
1005 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1007 LeaveCriticalSection(&This
->lock
);
1008 return E_INVALIDARG
;
1011 /* set up setjmp/longjmp error handling */
1014 LeaveCriticalSection(&This
->lock
);
1015 HeapFree(GetProcessHeap(), 0, row_pointers
);
1018 ppng_set_error_fn(This
->png_ptr
, &jmpbuf
, user_error_fn
, user_warning_fn
);
1020 if (!This
->info_written
)
1022 ppng_set_IHDR(This
->png_ptr
, This
->info_ptr
, This
->width
, This
->height
,
1023 This
->format
->bit_depth
, This
->format
->color_type
, PNG_INTERLACE_NONE
,
1024 PNG_COMPRESSION_TYPE_DEFAULT
, PNG_FILTER_TYPE_DEFAULT
);
1026 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1028 ppng_set_pHYs(This
->png_ptr
, This
->info_ptr
, (This
->xres
+0.0127) / 0.0254,
1029 (This
->yres
+0.0127) / 0.0254, PNG_RESOLUTION_METER
);
1032 ppng_write_info(This
->png_ptr
, This
->info_ptr
);
1034 if (This
->format
->remove_filler
)
1035 ppng_set_filler(This
->png_ptr
, 0, PNG_FILLER_AFTER
);
1037 if (This
->format
->swap_rgb
)
1038 ppng_set_bgr(This
->png_ptr
);
1040 This
->info_written
= TRUE
;
1043 row_pointers
= HeapAlloc(GetProcessHeap(), 0, lineCount
* sizeof(png_byte
*));
1046 LeaveCriticalSection(&This
->lock
);
1047 return E_OUTOFMEMORY
;
1050 for (i
=0; i
<lineCount
; i
++)
1051 row_pointers
[i
] = pbPixels
+ cbStride
* i
;
1053 ppng_write_rows(This
->png_ptr
, row_pointers
, lineCount
);
1054 This
->lines_written
+= lineCount
;
1056 LeaveCriticalSection(&This
->lock
);
1058 HeapFree(GetProcessHeap(), 0, row_pointers
);
1063 static HRESULT WINAPI
PngFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1064 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1066 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1069 WICPixelFormatGUID guid
;
1072 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1074 if (!This
->frame_initialized
|| !This
->width
|| !This
->height
)
1075 return WINCODEC_ERR_WRONGSTATE
;
1079 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1080 if (FAILED(hr
)) return hr
;
1081 hr
= IWICBitmapFrameEncode_SetPixelFormat(iface
, &guid
);
1082 if (FAILED(hr
)) return hr
;
1085 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1086 if (FAILED(hr
)) return hr
;
1087 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
1089 /* FIXME: should use WICConvertBitmapSource to convert */
1090 ERR("format %s unsupported\n", debugstr_guid(&guid
));
1094 if (This
->xres
== 0.0 || This
->yres
== 0.0)
1097 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
1098 if (FAILED(hr
)) return hr
;
1099 hr
= IWICBitmapFrameEncode_SetResolution(iface
, xres
, yres
);
1100 if (FAILED(hr
)) return hr
;
1106 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
1107 if (FAILED(hr
)) return hr
;
1115 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
1117 stride
= (This
->format
->bpp
* This
->width
+ 7)/8;
1119 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
1120 if (!pixeldata
) return E_OUTOFMEMORY
;
1122 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
1123 stride
*prc
->Height
, pixeldata
);
1127 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
1128 stride
*prc
->Height
, pixeldata
);
1131 HeapFree(GetProcessHeap(), 0, pixeldata
);
1136 static HRESULT WINAPI
PngFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1138 PngEncoder
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1140 TRACE("(%p)\n", iface
);
1142 EnterCriticalSection(&This
->lock
);
1144 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->frame_committed
)
1146 LeaveCriticalSection(&This
->lock
);
1147 return WINCODEC_ERR_WRONGSTATE
;
1150 /* set up setjmp/longjmp error handling */
1153 LeaveCriticalSection(&This
->lock
);
1156 ppng_set_error_fn(This
->png_ptr
, &jmpbuf
, user_error_fn
, user_warning_fn
);
1158 ppng_write_end(This
->png_ptr
, This
->info_ptr
);
1160 This
->frame_committed
= TRUE
;
1162 LeaveCriticalSection(&This
->lock
);
1167 static HRESULT WINAPI
PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1168 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1170 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1174 static const IWICBitmapFrameEncodeVtbl PngEncoder_FrameVtbl
= {
1175 PngFrameEncode_QueryInterface
,
1176 PngFrameEncode_AddRef
,
1177 PngFrameEncode_Release
,
1178 PngFrameEncode_Initialize
,
1179 PngFrameEncode_SetSize
,
1180 PngFrameEncode_SetResolution
,
1181 PngFrameEncode_SetPixelFormat
,
1182 PngFrameEncode_SetColorContexts
,
1183 PngFrameEncode_SetPalette
,
1184 PngFrameEncode_SetThumbnail
,
1185 PngFrameEncode_WritePixels
,
1186 PngFrameEncode_WriteSource
,
1187 PngFrameEncode_Commit
,
1188 PngFrameEncode_GetMetadataQueryWriter
1191 static HRESULT WINAPI
PngEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1194 PngEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1195 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1197 if (!ppv
) return E_INVALIDARG
;
1199 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1200 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1207 return E_NOINTERFACE
;
1210 IUnknown_AddRef((IUnknown
*)*ppv
);
1214 static ULONG WINAPI
PngEncoder_AddRef(IWICBitmapEncoder
*iface
)
1216 PngEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1217 ULONG ref
= InterlockedIncrement(&This
->ref
);
1219 TRACE("(%p) refcount=%u\n", iface
, ref
);
1224 static ULONG WINAPI
PngEncoder_Release(IWICBitmapEncoder
*iface
)
1226 PngEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1227 ULONG ref
= InterlockedDecrement(&This
->ref
);
1229 TRACE("(%p) refcount=%u\n", iface
, ref
);
1233 This
->lock
.DebugInfo
->Spare
[0] = 0;
1234 DeleteCriticalSection(&This
->lock
);
1236 ppng_destroy_write_struct(&This
->png_ptr
, &This
->info_ptr
);
1238 IStream_Release(This
->stream
);
1239 HeapFree(GetProcessHeap(), 0, This
);
1245 static void user_write_data(png_structp png_ptr
, png_bytep data
, png_size_t length
)
1247 PngEncoder
*This
= ppng_get_io_ptr(png_ptr
);
1251 hr
= IStream_Write(This
->stream
, data
, length
, &byteswritten
);
1252 if (FAILED(hr
) || byteswritten
!= length
)
1254 ppng_error(png_ptr
, "failed writing data");
1258 static void user_flush(png_structp png_ptr
)
1262 static HRESULT WINAPI
PngEncoder_Initialize(IWICBitmapEncoder
*iface
,
1263 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1265 PngEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1268 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1270 EnterCriticalSection(&This
->lock
);
1274 LeaveCriticalSection(&This
->lock
);
1275 return WINCODEC_ERR_WRONGSTATE
;
1278 /* initialize libpng */
1279 This
->png_ptr
= ppng_create_write_struct(PNG_LIBPNG_VER_STRING
, NULL
, NULL
, NULL
);
1282 LeaveCriticalSection(&This
->lock
);
1286 This
->info_ptr
= ppng_create_info_struct(This
->png_ptr
);
1287 if (!This
->info_ptr
)
1289 ppng_destroy_write_struct(&This
->png_ptr
, NULL
);
1290 This
->png_ptr
= NULL
;
1291 LeaveCriticalSection(&This
->lock
);
1295 IStream_AddRef(pIStream
);
1296 This
->stream
= pIStream
;
1298 /* set up setjmp/longjmp error handling */
1301 ppng_destroy_write_struct(&This
->png_ptr
, &This
->info_ptr
);
1302 This
->png_ptr
= NULL
;
1303 IStream_Release(This
->stream
);
1304 This
->stream
= NULL
;
1305 LeaveCriticalSection(&This
->lock
);
1308 ppng_set_error_fn(This
->png_ptr
, &jmpbuf
, user_error_fn
, user_warning_fn
);
1310 /* set up custom i/o handling */
1311 ppng_set_write_fn(This
->png_ptr
, This
, user_write_data
, user_flush
);
1313 LeaveCriticalSection(&This
->lock
);
1318 static HRESULT WINAPI
PngEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1319 GUID
*pguidContainerFormat
)
1321 FIXME("(%p,%s): stub\n", iface
, debugstr_guid(pguidContainerFormat
));
1325 static HRESULT WINAPI
PngEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1326 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1328 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1332 static HRESULT WINAPI
PngEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1333 UINT cCount
, IWICColorContext
**ppIColorContext
)
1335 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1339 static HRESULT WINAPI
PngEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1341 TRACE("(%p,%p)\n", iface
, pIPalette
);
1342 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1345 static HRESULT WINAPI
PngEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1347 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1348 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1351 static HRESULT WINAPI
PngEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1353 TRACE("(%p,%p)\n", iface
, pIPreview
);
1354 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1357 static HRESULT WINAPI
PngEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1358 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1360 PngEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1362 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1364 EnterCriticalSection(&This
->lock
);
1366 if (This
->frame_count
!= 0)
1368 LeaveCriticalSection(&This
->lock
);
1369 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1374 LeaveCriticalSection(&This
->lock
);
1375 return WINCODEC_ERR_NOTINITIALIZED
;
1378 hr
= CreatePropertyBag2(ppIEncoderOptions
);
1381 LeaveCriticalSection(&This
->lock
);
1385 This
->frame_count
= 1;
1387 LeaveCriticalSection(&This
->lock
);
1389 IWICBitmapEncoder_AddRef(iface
);
1390 *ppIFrameEncode
= &This
->IWICBitmapFrameEncode_iface
;
1395 static HRESULT WINAPI
PngEncoder_Commit(IWICBitmapEncoder
*iface
)
1397 PngEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1398 TRACE("(%p)\n", iface
);
1400 EnterCriticalSection(&This
->lock
);
1402 if (!This
->frame_committed
|| This
->committed
)
1404 LeaveCriticalSection(&This
->lock
);
1405 return WINCODEC_ERR_WRONGSTATE
;
1408 This
->committed
= TRUE
;
1410 LeaveCriticalSection(&This
->lock
);
1415 static HRESULT WINAPI
PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
1416 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1418 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
1422 static const IWICBitmapEncoderVtbl PngEncoder_Vtbl
= {
1423 PngEncoder_QueryInterface
,
1426 PngEncoder_Initialize
,
1427 PngEncoder_GetContainerFormat
,
1428 PngEncoder_GetEncoderInfo
,
1429 PngEncoder_SetColorContexts
,
1430 PngEncoder_SetPalette
,
1431 PngEncoder_SetThumbnail
,
1432 PngEncoder_SetPreview
,
1433 PngEncoder_CreateNewFrame
,
1435 PngEncoder_GetMetadataQueryWriter
1438 HRESULT
PngEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1443 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1447 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1449 if (!libpng_handle
&& !load_libpng())
1451 ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG
);
1455 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder
));
1456 if (!This
) return E_OUTOFMEMORY
;
1458 This
->IWICBitmapEncoder_iface
.lpVtbl
= &PngEncoder_Vtbl
;
1459 This
->IWICBitmapFrameEncode_iface
.lpVtbl
= &PngEncoder_FrameVtbl
;
1461 This
->png_ptr
= NULL
;
1462 This
->info_ptr
= NULL
;
1463 This
->stream
= NULL
;
1464 This
->frame_count
= 0;
1465 This
->frame_initialized
= FALSE
;
1466 This
->format
= NULL
;
1467 This
->info_written
= FALSE
;
1472 This
->lines_written
= 0;
1473 This
->frame_committed
= FALSE
;
1474 This
->committed
= FALSE
;
1475 InitializeCriticalSection(&This
->lock
);
1476 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PngEncoder.lock");
1478 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1479 IUnknown_Release((IUnknown
*)This
);
1484 #else /* !HAVE_PNG_H */
1486 HRESULT
PngDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1488 ERR("Trying to load PNG picture, but PNG support is not compiled in.\n");
1492 HRESULT
PngEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1494 ERR("Trying to save PNG picture, but PNG support is not compiled in.\n");