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