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