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 HRESULT hr; 833 IWICComponentInfo *compinfo; 834 835 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 836 837 hr = CreateComponentInfo(&CLSID_WICPngDecoder, &compinfo); 838 if (FAILED(hr)) return hr; 839 840 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 841 (void**)ppIDecoderInfo); 842 843 IWICComponentInfo_Release(compinfo); 844 845 return hr; 846 } 847 848 static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface, 849 IWICPalette *palette) 850 { 851 TRACE("(%p,%p)\n", iface, palette); 852 return WINCODEC_ERR_PALETTEUNAVAILABLE; 853 } 854 855 static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 856 IWICMetadataQueryReader **reader) 857 { 858 FIXME("(%p,%p): stub\n", iface, reader); 859 860 if (!reader) return E_INVALIDARG; 861 862 *reader = NULL; 863 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 864 } 865 866 static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface, 867 IWICBitmapSource **ppIBitmapSource) 868 { 869 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 870 871 if (!ppIBitmapSource) return E_INVALIDARG; 872 873 *ppIBitmapSource = NULL; 874 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 875 } 876 877 static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface, 878 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 879 { 880 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 881 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 882 } 883 884 static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface, 885 IWICBitmapSource **ppIThumbnail) 886 { 887 TRACE("(%p,%p)\n", iface, ppIThumbnail); 888 889 if (!ppIThumbnail) return E_INVALIDARG; 890 891 *ppIThumbnail = NULL; 892 return WINCODEC_ERR_CODECNOTHUMBNAIL; 893 } 894 895 static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface, 896 UINT *pCount) 897 { 898 if (!pCount) return E_INVALIDARG; 899 900 *pCount = 1; 901 return S_OK; 902 } 903 904 static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface, 905 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 906 { 907 PngDecoder *This = impl_from_IWICBitmapDecoder(iface); 908 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 909 910 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 911 912 if (index != 0) return E_INVALIDARG; 913 914 IWICBitmapDecoder_AddRef(iface); 915 916 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; 917 918 return S_OK; 919 } 920 921 static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = { 922 PngDecoder_QueryInterface, 923 PngDecoder_AddRef, 924 PngDecoder_Release, 925 PngDecoder_QueryCapability, 926 PngDecoder_Initialize, 927 PngDecoder_GetContainerFormat, 928 PngDecoder_GetDecoderInfo, 929 PngDecoder_CopyPalette, 930 PngDecoder_GetMetadataQueryReader, 931 PngDecoder_GetPreview, 932 PngDecoder_GetColorContexts, 933 PngDecoder_GetThumbnail, 934 PngDecoder_GetFrameCount, 935 PngDecoder_GetFrame 936 }; 937 938 static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 939 void **ppv) 940 { 941 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 942 if (!ppv) return E_INVALIDARG; 943 944 if (IsEqualIID(&IID_IUnknown, iid) || 945 IsEqualIID(&IID_IWICBitmapSource, iid) || 946 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 947 { 948 *ppv = &This->IWICBitmapFrameDecode_iface; 949 } 950 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) 951 { 952 *ppv = &This->IWICMetadataBlockReader_iface; 953 } 954 else 955 { 956 *ppv = NULL; 957 return E_NOINTERFACE; 958 } 959 960 IUnknown_AddRef((IUnknown*)*ppv); 961 return S_OK; 962 } 963 964 static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface) 965 { 966 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 967 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 968 } 969 970 static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface) 971 { 972 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 973 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 974 } 975 976 static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface, 977 UINT *puiWidth, UINT *puiHeight) 978 { 979 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 980 *puiWidth = This->width; 981 *puiHeight = This->height; 982 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight); 983 return S_OK; 984 } 985 986 static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface, 987 WICPixelFormatGUID *pPixelFormat) 988 { 989 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 990 TRACE("(%p,%p)\n", iface, pPixelFormat); 991 992 memcpy(pPixelFormat, This->format, sizeof(GUID)); 993 994 return S_OK; 995 } 996 997 static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface, 998 double *pDpiX, double *pDpiY) 999 { 1000 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 1001 png_uint_32 ret, xres, yres; 1002 int unit_type; 1003 1004 EnterCriticalSection(&This->lock); 1005 1006 ret = ppng_get_pHYs(This->png_ptr, This->info_ptr, &xres, &yres, &unit_type); 1007 1008 if (ret && unit_type == PNG_RESOLUTION_METER) 1009 { 1010 *pDpiX = xres * 0.0254; 1011 *pDpiY = yres * 0.0254; 1012 } 1013 else 1014 { 1015 WARN("no pHYs block present\n"); 1016 *pDpiX = *pDpiY = 96.0; 1017 } 1018 1019 LeaveCriticalSection(&This->lock); 1020 1021 TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY); 1022 1023 return S_OK; 1024 } 1025 1026 static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface, 1027 IWICPalette *pIPalette) 1028 { 1029 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 1030 png_uint_32 ret, color_type, bit_depth; 1031 png_colorp png_palette; 1032 int num_palette; 1033 WICColor palette[256]; 1034 png_bytep trans_alpha; 1035 int num_trans; 1036 png_color_16p trans_values; 1037 int i; 1038 HRESULT hr=S_OK; 1039 1040 TRACE("(%p,%p)\n", iface, pIPalette); 1041 1042 EnterCriticalSection(&This->lock); 1043 1044 color_type = ppng_get_color_type(This->png_ptr, This->info_ptr); 1045 bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr); 1046 1047 if (color_type == PNG_COLOR_TYPE_PALETTE) 1048 { 1049 ret = ppng_get_PLTE(This->png_ptr, This->info_ptr, &png_palette, &num_palette); 1050 if (!ret) 1051 { 1052 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 1053 goto end; 1054 } 1055 1056 if (num_palette > 256) 1057 { 1058 ERR("palette has %i colors?!\n", num_palette); 1059 hr = E_FAIL; 1060 goto end; 1061 } 1062 1063 ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans_alpha, &num_trans, &trans_values); 1064 if (!ret) num_trans = 0; 1065 1066 for (i=0; i<num_palette; i++) 1067 { 1068 BYTE alpha = (i < num_trans) ? trans_alpha[i] : 0xff; 1069 palette[i] = (alpha << 24 | 1070 png_palette[i].red << 16| 1071 png_palette[i].green << 8| 1072 png_palette[i].blue); 1073 } 1074 } 1075 else if (color_type == PNG_COLOR_TYPE_GRAY) { 1076 ret = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans_alpha, &num_trans, &trans_values); 1077 1078 if (!ret) 1079 { 1080 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 1081 goto end; 1082 } 1083 1084 num_palette = 1 << bit_depth; 1085 1086 for (i=0; i<num_palette; i++) 1087 { 1088 BYTE alpha = (i == trans_values[0].gray) ? 0 : 0xff; 1089 BYTE val = i * 255 / (num_palette - 1); 1090 palette[i] = (alpha << 24 | val << 16 | val << 8 | val); 1091 } 1092 } 1093 else 1094 { 1095 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 1096 } 1097 1098 end: 1099 1100 LeaveCriticalSection(&This->lock); 1101 1102 if (SUCCEEDED(hr)) 1103 hr = IWICPalette_InitializeCustom(pIPalette, palette, num_palette); 1104 1105 return hr; 1106 } 1107 1108 static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, 1109 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 1110 { 1111 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 1112 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 1113 1114 return copy_pixels(This->bpp, This->image_bits, 1115 This->width, This->height, This->stride, 1116 prc, cbStride, cbBufferSize, pbBuffer); 1117 } 1118 1119 static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 1120 IWICMetadataQueryReader **ppIMetadataQueryReader) 1121 { 1122 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 1123 1124 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1125 1126 if (!ppIMetadataQueryReader) 1127 return E_INVALIDARG; 1128 1129 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 1130 } 1131 1132 static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface, 1133 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1134 { 1135 PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 1136 png_charp name; 1137 BYTE *profile; 1138 png_uint_32 len; 1139 int compression_type; 1140 HRESULT hr; 1141 1142 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1143 1144 if (!pcActualCount) return E_INVALIDARG; 1145 1146 EnterCriticalSection(&This->lock); 1147 1148 if (ppng_get_iCCP(This->png_ptr, This->info_ptr, &name, &compression_type, (void *)&profile, &len)) 1149 { 1150 if (cCount && ppIColorContexts) 1151 { 1152 hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, len); 1153 if (FAILED(hr)) 1154 { 1155 LeaveCriticalSection(&This->lock); 1156 return hr; 1157 } 1158 } 1159 *pcActualCount = 1; 1160 } 1161 else 1162 *pcActualCount = 0; 1163 1164 LeaveCriticalSection(&This->lock); 1165 1166 return S_OK; 1167 } 1168 1169 static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface, 1170 IWICBitmapSource **ppIThumbnail) 1171 { 1172 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1173 1174 if (!ppIThumbnail) return E_INVALIDARG; 1175 1176 *ppIThumbnail = NULL; 1177 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1178 } 1179 1180 static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = { 1181 PngDecoder_Frame_QueryInterface, 1182 PngDecoder_Frame_AddRef, 1183 PngDecoder_Frame_Release, 1184 PngDecoder_Frame_GetSize, 1185 PngDecoder_Frame_GetPixelFormat, 1186 PngDecoder_Frame_GetResolution, 1187 PngDecoder_Frame_CopyPalette, 1188 PngDecoder_Frame_CopyPixels, 1189 PngDecoder_Frame_GetMetadataQueryReader, 1190 PngDecoder_Frame_GetColorContexts, 1191 PngDecoder_Frame_GetThumbnail 1192 }; 1193 1194 static HRESULT WINAPI PngDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, 1195 void **ppv) 1196 { 1197 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1198 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); 1199 } 1200 1201 static ULONG WINAPI PngDecoder_Block_AddRef(IWICMetadataBlockReader *iface) 1202 { 1203 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1204 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 1205 } 1206 1207 static ULONG WINAPI PngDecoder_Block_Release(IWICMetadataBlockReader *iface) 1208 { 1209 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1210 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1211 } 1212 1213 static HRESULT WINAPI PngDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 1214 GUID *pguidContainerFormat) 1215 { 1216 if (!pguidContainerFormat) return E_INVALIDARG; 1217 memcpy(pguidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID)); 1218 return S_OK; 1219 } 1220 1221 static HRESULT WINAPI PngDecoder_Block_GetCount(IWICMetadataBlockReader *iface, 1222 UINT *pcCount) 1223 { 1224 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1225 1226 TRACE("%p,%p\n", iface, pcCount); 1227 1228 if (!pcCount) return E_INVALIDARG; 1229 1230 *pcCount = This->metadata_count; 1231 1232 return S_OK; 1233 } 1234 1235 static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 1236 UINT nIndex, IWICMetadataReader **ppIMetadataReader) 1237 { 1238 PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1239 HRESULT hr; 1240 IWICComponentFactory* factory; 1241 IWICStream* stream; 1242 1243 TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader); 1244 1245 if (nIndex >= This->metadata_count || !ppIMetadataReader) 1246 return E_INVALIDARG; 1247 1248 if (!This->metadata_blocks[nIndex].reader) 1249 { 1250 hr = StreamImpl_Create(&stream); 1251 1252 if (SUCCEEDED(hr)) 1253 { 1254 hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream, 1255 This->metadata_blocks[nIndex].ofs, This->metadata_blocks[nIndex].len); 1256 1257 if (SUCCEEDED(hr)) 1258 hr = ComponentFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory); 1259 1260 if (SUCCEEDED(hr)) 1261 { 1262 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, 1263 &GUID_ContainerFormatPng, NULL, WICMetadataCreationAllowUnknown, 1264 (IStream*)stream, &This->metadata_blocks[nIndex].reader); 1265 1266 IWICComponentFactory_Release(factory); 1267 } 1268 1269 IWICStream_Release(stream); 1270 } 1271 1272 if (FAILED(hr)) 1273 { 1274 *ppIMetadataReader = NULL; 1275 return hr; 1276 } 1277 } 1278 1279 *ppIMetadataReader = This->metadata_blocks[nIndex].reader; 1280 IWICMetadataReader_AddRef(*ppIMetadataReader); 1281 1282 return S_OK; 1283 } 1284 1285 static HRESULT WINAPI PngDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1286 IEnumUnknown **ppIEnumMetadata) 1287 { 1288 FIXME("%p,%p\n", iface, ppIEnumMetadata); 1289 return E_NOTIMPL; 1290 } 1291 1292 static const IWICMetadataBlockReaderVtbl PngDecoder_BlockVtbl = { 1293 PngDecoder_Block_QueryInterface, 1294 PngDecoder_Block_AddRef, 1295 PngDecoder_Block_Release, 1296 PngDecoder_Block_GetContainerFormat, 1297 PngDecoder_Block_GetCount, 1298 PngDecoder_Block_GetReaderByIndex, 1299 PngDecoder_Block_GetEnumerator, 1300 }; 1301 1302 HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv) 1303 { 1304 PngDecoder *This; 1305 HRESULT ret; 1306 1307 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1308 1309 *ppv = NULL; 1310 1311 if (!load_libpng()) 1312 { 1313 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG); 1314 return E_FAIL; 1315 } 1316 1317 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder)); 1318 if (!This) return E_OUTOFMEMORY; 1319 1320 This->IWICBitmapDecoder_iface.lpVtbl = &PngDecoder_Vtbl; 1321 This->IWICBitmapFrameDecode_iface.lpVtbl = &PngDecoder_FrameVtbl; 1322 This->IWICMetadataBlockReader_iface.lpVtbl = &PngDecoder_BlockVtbl; 1323 This->ref = 1; 1324 This->png_ptr = NULL; 1325 This->info_ptr = NULL; 1326 This->end_info = NULL; 1327 This->stream = NULL; 1328 This->initialized = FALSE; 1329 This->image_bits = NULL; 1330 InitializeCriticalSection(&This->lock); 1331 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngDecoder.lock"); 1332 This->metadata_count = 0; 1333 This->metadata_blocks = NULL; 1334 1335 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1336 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1337 1338 return ret; 1339 } 1340 1341 struct png_pixelformat { 1342 const WICPixelFormatGUID *guid; 1343 UINT bpp; 1344 int bit_depth; 1345 int color_type; 1346 BOOL remove_filler; 1347 BOOL swap_rgb; 1348 }; 1349 1350 static const struct png_pixelformat formats[] = { 1351 {&GUID_WICPixelFormat32bppBGRA, 32, 8, PNG_COLOR_TYPE_RGB_ALPHA, 0, 1}, 1352 {&GUID_WICPixelFormat24bppBGR, 24, 8, PNG_COLOR_TYPE_RGB, 0, 1}, 1353 {&GUID_WICPixelFormatBlackWhite, 1, 1, PNG_COLOR_TYPE_GRAY, 0, 0}, 1354 {&GUID_WICPixelFormat2bppGray, 2, 2, PNG_COLOR_TYPE_GRAY, 0, 0}, 1355 {&GUID_WICPixelFormat4bppGray, 4, 4, PNG_COLOR_TYPE_GRAY, 0, 0}, 1356 {&GUID_WICPixelFormat8bppGray, 8, 8, PNG_COLOR_TYPE_GRAY, 0, 0}, 1357 {&GUID_WICPixelFormat16bppGray, 16, 16, PNG_COLOR_TYPE_GRAY, 0, 0}, 1358 {&GUID_WICPixelFormat32bppBGR, 32, 8, PNG_COLOR_TYPE_RGB, 1, 1}, 1359 {&GUID_WICPixelFormat48bppRGB, 48, 16, PNG_COLOR_TYPE_RGB, 0, 0}, 1360 {&GUID_WICPixelFormat64bppRGBA, 64, 16, PNG_COLOR_TYPE_RGB_ALPHA, 0, 0}, 1361 {&GUID_WICPixelFormat1bppIndexed, 1, 1, PNG_COLOR_TYPE_PALETTE, 0, 0}, 1362 {&GUID_WICPixelFormat2bppIndexed, 2, 2, PNG_COLOR_TYPE_PALETTE, 0, 0}, 1363 {&GUID_WICPixelFormat4bppIndexed, 4, 4, PNG_COLOR_TYPE_PALETTE, 0, 0}, 1364 {&GUID_WICPixelFormat8bppIndexed, 8, 8, PNG_COLOR_TYPE_PALETTE, 0, 0}, 1365 {NULL}, 1366 }; 1367 1368 typedef struct PngEncoder { 1369 IWICBitmapEncoder IWICBitmapEncoder_iface; 1370 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 1371 LONG ref; 1372 IStream *stream; 1373 png_structp png_ptr; 1374 png_infop info_ptr; 1375 UINT frame_count; 1376 BOOL frame_initialized; 1377 const struct png_pixelformat *format; 1378 BOOL info_written; 1379 UINT width, height; 1380 double xres, yres; 1381 UINT lines_written; 1382 BOOL frame_committed; 1383 BOOL committed; 1384 CRITICAL_SECTION lock; 1385 BOOL interlace; 1386 WICPngFilterOption filter; 1387 BYTE *data; 1388 UINT stride; 1389 UINT passes; 1390 WICColor palette[256]; 1391 UINT colors; 1392 } PngEncoder; 1393 1394 static inline PngEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 1395 { 1396 return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapEncoder_iface); 1397 } 1398 1399 static inline PngEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 1400 { 1401 return CONTAINING_RECORD(iface, PngEncoder, IWICBitmapFrameEncode_iface); 1402 } 1403 1404 static HRESULT WINAPI PngFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, 1405 void **ppv) 1406 { 1407 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1408 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1409 1410 if (!ppv) return E_INVALIDARG; 1411 1412 if (IsEqualIID(&IID_IUnknown, iid) || 1413 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 1414 { 1415 *ppv = &This->IWICBitmapFrameEncode_iface; 1416 } 1417 else 1418 { 1419 *ppv = NULL; 1420 return E_NOINTERFACE; 1421 } 1422 1423 IUnknown_AddRef((IUnknown*)*ppv); 1424 return S_OK; 1425 } 1426 1427 static ULONG WINAPI PngFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 1428 { 1429 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1430 return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface); 1431 } 1432 1433 static ULONG WINAPI PngFrameEncode_Release(IWICBitmapFrameEncode *iface) 1434 { 1435 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1436 return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 1437 } 1438 1439 static HRESULT WINAPI PngFrameEncode_Initialize(IWICBitmapFrameEncode *iface, 1440 IPropertyBag2 *pIEncoderOptions) 1441 { 1442 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1443 WICPngFilterOption filter; 1444 BOOL interlace; 1445 PROPBAG2 opts[2]= {{0}}; 1446 VARIANT opt_values[2]; 1447 HRESULT opt_hres[2]; 1448 HRESULT hr; 1449 1450 TRACE("(%p,%p)\n", iface, pIEncoderOptions); 1451 1452 opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption; 1453 opts[0].vt = VT_BOOL; 1454 opts[1].pstrName = (LPOLESTR)wszPngFilterOption; 1455 opts[1].vt = VT_UI1; 1456 1457 if (pIEncoderOptions) 1458 { 1459 hr = IPropertyBag2_Read(pIEncoderOptions, sizeof(opts)/sizeof(opts[0]), opts, NULL, opt_values, opt_hres); 1460 1461 if (FAILED(hr)) 1462 return hr; 1463 1464 if (V_VT(&opt_values[0]) == VT_EMPTY) 1465 interlace = FALSE; 1466 else 1467 interlace = (V_BOOL(&opt_values[0]) != 0); 1468 1469 filter = V_UI1(&opt_values[1]); 1470 if (filter > WICPngFilterAdaptive) 1471 { 1472 WARN("Unrecognized filter option value %u.\n", filter); 1473 filter = WICPngFilterUnspecified; 1474 } 1475 } 1476 else 1477 { 1478 interlace = FALSE; 1479 filter = WICPngFilterUnspecified; 1480 } 1481 1482 EnterCriticalSection(&This->lock); 1483 1484 if (This->frame_initialized) 1485 { 1486 LeaveCriticalSection(&This->lock); 1487 return WINCODEC_ERR_WRONGSTATE; 1488 } 1489 1490 This->interlace = interlace; 1491 This->filter = filter; 1492 1493 This->frame_initialized = TRUE; 1494 1495 LeaveCriticalSection(&This->lock); 1496 1497 return S_OK; 1498 } 1499 1500 static HRESULT WINAPI PngFrameEncode_SetSize(IWICBitmapFrameEncode *iface, 1501 UINT uiWidth, UINT uiHeight) 1502 { 1503 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1504 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); 1505 1506 EnterCriticalSection(&This->lock); 1507 1508 if (!This->frame_initialized || This->info_written) 1509 { 1510 LeaveCriticalSection(&This->lock); 1511 return WINCODEC_ERR_WRONGSTATE; 1512 } 1513 1514 This->width = uiWidth; 1515 This->height = uiHeight; 1516 1517 LeaveCriticalSection(&This->lock); 1518 1519 return S_OK; 1520 } 1521 1522 static HRESULT WINAPI PngFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, 1523 double dpiX, double dpiY) 1524 { 1525 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1526 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); 1527 1528 EnterCriticalSection(&This->lock); 1529 1530 if (!This->frame_initialized || This->info_written) 1531 { 1532 LeaveCriticalSection(&This->lock); 1533 return WINCODEC_ERR_WRONGSTATE; 1534 } 1535 1536 This->xres = dpiX; 1537 This->yres = dpiY; 1538 1539 LeaveCriticalSection(&This->lock); 1540 1541 return S_OK; 1542 } 1543 1544 static HRESULT WINAPI PngFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, 1545 WICPixelFormatGUID *pPixelFormat) 1546 { 1547 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1548 int i; 1549 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); 1550 1551 EnterCriticalSection(&This->lock); 1552 1553 if (!This->frame_initialized || This->info_written) 1554 { 1555 LeaveCriticalSection(&This->lock); 1556 return WINCODEC_ERR_WRONGSTATE; 1557 } 1558 1559 for (i=0; formats[i].guid; i++) 1560 { 1561 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0) 1562 break; 1563 } 1564 1565 if (!formats[i].guid) i = 0; 1566 1567 This->format = &formats[i]; 1568 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 1569 1570 LeaveCriticalSection(&This->lock); 1571 1572 return S_OK; 1573 } 1574 1575 static HRESULT WINAPI PngFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, 1576 UINT cCount, IWICColorContext **ppIColorContext) 1577 { 1578 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 1579 return E_NOTIMPL; 1580 } 1581 1582 static HRESULT WINAPI PngFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, 1583 IWICPalette *palette) 1584 { 1585 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1586 HRESULT hr; 1587 1588 TRACE("(%p,%p)\n", iface, palette); 1589 1590 if (!palette) return E_INVALIDARG; 1591 1592 EnterCriticalSection(&This->lock); 1593 1594 if (This->frame_initialized) 1595 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 1596 else 1597 hr = WINCODEC_ERR_NOTINITIALIZED; 1598 1599 LeaveCriticalSection(&This->lock); 1600 return hr; 1601 } 1602 1603 static HRESULT WINAPI PngFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, 1604 IWICBitmapSource *pIThumbnail) 1605 { 1606 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 1607 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1608 } 1609 1610 static HRESULT WINAPI PngFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, 1611 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 1612 { 1613 PngEncoder *This = impl_from_IWICBitmapFrameEncode(iface); 1614 png_byte **row_pointers=NULL; 1615 UINT i; 1616 jmp_buf jmpbuf; 1617 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 1618 1619 EnterCriticalSection(&This->lock); 1620 1621 if (!This->frame_initialized || !This->width || !This->height || !This->format) 1622 { 1623 LeaveCriticalSection(&This->lock); 1624 return WINCODEC_ERR_WRONGSTATE; 1625 } 1626 1627 if (lineCount == 0 || lineCount + This->lines_written > This->height) 1628 { 1629 LeaveCriticalSection(&This->lock); 1630 return E_INVALIDARG; 1631 } 1632 1633 /* set up setjmp/longjmp error handling */ 1634 if (setjmp(jmpbuf)) 1635 { 1636 LeaveCriticalSection(&This->lock); 1637 HeapFree(GetProcessHeap(), 0, row_pointers); 1638 return E_FAIL; 1639 } 1640 ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); 1641 1642 if (!This->info_written) 1643 { 1644 if (This->interlace) 1645 { 1646 /* libpng requires us to write all data multiple times in this case. */ 1647 This->stride = (This->format->bpp * This->width + 7)/8; 1648 This->data = HeapAlloc(GetProcessHeap(), 0, This->height * This->stride); 1649 if (!This->data) 1650 { 1651 LeaveCriticalSection(&This->lock); 1652 return E_OUTOFMEMORY; 1653 } 1654 } 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,%p)\n", iface, pIBitmapSource, 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, 1987 GUID *pguidContainerFormat) 1988 { 1989 FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat)); 1990 return E_NOTIMPL; 1991 } 1992 1993 static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 1994 { 1995 IWICComponentInfo *comp_info; 1996 HRESULT hr; 1997 1998 TRACE("%p,%p\n", iface, info); 1999 2000 if (!info) return E_INVALIDARG; 2001 2002 hr = CreateComponentInfo(&CLSID_WICPngEncoder, &comp_info); 2003 if (hr == S_OK) 2004 { 2005 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 2006 IWICComponentInfo_Release(comp_info); 2007 } 2008 return hr; 2009 } 2010 2011 static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface, 2012 UINT cCount, IWICColorContext **ppIColorContext) 2013 { 2014 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 2015 return E_NOTIMPL; 2016 } 2017 2018 static HRESULT WINAPI PngEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) 2019 { 2020 PngEncoder *This = impl_from_IWICBitmapEncoder(iface); 2021 HRESULT hr; 2022 2023 TRACE("(%p,%p)\n", iface, palette); 2024 2025 EnterCriticalSection(&This->lock); 2026 2027 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED; 2028 2029 LeaveCriticalSection(&This->lock); 2030 2031 return hr; 2032 } 2033 2034 static HRESULT WINAPI PngEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) 2035 { 2036 TRACE("(%p,%p)\n", iface, pIThumbnail); 2037 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2038 } 2039 2040 static HRESULT WINAPI PngEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) 2041 { 2042 TRACE("(%p,%p)\n", iface, pIPreview); 2043 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2044 } 2045 2046 static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, 2047 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions) 2048 { 2049 PngEncoder *This = impl_from_IWICBitmapEncoder(iface); 2050 HRESULT hr; 2051 static const PROPBAG2 opts[2] = 2052 { 2053 { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszPngInterlaceOption }, 2054 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszPngFilterOption }, 2055 }; 2056 2057 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); 2058 2059 EnterCriticalSection(&This->lock); 2060 2061 if (This->frame_count != 0) 2062 { 2063 LeaveCriticalSection(&This->lock); 2064 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2065 } 2066 2067 if (!This->stream) 2068 { 2069 LeaveCriticalSection(&This->lock); 2070 return WINCODEC_ERR_NOTINITIALIZED; 2071 } 2072 2073 if (ppIEncoderOptions) 2074 { 2075 hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); 2076 if (FAILED(hr)) 2077 { 2078 LeaveCriticalSection(&This->lock); 2079 return hr; 2080 } 2081 } 2082 2083 This->frame_count = 1; 2084 2085 LeaveCriticalSection(&This->lock); 2086 2087 IWICBitmapEncoder_AddRef(iface); 2088 *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface; 2089 2090 return S_OK; 2091 } 2092 2093 static HRESULT WINAPI PngEncoder_Commit(IWICBitmapEncoder *iface) 2094 { 2095 PngEncoder *This = impl_from_IWICBitmapEncoder(iface); 2096 TRACE("(%p)\n", iface); 2097 2098 EnterCriticalSection(&This->lock); 2099 2100 if (!This->frame_committed || This->committed) 2101 { 2102 LeaveCriticalSection(&This->lock); 2103 return WINCODEC_ERR_WRONGSTATE; 2104 } 2105 2106 This->committed = TRUE; 2107 2108 LeaveCriticalSection(&This->lock); 2109 2110 return S_OK; 2111 } 2112 2113 static HRESULT WINAPI PngEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, 2114 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 2115 { 2116 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); 2117 return E_NOTIMPL; 2118 } 2119 2120 static const IWICBitmapEncoderVtbl PngEncoder_Vtbl = { 2121 PngEncoder_QueryInterface, 2122 PngEncoder_AddRef, 2123 PngEncoder_Release, 2124 PngEncoder_Initialize, 2125 PngEncoder_GetContainerFormat, 2126 PngEncoder_GetEncoderInfo, 2127 PngEncoder_SetColorContexts, 2128 PngEncoder_SetPalette, 2129 PngEncoder_SetThumbnail, 2130 PngEncoder_SetPreview, 2131 PngEncoder_CreateNewFrame, 2132 PngEncoder_Commit, 2133 PngEncoder_GetMetadataQueryWriter 2134 }; 2135 2136 HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) 2137 { 2138 PngEncoder *This; 2139 HRESULT ret; 2140 2141 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 2142 2143 *ppv = NULL; 2144 2145 if (!load_libpng()) 2146 { 2147 ERR("Failed writing PNG because unable to find %s\n",SONAME_LIBPNG); 2148 return E_FAIL; 2149 } 2150 2151 This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngEncoder)); 2152 if (!This) return E_OUTOFMEMORY; 2153 2154 This->IWICBitmapEncoder_iface.lpVtbl = &PngEncoder_Vtbl; 2155 This->IWICBitmapFrameEncode_iface.lpVtbl = &PngEncoder_FrameVtbl; 2156 This->ref = 1; 2157 This->png_ptr = NULL; 2158 This->info_ptr = NULL; 2159 This->stream = NULL; 2160 This->frame_count = 0; 2161 This->frame_initialized = FALSE; 2162 This->format = NULL; 2163 This->info_written = FALSE; 2164 This->width = 0; 2165 This->height = 0; 2166 This->xres = 0.0; 2167 This->yres = 0.0; 2168 This->lines_written = 0; 2169 This->frame_committed = FALSE; 2170 This->committed = FALSE; 2171 This->data = NULL; 2172 This->colors = 0; 2173 InitializeCriticalSection(&This->lock); 2174 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngEncoder.lock"); 2175 2176 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 2177 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 2178 2179 return ret; 2180 } 2181 2182 #else /* !HAVE_PNG_H */ 2183 2184 HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv) 2185 { 2186 ERR("Trying to load PNG picture, but PNG support is not compiled in.\n"); 2187 return E_FAIL; 2188 } 2189 2190 HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) 2191 { 2192 ERR("Trying to save PNG picture, but PNG support is not compiled in.\n"); 2193 return E_FAIL; 2194 } 2195 2196 #endif 2197