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_image_height);
55 MAKE_FUNCPTR(png_get_image_width);
56 MAKE_FUNCPTR(png_get_io_ptr);
57 MAKE_FUNCPTR(png_get_pHYs);
58 MAKE_FUNCPTR(png_get_PLTE);
59 MAKE_FUNCPTR(png_get_tRNS);
60 MAKE_FUNCPTR(png_set_bgr);
61 MAKE_FUNCPTR(png_set_gray_1_2_4_to_8);
62 MAKE_FUNCPTR(png_set_gray_to_rgb);
63 MAKE_FUNCPTR(png_set_read_fn);
64 MAKE_FUNCPTR(png_set_strip_16);
65 MAKE_FUNCPTR(png_set_tRNS_to_alpha);
66 MAKE_FUNCPTR(png_set_write_fn);
67 MAKE_FUNCPTR(png_read_end);
68 MAKE_FUNCPTR(png_read_image);
69 MAKE_FUNCPTR(png_read_info);
72 static void *load_libpng(void)
74 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
76 #define LOAD_FUNCPTR(f) \
77 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
78 libpng_handle = NULL; \
81 LOAD_FUNCPTR(png_create_read_struct);
82 LOAD_FUNCPTR(png_create_info_struct);
83 LOAD_FUNCPTR(png_create_write_struct);
84 LOAD_FUNCPTR(png_destroy_read_struct);
85 LOAD_FUNCPTR(png_destroy_write_struct);
86 LOAD_FUNCPTR(png_error);
87 LOAD_FUNCPTR(png_get_bit_depth);
88 LOAD_FUNCPTR(png_get_color_type);
89 LOAD_FUNCPTR(png_get_image_height);
90 LOAD_FUNCPTR(png_get_image_width);
91 LOAD_FUNCPTR(png_get_io_ptr);
92 LOAD_FUNCPTR(png_get_pHYs);
93 LOAD_FUNCPTR(png_get_PLTE);
94 LOAD_FUNCPTR(png_get_tRNS);
95 LOAD_FUNCPTR(png_set_bgr);
96 LOAD_FUNCPTR(png_set_gray_1_2_4_to_8);
97 LOAD_FUNCPTR(png_set_gray_to_rgb);
98 LOAD_FUNCPTR(png_set_read_fn);
99 LOAD_FUNCPTR(png_set_strip_16);
100 LOAD_FUNCPTR(png_set_tRNS_to_alpha);
101 LOAD_FUNCPTR(png_set_write_fn);
102 LOAD_FUNCPTR(png_read_end);
103 LOAD_FUNCPTR(png_read_image);
104 LOAD_FUNCPTR(png_read_info);
108 return libpng_handle;
112 const IWICBitmapDecoderVtbl *lpVtbl;
113 const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
122 const WICPixelFormatGUID *format;
126 static inline PngDecoder *impl_from_frame(IWICBitmapFrameDecode *iface)
128 return CONTAINING_RECORD(iface, PngDecoder, lpFrameVtbl);
131 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl;
133 static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
136 PngDecoder *This = (PngDecoder*)iface;
137 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
139 if (!ppv) return E_INVALIDARG;
141 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
148 return E_NOINTERFACE;
151 IUnknown_AddRef((IUnknown*)*ppv);
155 static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface)
157 PngDecoder *This = (PngDecoder*)iface;
158 ULONG ref = InterlockedIncrement(&This->ref);
160 TRACE("(%p) refcount=%u\n", iface, ref);
165 static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
167 PngDecoder *This = (PngDecoder*)iface;
168 ULONG ref = InterlockedDecrement(&This->ref);
170 TRACE("(%p) refcount=%u\n", iface, ref);
175 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
176 HeapFree(GetProcessHeap(), 0, This->image_bits);
177 HeapFree(GetProcessHeap(), 0, This);
183 static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
184 DWORD *pdwCapability)
186 FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
190 static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
192 IStream *stream = ppng_get_io_ptr(png_ptr);
196 hr = IStream_Read(stream, data, length, &bytesread);
197 if (FAILED(hr) || bytesread != length)
199 ppng_error(png_ptr, "failed reading data");
203 static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
204 WICDecodeOptions cacheOptions)
206 PngDecoder *This = (PngDecoder*)iface;
209 png_bytep *row_pointers=NULL;
212 int color_type, bit_depth;
215 png_uint_32 transparency;
216 png_color_16p trans_values;
217 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
219 /* initialize libpng */
220 This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
221 if (!This->png_ptr) return E_FAIL;
223 This->info_ptr = ppng_create_info_struct(This->png_ptr);
226 ppng_destroy_read_struct(&This->png_ptr, (png_infopp)NULL, (png_infopp)NULL);
227 This->png_ptr = NULL;
231 This->end_info = ppng_create_info_struct(This->png_ptr);
234 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, (png_infopp)NULL);
235 This->png_ptr = NULL;
239 /* set up setjmp/longjmp error handling */
240 if (setjmp(png_jmpbuf(This->png_ptr)))
242 ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info);
243 HeapFree(GetProcessHeap(), 0, row_pointers);
244 This->png_ptr = NULL;
248 /* seek to the start of the stream */
250 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
251 if (FAILED(hr)) return hr;
253 /* set up custom i/o handling */
254 ppng_set_read_fn(This->png_ptr, pIStream, user_read_data);
256 /* read the header */
257 ppng_read_info(This->png_ptr, This->info_ptr);
259 /* choose a pixel format */
260 color_type = ppng_get_color_type(This->png_ptr, This->info_ptr);
261 bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr);
263 /* check for color-keyed alpha */
264 transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
266 if (transparency && color_type != PNG_COLOR_TYPE_PALETTE)
269 if (color_type == PNG_COLOR_TYPE_GRAY)
273 ppng_set_gray_1_2_4_to_8(This->png_ptr);
276 ppng_set_gray_to_rgb(This->png_ptr);
278 ppng_set_tRNS_to_alpha(This->png_ptr);
279 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
284 case PNG_COLOR_TYPE_GRAY:
285 This->bpp = bit_depth;
288 case 1: This->format = &GUID_WICPixelFormatBlackWhite; break;
289 case 2: This->format = &GUID_WICPixelFormat2bppGray; break;
290 case 4: This->format = &GUID_WICPixelFormat4bppGray; break;
291 case 8: This->format = &GUID_WICPixelFormat8bppGray; break;
292 case 16: This->format = &GUID_WICPixelFormat16bppGray; break;
294 ERR("invalid grayscale bit depth: %i\n", bit_depth);
298 case PNG_COLOR_TYPE_GRAY_ALPHA:
299 /* WIC does not support grayscale alpha formats so use RGBA */
300 ppng_set_gray_to_rgb(This->png_ptr);
301 case PNG_COLOR_TYPE_RGB_ALPHA:
302 This->bpp = bit_depth * 4;
306 ppng_set_bgr(This->png_ptr);
307 This->format = &GUID_WICPixelFormat32bppBGRA;
309 case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break;
311 ERR("invalid RGBA bit depth: %i\n", bit_depth);
315 case PNG_COLOR_TYPE_PALETTE:
316 This->bpp = bit_depth;
319 case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break;
320 case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break;
321 case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break;
322 case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break;
324 ERR("invalid indexed color bit depth: %i\n", bit_depth);
328 case PNG_COLOR_TYPE_RGB:
329 This->bpp = bit_depth * 3;
333 ppng_set_bgr(This->png_ptr);
334 This->format = &GUID_WICPixelFormat24bppBGR;
336 case 16: This->format = &GUID_WICPixelFormat48bppRGB; break;
338 ERR("invalid RGB color bit depth: %i\n", bit_depth);
343 ERR("invalid color type %i\n", color_type);
347 /* read the image data */
348 This->width = ppng_get_image_width(This->png_ptr, This->info_ptr);
349 This->height = ppng_get_image_height(This->png_ptr, This->info_ptr);
350 This->stride = This->width * This->bpp;
351 image_size = This->stride * This->height;
353 This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size);
354 if (!This->image_bits) return E_OUTOFMEMORY;
356 row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height);
357 if (!row_pointers) return E_OUTOFMEMORY;
359 for (i=0; i<This->height; i++)
360 row_pointers[i] = This->image_bits + i * This->stride;
362 ppng_read_image(This->png_ptr, row_pointers);
364 HeapFree(GetProcessHeap(), 0, row_pointers);
367 ppng_read_end(This->png_ptr, This->end_info);
369 This->initialized = TRUE;
374 static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
375 GUID *pguidContainerFormat)
377 memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID));
381 static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
382 IWICBitmapDecoderInfo **ppIDecoderInfo)
384 FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
388 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface,
389 IWICPalette *pIPalette)
391 FIXME("(%p,%p): stub\n", iface, pIPalette);
395 static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
396 IWICMetadataQueryReader **ppIMetadataQueryReader)
398 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
402 static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface,
403 IWICBitmapSource **ppIBitmapSource)
405 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
409 static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface,
410 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
412 FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
416 static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface,
417 IWICBitmapSource **ppIThumbnail)
419 TRACE("(%p,%p)\n", iface, ppIThumbnail);
420 return WINCODEC_ERR_CODECNOTHUMBNAIL;
423 static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface,
430 static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface,
431 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
433 PngDecoder *This = (PngDecoder*)iface;
434 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
436 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
438 if (index != 0) return E_INVALIDARG;
440 IWICBitmapDecoder_AddRef(iface);
442 *ppIBitmapFrame = (void*)(&This->lpFrameVtbl);
447 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = {
448 PngDecoder_QueryInterface,
451 PngDecoder_QueryCapability,
452 PngDecoder_Initialize,
453 PngDecoder_GetContainerFormat,
454 PngDecoder_GetDecoderInfo,
455 PngDecoder_CopyPalette,
456 PngDecoder_GetMetadataQueryReader,
457 PngDecoder_GetPreview,
458 PngDecoder_GetColorContexts,
459 PngDecoder_GetThumbnail,
460 PngDecoder_GetFrameCount,
464 static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
467 if (!ppv) return E_INVALIDARG;
469 if (IsEqualIID(&IID_IUnknown, iid) ||
470 IsEqualIID(&IID_IWICBitmapSource, iid) ||
471 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
478 return E_NOINTERFACE;
481 IUnknown_AddRef((IUnknown*)*ppv);
485 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
487 PngDecoder *This = impl_from_frame(iface);
488 return IUnknown_AddRef((IUnknown*)This);
491 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
493 PngDecoder *This = impl_from_frame(iface);
494 return IUnknown_Release((IUnknown*)This);
497 static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
498 UINT *puiWidth, UINT *puiHeight)
500 PngDecoder *This = impl_from_frame(iface);
501 *puiWidth = This->width;
502 *puiHeight = This->height;
503 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
507 static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
508 WICPixelFormatGUID *pPixelFormat)
510 PngDecoder *This = impl_from_frame(iface);
511 TRACE("(%p,%p)\n", iface, pPixelFormat);
513 memcpy(pPixelFormat, This->format, sizeof(GUID));
518 static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
519 double *pDpiX, double *pDpiY)
521 PngDecoder *This = impl_from_frame(iface);
522 png_uint_32 ret, xres, yres;
525 ret = ppng_get_pHYs(This->png_ptr, This->info_ptr, &xres, &yres, &unit_type);
527 if (ret && unit_type == PNG_RESOLUTION_METER)
529 *pDpiX = xres * 0.0254;
530 *pDpiY = yres * 0.0254;
534 WARN("no pHYs block present\n");
535 *pDpiX = *pDpiY = 96.0;
538 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
543 static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
544 IWICPalette *pIPalette)
546 PngDecoder *This = impl_from_frame(iface);
548 png_colorp png_palette;
550 WICColor palette[256];
553 png_color_16p trans_values;
556 TRACE("(%p,%p)\n", iface, pIPalette);
558 ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette);
559 if (!ret) return WINCODEC_ERR_PALETTEUNAVAILABLE;
561 if (num_palette > 256)
563 ERR("palette has %i colors?!\n", num_palette);
567 for (i=0; i<num_palette; i++)
569 palette[i] = (0xff000000|
570 png_palette[i].red << 16|
571 png_palette[i].green << 8|
572 png_palette[i].blue);
575 ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values);
578 for (i=0; i<num_trans; i++)
580 palette[trans[i]] = 0x00000000;
584 return IWICPalette_InitializeCustom(pIPalette, palette, num_palette);
587 static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
588 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
590 PngDecoder *This = impl_from_frame(iface);
591 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
593 return copy_pixels(This->bpp, This->image_bits,
594 This->width, This->height, This->stride,
595 prc, cbStride, cbBufferSize, pbBuffer);
598 static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
599 IWICMetadataQueryReader **ppIMetadataQueryReader)
601 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
605 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface,
606 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
608 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
612 static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface,
613 IWICBitmapSource **ppIThumbnail)
615 FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
619 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = {
620 PngDecoder_Frame_QueryInterface,
621 PngDecoder_Frame_AddRef,
622 PngDecoder_Frame_Release,
623 PngDecoder_Frame_GetSize,
624 PngDecoder_Frame_GetPixelFormat,
625 PngDecoder_Frame_GetResolution,
626 PngDecoder_Frame_CopyPalette,
627 PngDecoder_Frame_CopyPixels,
628 PngDecoder_Frame_GetMetadataQueryReader,
629 PngDecoder_Frame_GetColorContexts,
630 PngDecoder_Frame_GetThumbnail
633 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
638 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
642 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
644 if (!libpng_handle && !load_libpng())
646 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
650 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder));
651 if (!This) return E_OUTOFMEMORY;
653 This->lpVtbl = &PngDecoder_Vtbl;
654 This->lpFrameVtbl = &PngDecoder_FrameVtbl;
656 This->png_ptr = NULL;
657 This->info_ptr = NULL;
658 This->end_info = NULL;
659 This->initialized = FALSE;
660 This->image_bits = NULL;
662 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
663 IUnknown_Release((IUnknown*)This);
668 struct png_pixelformat {
669 const WICPixelFormatGUID *guid;
677 static const struct png_pixelformat formats[] = {
678 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1},
679 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0},
680 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0},
681 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0},
682 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0},
683 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0},
684 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1},
685 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1},
686 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0},
687 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0},
691 typedef struct PngEncoder {
692 const IWICBitmapEncoderVtbl *lpVtbl;
693 const IWICBitmapFrameEncodeVtbl *lpFrameVtbl;
699 BOOL frame_initialized;
700 const struct png_pixelformat *format;
705 static inline PngEncoder *encoder_from_frame(IWICBitmapFrameEncode *iface)
707 return CONTAINING_RECORD(iface, PngEncoder, lpFrameVtbl);
710 static HRESULT WINAPI PngFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
713 PngEncoder *This = encoder_from_frame(iface);
714 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
716 if (!ppv) return E_INVALIDARG;
718 if (IsEqualIID(&IID_IUnknown, iid) ||
719 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
721 *ppv = &This->lpFrameVtbl;
726 return E_NOINTERFACE;
729 IUnknown_AddRef((IUnknown*)*ppv);
733 static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
735 PngEncoder *This = encoder_from_frame(iface);
736 return IUnknown_AddRef((IUnknown*)This);
739 static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface)
741 PngEncoder *This = encoder_from_frame(iface);
742 return IUnknown_Release((IUnknown*)This);
745 static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
746 IPropertyBag2 *pIEncoderOptions)
748 PngEncoder *This = encoder_from_frame(iface);
749 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
751 if (This->frame_initialized) return WINCODEC_ERR_WRONGSTATE;
753 This->frame_initialized = TRUE;
758 static HRESULT WINAPI PngFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
759 UINT uiWidth, UINT uiHeight)
761 PngEncoder *This = encoder_from_frame(iface);
762 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
764 if (!This->frame_initialized || This->info_written) return WINCODEC_ERR_WRONGSTATE;
766 This->width = uiWidth;
767 This->height = uiHeight;
772 static HRESULT WINAPI PngFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
773 double dpiX, double dpiY)
775 FIXME("(%p,%0.2f,%0.2f): stub\n", iface, dpiX, dpiY);
779 static HRESULT WINAPI PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
780 WICPixelFormatGUID *pPixelFormat)
782 PngEncoder *This = encoder_from_frame(iface);
784 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
786 if (!This->frame_initialized || This->info_written) return WINCODEC_ERR_WRONGSTATE;
788 for (i=0; formats[i].guid; i++)
790 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
794 if (!formats[i].guid) i = 0;
796 This->format = &formats[i];
797 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
802 static HRESULT WINAPI PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
803 UINT cCount, IWICColorContext **ppIColorContext)
805 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
809 static HRESULT WINAPI PngFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
810 IWICPalette *pIPalette)
812 FIXME("(%p,%p): stub\n", iface, pIPalette);
813 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
816 static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
817 IWICBitmapSource *pIThumbnail)
819 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
820 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
823 static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
824 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
826 FIXME("(%p,%u,%u,%u,%p): stub\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
830 static HRESULT WINAPI PngFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
831 IWICBitmapSource *pIBitmapSource, WICRect *prc)
833 FIXME("(%p,%p,%p): stub\n", iface, pIBitmapSource, prc);
837 static HRESULT WINAPI PngFrameEncode_Commit(IWICBitmapFrameEncode *iface)
839 FIXME("(%p): stub\n", iface);
843 static HRESULT WINAPI PngFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
844 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
846 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
850 static const IWICBitmapFrameEncodeVtbl PngEncoder_FrameVtbl = {
851 PngFrameEncode_QueryInterface,
852 PngFrameEncode_AddRef,
853 PngFrameEncode_Release,
854 PngFrameEncode_Initialize,
855 PngFrameEncode_SetSize,
856 PngFrameEncode_SetResolution,
857 PngFrameEncode_SetPixelFormat,
858 PngFrameEncode_SetColorContexts,
859 PngFrameEncode_SetPalette,
860 PngFrameEncode_SetThumbnail,
861 PngFrameEncode_WritePixels,
862 PngFrameEncode_WriteSource,
863 PngFrameEncode_Commit,
864 PngFrameEncode_GetMetadataQueryWriter
867 static HRESULT WINAPI PngEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
870 PngEncoder *This = (PngEncoder*)iface;
871 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
873 if (!ppv) return E_INVALIDARG;
875 if (IsEqualIID(&IID_IUnknown, iid) ||
876 IsEqualIID(&IID_IWICBitmapEncoder, iid))
883 return E_NOINTERFACE;
886 IUnknown_AddRef((IUnknown*)*ppv);
890 static ULONG WINAPI PngEncoder_AddRef(IWICBitmapEncoder *iface)
892 PngEncoder *This = (PngEncoder*)iface;
893 ULONG ref = InterlockedIncrement(&This->ref);
895 TRACE("(%p) refcount=%u\n", iface, ref);
900 static ULONG WINAPI PngEncoder_Release(IWICBitmapEncoder *iface)
902 PngEncoder *This = (PngEncoder*)iface;
903 ULONG ref = InterlockedDecrement(&This->ref);
905 TRACE("(%p) refcount=%u\n", iface, ref);
910 ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
912 IStream_Release(This->stream);
913 HeapFree(GetProcessHeap(), 0, This);
919 static void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
921 PngEncoder *This = ppng_get_io_ptr(png_ptr);
925 hr = IStream_Write(This->stream, data, length, &byteswritten);
926 if (FAILED(hr) || byteswritten != length)
928 ppng_error(png_ptr, "failed writing data");
932 static void user_flush(png_structp png_ptr)
936 static HRESULT WINAPI PngEncoder_Initialize(IWICBitmapEncoder *iface,
937 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
939 PngEncoder *This = (PngEncoder*)iface;
941 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
944 return WINCODEC_ERR_WRONGSTATE;
946 /* initialize libpng */
947 This->png_ptr = ppng_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
951 This->info_ptr = ppng_create_info_struct(This->png_ptr);
954 ppng_destroy_write_struct(&This->png_ptr, (png_infopp)NULL);
955 This->png_ptr = NULL;
959 IStream_AddRef(pIStream);
960 This->stream = pIStream;
962 /* set up setjmp/longjmp error handling */
963 if (setjmp(png_jmpbuf(This->png_ptr)))
965 ppng_destroy_write_struct(&This->png_ptr, &This->info_ptr);
966 This->png_ptr = NULL;
967 IStream_Release(This->stream);
972 /* set up custom i/o handling */
973 ppng_set_write_fn(This->png_ptr, This, user_write_data, user_flush);
978 static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
979 GUID *pguidContainerFormat)
981 FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
985 static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
986 IWICBitmapEncoderInfo **ppIEncoderInfo)
988 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
992 static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface,
993 UINT cCount, IWICColorContext **ppIColorContext)
995 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
999 static HRESULT WINAPI PngEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
1001 TRACE("(%p,%p)\n", iface, pIPalette);
1002 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1005 static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1007 TRACE("(%p,%p)\n", iface, pIThumbnail);
1008 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1011 static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1013 TRACE("(%p,%p)\n", iface, pIPreview);
1014 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1017 static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1018 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1020 PngEncoder *This = (PngEncoder*)iface;
1022 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
1024 if (This->frame_count != 0)
1025 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1028 return WINCODEC_ERR_NOTINITIALIZED;
1030 hr = CreatePropertyBag2(ppIEncoderOptions);
1031 if (FAILED(hr)) return hr;
1033 This->frame_count = 1;
1035 IWICBitmapEncoder_AddRef(iface);
1036 *ppIFrameEncode = (IWICBitmapFrameEncode*)&This->lpFrameVtbl;
1041 static HRESULT WINAPI PngEncoder_Commit(IWICBitmapEncoder *iface)
1043 TRACE("(%p): stub\n", iface);
1047 static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1048 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1050 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1054 static const IWICBitmapEncoderVtbl PngEncoder_Vtbl = {
1055 PngEncoder_QueryInterface,
1058 PngEncoder_Initialize,
1059 PngEncoder_GetContainerFormat,
1060 PngEncoder_GetEncoderInfo,
1061 PngEncoder_SetColorContexts,
1062 PngEncoder_SetPalette,
1063 PngEncoder_SetThumbnail,
1064 PngEncoder_SetPreview,
1065 PngEncoder_CreateNewFrame,
1067 PngEncoder_GetMetadataQueryWriter
1070 HRESULT PngEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1075 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1079 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1081 if (!libpng_handle && !load_libpng())
1083 ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG);
1087 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder));
1088 if (!This) return E_OUTOFMEMORY;
1090 This->lpVtbl = &PngEncoder_Vtbl;
1091 This->lpFrameVtbl = &PngEncoder_FrameVtbl;
1093 This->png_ptr = NULL;
1094 This->info_ptr = NULL;
1095 This->stream = NULL;
1096 This->frame_count = 0;
1097 This->frame_initialized = FALSE;
1098 This->format = NULL;
1099 This->info_written = FALSE;
1103 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
1104 IUnknown_Release((IUnknown*)This);
1109 #else /* !HAVE_PNG_H */
1111 HRESULT PngDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1113 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1117 HRESULT PngEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1119 ERR("Trying to save PNG picture, but PNG supported not compiled in.\n");