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