1 /* 2 * Copyright 2010 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 #ifdef HAVE_UNISTD_H 25 #include <unistd.h> 26 #endif 27 #ifdef HAVE_TIFFIO_H 28 #include <tiffio.h> 29 #endif 30 31 #define COBJMACROS 32 33 #include "windef.h" 34 #include "winbase.h" 35 #include "objbase.h" 36 37 #include "wincodecs_private.h" 38 39 #include "wine/debug.h" 40 #include "wine/library.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 43 44 #ifdef SONAME_LIBTIFF 45 46 /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which 47 * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they 48 * are supposed to be always 64-bit. 49 * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x. 50 */ 51 #ifdef TIFF_UINT64_T 52 # undef toff_t 53 # define toff_t UINT64 54 #endif 55 56 static CRITICAL_SECTION init_tiff_cs; 57 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug = 58 { 59 0, 0, &init_tiff_cs, 60 { &init_tiff_cs_debug.ProcessLocksList, 61 &init_tiff_cs_debug.ProcessLocksList }, 62 0, 0, { (DWORD_PTR)(__FILE__ ": init_tiff_cs") } 63 }; 64 static CRITICAL_SECTION init_tiff_cs = { &init_tiff_cs_debug, -1, 0, 0, 0, 0 }; 65 66 static const WCHAR wszTiffCompressionMethod[] = {'T','i','f','f','C','o','m','p','r','e','s','s','i','o','n','M','e','t','h','o','d',0}; 67 static const WCHAR wszCompressionQuality[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0}; 68 69 static void *libtiff_handle; 70 #define MAKE_FUNCPTR(f) static typeof(f) * p##f 71 MAKE_FUNCPTR(TIFFClientOpen); 72 MAKE_FUNCPTR(TIFFClose); 73 MAKE_FUNCPTR(TIFFCurrentDirOffset); 74 MAKE_FUNCPTR(TIFFGetField); 75 MAKE_FUNCPTR(TIFFIsByteSwapped); 76 MAKE_FUNCPTR(TIFFNumberOfDirectories); 77 MAKE_FUNCPTR(TIFFReadDirectory); 78 MAKE_FUNCPTR(TIFFReadEncodedStrip); 79 MAKE_FUNCPTR(TIFFReadEncodedTile); 80 MAKE_FUNCPTR(TIFFSetDirectory); 81 MAKE_FUNCPTR(TIFFSetField); 82 MAKE_FUNCPTR(TIFFWriteDirectory); 83 MAKE_FUNCPTR(TIFFWriteScanline); 84 #undef MAKE_FUNCPTR 85 86 static void *load_libtiff(void) 87 { 88 void *result; 89 90 EnterCriticalSection(&init_tiff_cs); 91 92 if (!libtiff_handle && 93 (libtiff_handle = wine_dlopen(SONAME_LIBTIFF, RTLD_NOW, NULL, 0)) != NULL) 94 { 95 void * (*pTIFFSetWarningHandler)(void *); 96 void * (*pTIFFSetWarningHandlerExt)(void *); 97 98 #define LOAD_FUNCPTR(f) \ 99 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \ 100 ERR("failed to load symbol %s\n", #f); \ 101 libtiff_handle = NULL; \ 102 LeaveCriticalSection(&init_tiff_cs); \ 103 return NULL; \ 104 } 105 LOAD_FUNCPTR(TIFFClientOpen); 106 LOAD_FUNCPTR(TIFFClose); 107 LOAD_FUNCPTR(TIFFCurrentDirOffset); 108 LOAD_FUNCPTR(TIFFGetField); 109 LOAD_FUNCPTR(TIFFIsByteSwapped); 110 LOAD_FUNCPTR(TIFFNumberOfDirectories); 111 LOAD_FUNCPTR(TIFFReadDirectory); 112 LOAD_FUNCPTR(TIFFReadEncodedStrip); 113 LOAD_FUNCPTR(TIFFReadEncodedTile); 114 LOAD_FUNCPTR(TIFFSetDirectory); 115 LOAD_FUNCPTR(TIFFSetField); 116 LOAD_FUNCPTR(TIFFWriteDirectory); 117 LOAD_FUNCPTR(TIFFWriteScanline); 118 #undef LOAD_FUNCPTR 119 120 if ((pTIFFSetWarningHandler = wine_dlsym(libtiff_handle, "TIFFSetWarningHandler", NULL, 0))) 121 pTIFFSetWarningHandler(NULL); 122 if ((pTIFFSetWarningHandlerExt = wine_dlsym(libtiff_handle, "TIFFSetWarningHandlerExt", NULL, 0))) 123 pTIFFSetWarningHandlerExt(NULL); 124 } 125 126 result = libtiff_handle; 127 128 LeaveCriticalSection(&init_tiff_cs); 129 return result; 130 } 131 132 static tsize_t tiff_stream_read(thandle_t client_data, tdata_t data, tsize_t size) 133 { 134 IStream *stream = (IStream*)client_data; 135 ULONG bytes_read; 136 HRESULT hr; 137 138 hr = IStream_Read(stream, data, size, &bytes_read); 139 if (FAILED(hr)) bytes_read = 0; 140 return bytes_read; 141 } 142 143 static tsize_t tiff_stream_write(thandle_t client_data, tdata_t data, tsize_t size) 144 { 145 IStream *stream = (IStream*)client_data; 146 ULONG bytes_written; 147 HRESULT hr; 148 149 hr = IStream_Write(stream, data, size, &bytes_written); 150 if (FAILED(hr)) bytes_written = 0; 151 return bytes_written; 152 } 153 154 static toff_t tiff_stream_seek(thandle_t client_data, toff_t offset, int whence) 155 { 156 IStream *stream = (IStream*)client_data; 157 LARGE_INTEGER move; 158 DWORD origin; 159 ULARGE_INTEGER new_position; 160 HRESULT hr; 161 162 move.QuadPart = offset; 163 switch (whence) 164 { 165 case SEEK_SET: 166 origin = STREAM_SEEK_SET; 167 break; 168 case SEEK_CUR: 169 origin = STREAM_SEEK_CUR; 170 break; 171 case SEEK_END: 172 origin = STREAM_SEEK_END; 173 break; 174 default: 175 ERR("unknown whence value %i\n", whence); 176 return -1; 177 } 178 179 hr = IStream_Seek(stream, move, origin, &new_position); 180 if (SUCCEEDED(hr)) return new_position.QuadPart; 181 else return -1; 182 } 183 184 static int tiff_stream_close(thandle_t client_data) 185 { 186 /* Caller is responsible for releasing the stream object. */ 187 return 0; 188 } 189 190 static toff_t tiff_stream_size(thandle_t client_data) 191 { 192 IStream *stream = (IStream*)client_data; 193 STATSTG statstg; 194 HRESULT hr; 195 196 hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME); 197 198 if (SUCCEEDED(hr)) return statstg.cbSize.QuadPart; 199 else return -1; 200 } 201 202 static int tiff_stream_map(thandle_t client_data, tdata_t *addr, toff_t *size) 203 { 204 /* Cannot mmap streams */ 205 return 0; 206 } 207 208 static void tiff_stream_unmap(thandle_t client_data, tdata_t addr, toff_t size) 209 { 210 /* No need to ever do this, since we can't map things. */ 211 } 212 213 static TIFF* tiff_open_stream(IStream *stream, const char *mode) 214 { 215 LARGE_INTEGER zero; 216 217 zero.QuadPart = 0; 218 IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); 219 220 return pTIFFClientOpen("<IStream object>", mode, stream, tiff_stream_read, 221 tiff_stream_write, (void *)tiff_stream_seek, tiff_stream_close, 222 (void *)tiff_stream_size, (void *)tiff_stream_map, (void *)tiff_stream_unmap); 223 } 224 225 typedef struct { 226 IWICBitmapDecoder IWICBitmapDecoder_iface; 227 LONG ref; 228 IStream *stream; 229 CRITICAL_SECTION lock; /* Must be held when tiff is used or initialized is set */ 230 TIFF *tiff; 231 BOOL initialized; 232 } TiffDecoder; 233 234 typedef struct { 235 const WICPixelFormatGUID *format; 236 int bps; 237 int samples; 238 int bpp, source_bpp; 239 int planar; 240 int indexed; 241 int reverse_bgr; 242 int invert_grayscale; 243 UINT width, height; 244 UINT tile_width, tile_height; 245 UINT tile_stride; 246 UINT tile_size; 247 int tiled; 248 UINT tiles_across; 249 UINT resolution_unit; 250 float xres, yres; 251 } tiff_decode_info; 252 253 typedef struct { 254 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 255 IWICMetadataBlockReader IWICMetadataBlockReader_iface; 256 LONG ref; 257 TiffDecoder *parent; 258 UINT index; 259 tiff_decode_info decode_info; 260 INT cached_tile_x, cached_tile_y; 261 BYTE *cached_tile; 262 } TiffFrameDecode; 263 264 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl; 265 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl; 266 267 static inline TiffDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 268 { 269 return CONTAINING_RECORD(iface, TiffDecoder, IWICBitmapDecoder_iface); 270 } 271 272 static inline TiffFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 273 { 274 return CONTAINING_RECORD(iface, TiffFrameDecode, IWICBitmapFrameDecode_iface); 275 } 276 277 static inline TiffFrameDecode *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) 278 { 279 return CONTAINING_RECORD(iface, TiffFrameDecode, IWICMetadataBlockReader_iface); 280 } 281 282 static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) 283 { 284 uint16 photometric, bps, samples, planar; 285 uint16 extra_sample_count, extra_sample, *extra_samples; 286 int ret; 287 288 decode_info->indexed = 0; 289 decode_info->reverse_bgr = 0; 290 decode_info->invert_grayscale = 0; 291 decode_info->tiled = 0; 292 293 ret = pTIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); 294 if (!ret) 295 { 296 WARN("missing PhotometricInterpretation tag\n"); 297 return E_FAIL; 298 } 299 300 ret = pTIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps); 301 if (!ret) bps = 1; 302 decode_info->bps = bps; 303 304 ret = pTIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples); 305 if (!ret) samples = 1; 306 decode_info->samples = samples; 307 308 if (samples == 1) 309 planar = 1; 310 else 311 { 312 ret = pTIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar); 313 if (!ret) planar = 1; 314 if (planar != 1) 315 { 316 FIXME("unhandled planar configuration %u\n", planar); 317 return E_FAIL; 318 } 319 } 320 decode_info->planar = planar; 321 322 TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar, photometric, samples, bps); 323 324 switch(photometric) 325 { 326 case 0: /* WhiteIsZero */ 327 decode_info->invert_grayscale = 1; 328 /* fall through */ 329 case 1: /* BlackIsZero */ 330 if (samples == 2) 331 { 332 ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples); 333 if (!ret) 334 { 335 extra_sample_count = 1; 336 extra_sample = 0; 337 extra_samples = &extra_sample; 338 } 339 } 340 else if (samples != 1) 341 { 342 FIXME("unhandled %dbpp sample count %u\n", bps, samples); 343 return E_FAIL; 344 } 345 346 decode_info->bpp = bps * samples; 347 decode_info->source_bpp = decode_info->bpp; 348 switch (bps) 349 { 350 case 1: 351 if (samples != 1) 352 { 353 FIXME("unhandled 1bpp sample count %u\n", samples); 354 return E_FAIL; 355 } 356 decode_info->format = &GUID_WICPixelFormatBlackWhite; 357 break; 358 case 4: 359 if (samples != 1) 360 { 361 FIXME("unhandled 4bpp grayscale sample count %u\n", samples); 362 return E_FAIL; 363 } 364 decode_info->format = &GUID_WICPixelFormat4bppGray; 365 break; 366 case 8: 367 if (samples == 1) 368 decode_info->format = &GUID_WICPixelFormat8bppGray; 369 else 370 { 371 decode_info->bpp = 32; 372 373 switch(extra_samples[0]) 374 { 375 case 1: /* Associated (pre-multiplied) alpha data */ 376 decode_info->format = &GUID_WICPixelFormat32bppPBGRA; 377 break; 378 case 0: /* Unspecified data */ 379 case 2: /* Unassociated alpha data */ 380 decode_info->format = &GUID_WICPixelFormat32bppBGRA; 381 break; 382 default: 383 FIXME("unhandled extra sample type %u\n", extra_samples[0]); 384 return E_FAIL; 385 } 386 } 387 break; 388 case 16: 389 if (samples != 1) 390 { 391 FIXME("unhandled 16bpp grayscale sample count %u\n", samples); 392 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 393 } 394 decode_info->format = &GUID_WICPixelFormat16bppGray; 395 break; 396 case 32: 397 if (samples != 1) 398 { 399 FIXME("unhandled 32bpp grayscale sample count %u\n", samples); 400 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 401 } 402 decode_info->format = &GUID_WICPixelFormat32bppGrayFloat; 403 break; 404 default: 405 WARN("unhandled greyscale bit count %u\n", bps); 406 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 407 } 408 break; 409 case 2: /* RGB */ 410 if (samples == 4) 411 { 412 ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples); 413 if (!ret) 414 { 415 extra_sample_count = 1; 416 extra_sample = 0; 417 extra_samples = &extra_sample; 418 } 419 } 420 else if (samples != 3) 421 { 422 FIXME("unhandled RGB sample count %u\n", samples); 423 return E_FAIL; 424 } 425 426 decode_info->bpp = max(bps, 8) * samples; 427 decode_info->source_bpp = bps * samples; 428 switch(bps) 429 { 430 case 1: 431 case 4: 432 case 8: 433 decode_info->reverse_bgr = 1; 434 if (samples == 3) 435 decode_info->format = &GUID_WICPixelFormat24bppBGR; 436 else 437 switch(extra_samples[0]) 438 { 439 case 1: /* Associated (pre-multiplied) alpha data */ 440 decode_info->format = &GUID_WICPixelFormat32bppPBGRA; 441 break; 442 case 0: /* Unspecified data */ 443 case 2: /* Unassociated alpha data */ 444 decode_info->format = &GUID_WICPixelFormat32bppBGRA; 445 break; 446 default: 447 FIXME("unhandled extra sample type %i\n", extra_samples[0]); 448 return E_FAIL; 449 } 450 break; 451 case 16: 452 if (samples == 3) 453 decode_info->format = &GUID_WICPixelFormat48bppRGB; 454 else 455 switch(extra_samples[0]) 456 { 457 case 1: /* Associated (pre-multiplied) alpha data */ 458 decode_info->format = &GUID_WICPixelFormat64bppPRGBA; 459 break; 460 case 0: /* Unspecified data */ 461 case 2: /* Unassociated alpha data */ 462 decode_info->format = &GUID_WICPixelFormat64bppRGBA; 463 break; 464 default: 465 FIXME("unhandled extra sample type %i\n", extra_samples[0]); 466 return E_FAIL; 467 } 468 break; 469 case 32: 470 if (samples != 4) 471 { 472 FIXME("unhandled 32bpp RGB sample count %u\n", samples); 473 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 474 } 475 decode_info->format = &GUID_WICPixelFormat128bppRGBAFloat; 476 break; 477 default: 478 WARN("unhandled RGB bit count %u\n", bps); 479 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 480 } 481 break; 482 case 3: /* RGB Palette */ 483 if (samples != 1) 484 { 485 FIXME("unhandled indexed sample count %u\n", samples); 486 return E_FAIL; 487 } 488 489 decode_info->indexed = 1; 490 decode_info->bpp = bps; 491 switch (bps) 492 { 493 case 1: 494 decode_info->format = &GUID_WICPixelFormat1bppIndexed; 495 break; 496 case 2: 497 decode_info->format = &GUID_WICPixelFormat2bppIndexed; 498 break; 499 case 4: 500 decode_info->format = &GUID_WICPixelFormat4bppIndexed; 501 break; 502 case 8: 503 decode_info->format = &GUID_WICPixelFormat8bppIndexed; 504 break; 505 default: 506 FIXME("unhandled indexed bit count %u\n", bps); 507 return E_FAIL; 508 } 509 break; 510 511 case 5: /* Separated */ 512 if (samples != 4) 513 { 514 FIXME("unhandled Separated sample count %u\n", samples); 515 return E_FAIL; 516 } 517 518 decode_info->bpp = bps * samples; 519 switch(bps) 520 { 521 case 8: 522 decode_info->format = &GUID_WICPixelFormat32bppCMYK; 523 break; 524 case 16: 525 decode_info->format = &GUID_WICPixelFormat64bppCMYK; 526 break; 527 528 default: 529 WARN("unhandled Separated bit count %u\n", bps); 530 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 531 } 532 break; 533 534 case 4: /* Transparency mask */ 535 case 6: /* YCbCr */ 536 case 8: /* CIELab */ 537 default: 538 FIXME("unhandled PhotometricInterpretation %u\n", photometric); 539 return E_FAIL; 540 } 541 542 ret = pTIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->width); 543 if (!ret) 544 { 545 WARN("missing image width\n"); 546 return E_FAIL; 547 } 548 549 ret = pTIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->height); 550 if (!ret) 551 { 552 WARN("missing image length\n"); 553 return E_FAIL; 554 } 555 556 if ((ret = pTIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width))) 557 { 558 decode_info->tiled = 1; 559 560 ret = pTIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height); 561 if (!ret) 562 { 563 WARN("missing tile height\n"); 564 return E_FAIL; 565 } 566 567 decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8); 568 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride; 569 decode_info->tiles_across = (decode_info->width + decode_info->tile_width - 1) / decode_info->tile_width; 570 } 571 else if ((ret = pTIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height))) 572 { 573 if (decode_info->tile_height > decode_info->height) 574 decode_info->tile_height = decode_info->height; 575 decode_info->tile_width = decode_info->width; 576 decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8); 577 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride; 578 } 579 else 580 { 581 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */ 582 decode_info->tile_height = decode_info->height; 583 decode_info->tile_width = decode_info->width; 584 decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8); 585 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride; 586 } 587 588 decode_info->resolution_unit = 0; 589 pTIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &decode_info->resolution_unit); 590 591 ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &decode_info->xres); 592 if (!ret) 593 { 594 WARN("missing X resolution\n"); 595 } 596 /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131) 597 * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */ 598 if (!isfinite(decode_info->xres)) 599 { 600 decode_info->xres = 0.0; 601 } 602 603 ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &decode_info->yres); 604 if (!ret) 605 { 606 WARN("missing Y resolution\n"); 607 } 608 if (!isfinite(decode_info->yres)) 609 { 610 decode_info->yres = 0.0; 611 } 612 613 return S_OK; 614 } 615 616 static HRESULT WINAPI TiffDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 617 void **ppv) 618 { 619 TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); 620 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 621 622 if (!ppv) return E_INVALIDARG; 623 624 if (IsEqualIID(&IID_IUnknown, iid) || 625 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 626 { 627 *ppv = &This->IWICBitmapDecoder_iface; 628 } 629 else 630 { 631 *ppv = NULL; 632 return E_NOINTERFACE; 633 } 634 635 IUnknown_AddRef((IUnknown*)*ppv); 636 return S_OK; 637 } 638 639 static ULONG WINAPI TiffDecoder_AddRef(IWICBitmapDecoder *iface) 640 { 641 TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); 642 ULONG ref = InterlockedIncrement(&This->ref); 643 644 TRACE("(%p) refcount=%u\n", iface, ref); 645 646 return ref; 647 } 648 649 static ULONG WINAPI TiffDecoder_Release(IWICBitmapDecoder *iface) 650 { 651 TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); 652 ULONG ref = InterlockedDecrement(&This->ref); 653 654 TRACE("(%p) refcount=%u\n", iface, ref); 655 656 if (ref == 0) 657 { 658 if (This->tiff) pTIFFClose(This->tiff); 659 if (This->stream) IStream_Release(This->stream); 660 This->lock.DebugInfo->Spare[0] = 0; 661 DeleteCriticalSection(&This->lock); 662 HeapFree(GetProcessHeap(), 0, This); 663 } 664 665 return ref; 666 } 667 668 static HRESULT WINAPI TiffDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 669 DWORD *capability) 670 { 671 HRESULT hr; 672 673 TRACE("(%p,%p,%p)\n", iface, stream, capability); 674 675 if (!stream || !capability) return E_INVALIDARG; 676 677 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 678 if (hr != S_OK) return hr; 679 680 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | 681 WICBitmapDecoderCapabilityCanDecodeSomeImages | 682 WICBitmapDecoderCapabilityCanEnumerateMetadata; 683 return S_OK; 684 } 685 686 static HRESULT WINAPI TiffDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 687 WICDecodeOptions cacheOptions) 688 { 689 TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); 690 TIFF *tiff; 691 tiff_decode_info decode_info; 692 HRESULT hr=S_OK; 693 694 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 695 696 EnterCriticalSection(&This->lock); 697 698 if (This->initialized) 699 { 700 hr = WINCODEC_ERR_WRONGSTATE; 701 goto exit; 702 } 703 704 tiff = tiff_open_stream(pIStream, "r"); 705 if (!tiff) 706 { 707 hr = E_FAIL; 708 goto exit; 709 } 710 711 /* make sure that TIFF format is supported */ 712 hr = tiff_get_decode_info(tiff, &decode_info); 713 if (hr != S_OK) 714 { 715 pTIFFClose(tiff); 716 goto exit; 717 } 718 719 This->tiff = tiff; 720 This->stream = pIStream; 721 IStream_AddRef(pIStream); 722 This->initialized = TRUE; 723 724 exit: 725 LeaveCriticalSection(&This->lock); 726 return hr; 727 } 728 729 static HRESULT WINAPI TiffDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 730 GUID *pguidContainerFormat) 731 { 732 if (!pguidContainerFormat) return E_INVALIDARG; 733 734 memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)); 735 return S_OK; 736 } 737 738 static HRESULT WINAPI TiffDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 739 IWICBitmapDecoderInfo **ppIDecoderInfo) 740 { 741 HRESULT hr; 742 IWICComponentInfo *compinfo; 743 744 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 745 746 hr = CreateComponentInfo(&CLSID_WICTiffDecoder, &compinfo); 747 if (FAILED(hr)) return hr; 748 749 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 750 (void**)ppIDecoderInfo); 751 752 IWICComponentInfo_Release(compinfo); 753 754 return hr; 755 } 756 757 static HRESULT WINAPI TiffDecoder_CopyPalette(IWICBitmapDecoder *iface, 758 IWICPalette *palette) 759 { 760 TRACE("(%p,%p)\n", iface, palette); 761 return WINCODEC_ERR_PALETTEUNAVAILABLE; 762 } 763 764 static HRESULT WINAPI TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 765 IWICMetadataQueryReader **ppIMetadataQueryReader) 766 { 767 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 768 769 if (!ppIMetadataQueryReader) return E_INVALIDARG; 770 771 *ppIMetadataQueryReader = NULL; 772 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 773 } 774 775 static HRESULT WINAPI TiffDecoder_GetPreview(IWICBitmapDecoder *iface, 776 IWICBitmapSource **ppIBitmapSource) 777 { 778 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 779 780 if (!ppIBitmapSource) return E_INVALIDARG; 781 782 *ppIBitmapSource = NULL; 783 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 784 } 785 786 static HRESULT WINAPI TiffDecoder_GetColorContexts(IWICBitmapDecoder *iface, 787 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 788 { 789 FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 790 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 791 } 792 793 static HRESULT WINAPI TiffDecoder_GetThumbnail(IWICBitmapDecoder *iface, 794 IWICBitmapSource **ppIThumbnail) 795 { 796 TRACE("(%p,%p)\n", iface, ppIThumbnail); 797 798 if (!ppIThumbnail) return E_INVALIDARG; 799 800 *ppIThumbnail = NULL; 801 return WINCODEC_ERR_CODECNOTHUMBNAIL; 802 } 803 804 static HRESULT WINAPI TiffDecoder_GetFrameCount(IWICBitmapDecoder *iface, 805 UINT *pCount) 806 { 807 TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); 808 809 if (!pCount) return E_INVALIDARG; 810 811 EnterCriticalSection(&This->lock); 812 *pCount = This->tiff ? pTIFFNumberOfDirectories(This->tiff) : 0; 813 LeaveCriticalSection(&This->lock); 814 815 TRACE("(%p) <-- %i\n", iface, *pCount); 816 817 return S_OK; 818 } 819 820 static HRESULT WINAPI TiffDecoder_GetFrame(IWICBitmapDecoder *iface, 821 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 822 { 823 TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); 824 TiffFrameDecode *result; 825 int res; 826 tiff_decode_info decode_info; 827 HRESULT hr; 828 829 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 830 831 if (!This->tiff) 832 return WINCODEC_ERR_FRAMEMISSING; 833 834 EnterCriticalSection(&This->lock); 835 res = pTIFFSetDirectory(This->tiff, index); 836 if (!res) hr = E_INVALIDARG; 837 else hr = tiff_get_decode_info(This->tiff, &decode_info); 838 LeaveCriticalSection(&This->lock); 839 840 if (SUCCEEDED(hr)) 841 { 842 result = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode)); 843 844 if (result) 845 { 846 result->IWICBitmapFrameDecode_iface.lpVtbl = &TiffFrameDecode_Vtbl; 847 result->IWICMetadataBlockReader_iface.lpVtbl = &TiffFrameDecode_BlockVtbl; 848 result->ref = 1; 849 result->parent = This; 850 result->index = index; 851 result->decode_info = decode_info; 852 result->cached_tile_x = -1; 853 result->cached_tile = HeapAlloc(GetProcessHeap(), 0, decode_info.tile_size); 854 855 if (result->cached_tile) 856 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; 857 else 858 { 859 hr = E_OUTOFMEMORY; 860 HeapFree(GetProcessHeap(), 0, result); 861 } 862 } 863 else hr = E_OUTOFMEMORY; 864 } 865 866 if (FAILED(hr)) *ppIBitmapFrame = NULL; 867 868 return hr; 869 } 870 871 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl = { 872 TiffDecoder_QueryInterface, 873 TiffDecoder_AddRef, 874 TiffDecoder_Release, 875 TiffDecoder_QueryCapability, 876 TiffDecoder_Initialize, 877 TiffDecoder_GetContainerFormat, 878 TiffDecoder_GetDecoderInfo, 879 TiffDecoder_CopyPalette, 880 TiffDecoder_GetMetadataQueryReader, 881 TiffDecoder_GetPreview, 882 TiffDecoder_GetColorContexts, 883 TiffDecoder_GetThumbnail, 884 TiffDecoder_GetFrameCount, 885 TiffDecoder_GetFrame 886 }; 887 888 static HRESULT WINAPI TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 889 void **ppv) 890 { 891 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 892 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 893 894 if (!ppv) return E_INVALIDARG; 895 896 if (IsEqualIID(&IID_IUnknown, iid) || 897 IsEqualIID(&IID_IWICBitmapSource, iid) || 898 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 899 { 900 *ppv = &This->IWICBitmapFrameDecode_iface; 901 } 902 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) 903 { 904 *ppv = &This->IWICMetadataBlockReader_iface; 905 } 906 else 907 { 908 *ppv = NULL; 909 return E_NOINTERFACE; 910 } 911 912 IUnknown_AddRef((IUnknown*)*ppv); 913 return S_OK; 914 } 915 916 static ULONG WINAPI TiffFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 917 { 918 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 919 ULONG ref = InterlockedIncrement(&This->ref); 920 921 TRACE("(%p) refcount=%u\n", iface, ref); 922 923 return ref; 924 } 925 926 static ULONG WINAPI TiffFrameDecode_Release(IWICBitmapFrameDecode *iface) 927 { 928 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 929 ULONG ref = InterlockedDecrement(&This->ref); 930 931 TRACE("(%p) refcount=%u\n", iface, ref); 932 933 if (ref == 0) 934 { 935 HeapFree(GetProcessHeap(), 0, This->cached_tile); 936 HeapFree(GetProcessHeap(), 0, This); 937 } 938 939 return ref; 940 } 941 942 static HRESULT WINAPI TiffFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 943 UINT *puiWidth, UINT *puiHeight) 944 { 945 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 946 947 *puiWidth = This->decode_info.width; 948 *puiHeight = This->decode_info.height; 949 950 TRACE("(%p) <-- %ux%u\n", iface, *puiWidth, *puiHeight); 951 952 return S_OK; 953 } 954 955 static HRESULT WINAPI TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 956 WICPixelFormatGUID *pPixelFormat) 957 { 958 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 959 960 memcpy(pPixelFormat, This->decode_info.format, sizeof(GUID)); 961 962 TRACE("(%p) <-- %s\n", This, debugstr_guid(This->decode_info.format)); 963 964 return S_OK; 965 } 966 967 static HRESULT WINAPI TiffFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 968 double *pDpiX, double *pDpiY) 969 { 970 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 971 972 if (This->decode_info.xres == 0 || This->decode_info.yres == 0) 973 { 974 *pDpiX = *pDpiY = 96.0; 975 } 976 else 977 { 978 switch (This->decode_info.resolution_unit) 979 { 980 default: 981 FIXME("unknown resolution unit %i\n", This->decode_info.resolution_unit); 982 /* fall through */ 983 case 0: /* Not set */ 984 case 1: /* Relative measurements */ 985 case 2: /* Inch */ 986 *pDpiX = This->decode_info.xres; 987 *pDpiY = This->decode_info.yres; 988 break; 989 case 3: /* Centimeter */ 990 *pDpiX = This->decode_info.xres * 2.54; 991 *pDpiY = This->decode_info.yres * 2.54; 992 break; 993 } 994 } 995 996 TRACE("(%p) <-- %f,%f unit=%i\n", iface, *pDpiX, *pDpiY, This->decode_info.resolution_unit); 997 998 return S_OK; 999 } 1000 1001 static HRESULT WINAPI TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 1002 IWICPalette *pIPalette) 1003 { 1004 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1005 uint16 *red, *green, *blue; 1006 WICColor colors[256]; 1007 int color_count, ret, i; 1008 1009 TRACE("(%p,%p)\n", iface, pIPalette); 1010 1011 color_count = 1<<This->decode_info.bps; 1012 1013 EnterCriticalSection(&This->parent->lock); 1014 ret = pTIFFGetField(This->parent->tiff, TIFFTAG_COLORMAP, &red, &green, &blue); 1015 LeaveCriticalSection(&This->parent->lock); 1016 1017 if (!ret) 1018 { 1019 WARN("Couldn't read color map\n"); 1020 return WINCODEC_ERR_PALETTEUNAVAILABLE; 1021 } 1022 1023 for (i=0; i<color_count; i++) 1024 { 1025 colors[i] = 0xff000000 | 1026 ((red[i]<<8) & 0xff0000) | 1027 (green[i] & 0xff00) | 1028 ((blue[i]>>8) & 0xff); 1029 } 1030 1031 return IWICPalette_InitializeCustom(pIPalette, colors, color_count); 1032 } 1033 1034 static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT tile_y) 1035 { 1036 tsize_t ret; 1037 int swap_bytes; 1038 1039 swap_bytes = pTIFFIsByteSwapped(This->parent->tiff); 1040 1041 ret = pTIFFSetDirectory(This->parent->tiff, This->index); 1042 if (ret == -1) 1043 return E_FAIL; 1044 1045 if (This->decode_info.tiled) 1046 ret = pTIFFReadEncodedTile(This->parent->tiff, tile_x + tile_y * This->decode_info.tiles_across, This->cached_tile, This->decode_info.tile_size); 1047 else 1048 ret = pTIFFReadEncodedStrip(This->parent->tiff, tile_y, This->cached_tile, This->decode_info.tile_size); 1049 1050 if (ret == -1) 1051 return E_FAIL; 1052 1053 /* 3bpp RGB */ 1054 if (This->decode_info.source_bpp == 3 && This->decode_info.samples == 3 && This->decode_info.bpp == 24) 1055 { 1056 BYTE *srcdata, *src, *dst; 1057 DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 3 + 7) / 8; 1058 1059 count = width_bytes * This->decode_info.tile_height; 1060 1061 srcdata = HeapAlloc(GetProcessHeap(), 0, count); 1062 if (!srcdata) return E_OUTOFMEMORY; 1063 memcpy(srcdata, This->cached_tile, count); 1064 1065 for (y = 0; y < This->decode_info.tile_height; y++) 1066 { 1067 src = srcdata + y * width_bytes; 1068 dst = This->cached_tile + y * This->decode_info.tile_width * 3; 1069 1070 for (x = 0; x < This->decode_info.tile_width; x += 8) 1071 { 1072 dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */ 1073 dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */ 1074 dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */ 1075 if (x + 1 < This->decode_info.tile_width) 1076 { 1077 dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */ 1078 dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */ 1079 dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */ 1080 } 1081 if (x + 2 < This->decode_info.tile_width) 1082 { 1083 dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */ 1084 dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */ 1085 dst[6] = (src[1] & 0x80) ? 0xff : 0; /* B */ 1086 } 1087 if (x + 3 < This->decode_info.tile_width) 1088 { 1089 dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */ 1090 dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */ 1091 dst[9] = (src[1] & 0x10) ? 0xff : 0; /* B */ 1092 } 1093 if (x + 4 < This->decode_info.tile_width) 1094 { 1095 dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */ 1096 dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */ 1097 dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */ 1098 } 1099 if (x + 5 < This->decode_info.tile_width) 1100 { 1101 dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */ 1102 dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */ 1103 dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */ 1104 } 1105 if (x + 6 < This->decode_info.tile_width) 1106 { 1107 dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */ 1108 dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */ 1109 dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */ 1110 } 1111 if (x + 7 < This->decode_info.tile_width) 1112 { 1113 dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */ 1114 dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */ 1115 dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */ 1116 } 1117 src += 3; 1118 dst += 24; 1119 } 1120 } 1121 1122 HeapFree(GetProcessHeap(), 0, srcdata); 1123 } 1124 /* 12bpp RGB */ 1125 else if (This->decode_info.source_bpp == 12 && This->decode_info.samples == 3 && This->decode_info.bpp == 24) 1126 { 1127 BYTE *srcdata, *src, *dst; 1128 DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 12 + 7) / 8; 1129 1130 count = width_bytes * This->decode_info.tile_height; 1131 1132 srcdata = HeapAlloc(GetProcessHeap(), 0, count); 1133 if (!srcdata) return E_OUTOFMEMORY; 1134 memcpy(srcdata, This->cached_tile, count); 1135 1136 for (y = 0; y < This->decode_info.tile_height; y++) 1137 { 1138 src = srcdata + y * width_bytes; 1139 dst = This->cached_tile + y * This->decode_info.tile_width * 3; 1140 1141 for (x = 0; x < This->decode_info.tile_width; x += 2) 1142 { 1143 dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */ 1144 dst[1] = (src[0] & 0x0f) * 17; /* G */ 1145 dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */ 1146 if (x + 1 < This->decode_info.tile_width) 1147 { 1148 dst[5] = (src[1] & 0x0f) * 17; /* B */ 1149 dst[4] = ((src[2] & 0xf0) >> 4) * 17; /* G */ 1150 dst[3] = (src[2] & 0x0f) * 17; /* R */ 1151 } 1152 src += 3; 1153 dst += 6; 1154 } 1155 } 1156 1157 HeapFree(GetProcessHeap(), 0, srcdata); 1158 } 1159 /* 4bpp RGBA */ 1160 else if (This->decode_info.source_bpp == 4 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) 1161 { 1162 BYTE *src, *dst; 1163 DWORD count; 1164 1165 /* 1 source byte expands to 2 BGRA samples */ 1166 count = (This->decode_info.tile_width * This->decode_info.tile_height + 1) / 2; 1167 1168 src = This->cached_tile + count - 1; 1169 dst = This->cached_tile + This->decode_info.tile_size; 1170 1171 while (count--) 1172 { 1173 BYTE b = *src--; 1174 1175 dst -= 8; 1176 dst[2] = (b & 0x80) ? 0xff : 0; /* R */ 1177 dst[1] = (b & 0x40) ? 0xff : 0; /* G */ 1178 dst[0] = (b & 0x20) ? 0xff : 0; /* B */ 1179 dst[3] = (b & 0x10) ? 0xff : 0; /* A */ 1180 dst[6] = (b & 0x08) ? 0xff : 0; /* R */ 1181 dst[5] = (b & 0x04) ? 0xff : 0; /* G */ 1182 dst[4] = (b & 0x02) ? 0xff : 0; /* B */ 1183 dst[7] = (b & 0x01) ? 0xff : 0; /* A */ 1184 } 1185 } 1186 /* 16bpp RGBA */ 1187 else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) 1188 { 1189 BYTE *src, *dst; 1190 DWORD count = This->decode_info.tile_width * This->decode_info.tile_height; 1191 1192 src = This->cached_tile + count * 2; 1193 dst = This->cached_tile + This->decode_info.tile_size; 1194 1195 while (count--) 1196 { 1197 BYTE b[2]; 1198 1199 src -= 2; 1200 dst -= 4; 1201 1202 b[0] = src[0]; 1203 b[1] = src[1]; 1204 1205 dst[0] = ((b[1] & 0xf0) >> 4) * 17; /* B */ 1206 dst[1] = (b[0] & 0x0f) * 17; /* G */ 1207 dst[2] = ((b[0] & 0xf0) >> 4) * 17; /* R */ 1208 dst[3] = (b[1] & 0x0f) * 17; /* A */ 1209 } 1210 } 1211 /* 8bpp grayscale with extra alpha */ 1212 else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32) 1213 { 1214 BYTE *src; 1215 DWORD *dst, count = This->decode_info.tile_width * This->decode_info.tile_height; 1216 1217 src = This->cached_tile + This->decode_info.tile_width * This->decode_info.tile_height * 2 - 2; 1218 dst = (DWORD *)(This->cached_tile + This->decode_info.tile_size - 4); 1219 1220 while (count--) 1221 { 1222 *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24); 1223 src -= 2; 1224 } 1225 } 1226 1227 if (This->decode_info.reverse_bgr) 1228 { 1229 if (This->decode_info.bps == 8) 1230 { 1231 UINT sample_count = This->decode_info.samples; 1232 1233 reverse_bgr8(sample_count, This->cached_tile, This->decode_info.tile_width, 1234 This->decode_info.tile_height, This->decode_info.tile_width * sample_count); 1235 } 1236 } 1237 1238 if (swap_bytes && This->decode_info.bps > 8) 1239 { 1240 UINT row, i, samples_per_row; 1241 BYTE *sample, temp; 1242 1243 samples_per_row = This->decode_info.tile_width * This->decode_info.samples; 1244 1245 switch(This->decode_info.bps) 1246 { 1247 case 16: 1248 for (row=0; row<This->decode_info.tile_height; row++) 1249 { 1250 sample = This->cached_tile + row * This->decode_info.tile_stride; 1251 for (i=0; i<samples_per_row; i++) 1252 { 1253 temp = sample[1]; 1254 sample[1] = sample[0]; 1255 sample[0] = temp; 1256 sample += 2; 1257 } 1258 } 1259 break; 1260 default: 1261 ERR("unhandled bps for byte swap %u\n", This->decode_info.bps); 1262 return E_FAIL; 1263 } 1264 } 1265 1266 if (This->decode_info.invert_grayscale) 1267 { 1268 BYTE *byte, *end; 1269 1270 if (This->decode_info.samples != 1) 1271 { 1272 ERR("cannot invert grayscale image with %u samples\n", This->decode_info.samples); 1273 return E_FAIL; 1274 } 1275 1276 end = This->cached_tile+This->decode_info.tile_size; 1277 1278 for (byte = This->cached_tile; byte != end; byte++) 1279 *byte = ~(*byte); 1280 } 1281 1282 This->cached_tile_x = tile_x; 1283 This->cached_tile_y = tile_y; 1284 1285 return S_OK; 1286 } 1287 1288 static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 1289 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 1290 { 1291 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1292 UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y; 1293 UINT tile_x, tile_y; 1294 WICRect rc; 1295 HRESULT hr=S_OK; 1296 BYTE *dst_tilepos; 1297 UINT bytesperrow; 1298 WICRect rect; 1299 1300 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 1301 1302 if (!prc) 1303 { 1304 rect.X = 0; 1305 rect.Y = 0; 1306 rect.Width = This->decode_info.width; 1307 rect.Height = This->decode_info.height; 1308 prc = ▭ 1309 } 1310 else 1311 { 1312 if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->decode_info.width || 1313 prc->Y+prc->Height > This->decode_info.height) 1314 return E_INVALIDARG; 1315 } 1316 1317 bytesperrow = ((This->decode_info.bpp * prc->Width)+7)/8; 1318 1319 if (cbStride < bytesperrow) 1320 return E_INVALIDARG; 1321 1322 if ((cbStride * (prc->Height-1)) + ((prc->Width * This->decode_info.bpp) + 7)/8 > cbBufferSize) 1323 return E_INVALIDARG; 1324 1325 min_tile_x = prc->X / This->decode_info.tile_width; 1326 min_tile_y = prc->Y / This->decode_info.tile_height; 1327 max_tile_x = (prc->X+prc->Width-1) / This->decode_info.tile_width; 1328 max_tile_y = (prc->Y+prc->Height-1) / This->decode_info.tile_height; 1329 1330 EnterCriticalSection(&This->parent->lock); 1331 1332 for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++) 1333 { 1334 for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++) 1335 { 1336 if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y) 1337 { 1338 hr = TiffFrameDecode_ReadTile(This, tile_x, tile_y); 1339 } 1340 1341 if (SUCCEEDED(hr)) 1342 { 1343 if (prc->X < tile_x * This->decode_info.tile_width) 1344 rc.X = 0; 1345 else 1346 rc.X = prc->X - tile_x * This->decode_info.tile_width; 1347 1348 if (prc->Y < tile_y * This->decode_info.tile_height) 1349 rc.Y = 0; 1350 else 1351 rc.Y = prc->Y - tile_y * This->decode_info.tile_height; 1352 1353 if (prc->X+prc->Width > (tile_x+1) * This->decode_info.tile_width) 1354 rc.Width = This->decode_info.tile_width - rc.X; 1355 else if (prc->X < tile_x * This->decode_info.tile_width) 1356 rc.Width = prc->Width + prc->X - tile_x * This->decode_info.tile_width; 1357 else 1358 rc.Width = prc->Width; 1359 1360 if (prc->Y+prc->Height > (tile_y+1) * This->decode_info.tile_height) 1361 rc.Height = This->decode_info.tile_height - rc.Y; 1362 else if (prc->Y < tile_y * This->decode_info.tile_height) 1363 rc.Height = prc->Height + prc->Y - tile_y * This->decode_info.tile_height; 1364 else 1365 rc.Height = prc->Height; 1366 1367 dst_tilepos = pbBuffer + (cbStride * ((rc.Y + tile_y * This->decode_info.tile_height) - prc->Y)) + 1368 ((This->decode_info.bpp * ((rc.X + tile_x * This->decode_info.tile_width) - prc->X) + 7) / 8); 1369 1370 hr = copy_pixels(This->decode_info.bpp, This->cached_tile, 1371 This->decode_info.tile_width, This->decode_info.tile_height, This->decode_info.tile_stride, 1372 &rc, cbStride, cbBufferSize, dst_tilepos); 1373 } 1374 1375 if (FAILED(hr)) 1376 { 1377 LeaveCriticalSection(&This->parent->lock); 1378 TRACE("<-- 0x%x\n", hr); 1379 return hr; 1380 } 1381 } 1382 } 1383 1384 LeaveCriticalSection(&This->parent->lock); 1385 1386 return S_OK; 1387 } 1388 1389 static HRESULT WINAPI TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 1390 IWICMetadataQueryReader **ppIMetadataQueryReader) 1391 { 1392 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1393 1394 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1395 1396 if (!ppIMetadataQueryReader) 1397 return E_INVALIDARG; 1398 1399 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 1400 } 1401 1402 static HRESULT WINAPI TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 1403 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1404 { 1405 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1406 const BYTE *profile; 1407 UINT len; 1408 HRESULT hr; 1409 1410 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1411 1412 EnterCriticalSection(&This->parent->lock); 1413 1414 if (pTIFFGetField(This->parent->tiff, TIFFTAG_ICCPROFILE, &len, &profile)) 1415 { 1416 if (cCount && ppIColorContexts) 1417 { 1418 hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, len); 1419 if (FAILED(hr)) 1420 { 1421 LeaveCriticalSection(&This->parent->lock); 1422 return hr; 1423 } 1424 } 1425 *pcActualCount = 1; 1426 } 1427 else 1428 *pcActualCount = 0; 1429 1430 LeaveCriticalSection(&This->parent->lock); 1431 1432 return S_OK; 1433 } 1434 1435 static HRESULT WINAPI TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 1436 IWICBitmapSource **ppIThumbnail) 1437 { 1438 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1439 1440 if (!ppIThumbnail) return E_INVALIDARG; 1441 1442 *ppIThumbnail = NULL; 1443 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1444 } 1445 1446 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl = { 1447 TiffFrameDecode_QueryInterface, 1448 TiffFrameDecode_AddRef, 1449 TiffFrameDecode_Release, 1450 TiffFrameDecode_GetSize, 1451 TiffFrameDecode_GetPixelFormat, 1452 TiffFrameDecode_GetResolution, 1453 TiffFrameDecode_CopyPalette, 1454 TiffFrameDecode_CopyPixels, 1455 TiffFrameDecode_GetMetadataQueryReader, 1456 TiffFrameDecode_GetColorContexts, 1457 TiffFrameDecode_GetThumbnail 1458 }; 1459 1460 static HRESULT WINAPI TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface, 1461 REFIID iid, void **ppv) 1462 { 1463 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1464 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); 1465 } 1466 1467 static ULONG WINAPI TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface) 1468 { 1469 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1470 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); 1471 } 1472 1473 static ULONG WINAPI TiffFrameDecode_Block_Release(IWICMetadataBlockReader *iface) 1474 { 1475 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1476 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); 1477 } 1478 1479 static HRESULT WINAPI TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 1480 GUID *guid) 1481 { 1482 TRACE("(%p,%p)\n", iface, guid); 1483 1484 if (!guid) return E_INVALIDARG; 1485 1486 *guid = GUID_ContainerFormatTiff; 1487 return S_OK; 1488 } 1489 1490 static HRESULT WINAPI TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface, 1491 UINT *count) 1492 { 1493 TRACE("%p,%p\n", iface, count); 1494 1495 if (!count) return E_INVALIDARG; 1496 1497 *count = 1; 1498 return S_OK; 1499 } 1500 1501 static HRESULT create_metadata_reader(TiffFrameDecode *This, IWICMetadataReader **reader) 1502 { 1503 HRESULT hr; 1504 LARGE_INTEGER dir_offset; 1505 IWICMetadataReader *metadata_reader; 1506 IWICPersistStream *persist; 1507 1508 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ 1509 1510 hr = IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); 1511 if (FAILED(hr)) return hr; 1512 1513 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); 1514 if (FAILED(hr)) 1515 { 1516 IWICMetadataReader_Release(metadata_reader); 1517 return hr; 1518 } 1519 1520 EnterCriticalSection(&This->parent->lock); 1521 1522 dir_offset.QuadPart = pTIFFCurrentDirOffset(This->parent->tiff); 1523 hr = IStream_Seek(This->parent->stream, dir_offset, STREAM_SEEK_SET, NULL); 1524 if (SUCCEEDED(hr)) 1525 { 1526 BOOL byte_swapped = pTIFFIsByteSwapped(This->parent->tiff); 1527 #ifdef WORDS_BIGENDIAN 1528 DWORD persist_options = byte_swapped ? WICPersistOptionLittleEndian : WICPersistOptionBigEndian; 1529 #else 1530 DWORD persist_options = byte_swapped ? WICPersistOptionBigEndian : WICPersistOptionLittleEndian; 1531 #endif 1532 persist_options |= WICPersistOptionNoCacheStream; 1533 hr = IWICPersistStream_LoadEx(persist, This->parent->stream, NULL, persist_options); 1534 if (FAILED(hr)) 1535 ERR("IWICPersistStream_LoadEx error %#x\n", hr); 1536 } 1537 1538 LeaveCriticalSection(&This->parent->lock); 1539 1540 IWICPersistStream_Release(persist); 1541 1542 if (FAILED(hr)) 1543 { 1544 IWICMetadataReader_Release(metadata_reader); 1545 return hr; 1546 } 1547 1548 *reader = metadata_reader; 1549 return S_OK; 1550 } 1551 1552 static HRESULT WINAPI TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 1553 UINT index, IWICMetadataReader **reader) 1554 { 1555 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1556 1557 TRACE("(%p,%u,%p)\n", iface, index, reader); 1558 1559 if (!reader || index != 0) return E_INVALIDARG; 1560 1561 return create_metadata_reader(This, reader); 1562 } 1563 1564 static HRESULT WINAPI TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1565 IEnumUnknown **enum_metadata) 1566 { 1567 FIXME("(%p,%p): stub\n", iface, enum_metadata); 1568 return E_NOTIMPL; 1569 } 1570 1571 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl = 1572 { 1573 TiffFrameDecode_Block_QueryInterface, 1574 TiffFrameDecode_Block_AddRef, 1575 TiffFrameDecode_Block_Release, 1576 TiffFrameDecode_Block_GetContainerFormat, 1577 TiffFrameDecode_Block_GetCount, 1578 TiffFrameDecode_Block_GetReaderByIndex, 1579 TiffFrameDecode_Block_GetEnumerator 1580 }; 1581 1582 HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv) 1583 { 1584 HRESULT ret; 1585 TiffDecoder *This; 1586 1587 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1588 1589 *ppv = NULL; 1590 1591 if (!load_libtiff()) 1592 { 1593 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF); 1594 return E_FAIL; 1595 } 1596 1597 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder)); 1598 if (!This) return E_OUTOFMEMORY; 1599 1600 This->IWICBitmapDecoder_iface.lpVtbl = &TiffDecoder_Vtbl; 1601 This->ref = 1; 1602 This->stream = NULL; 1603 InitializeCriticalSection(&This->lock); 1604 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffDecoder.lock"); 1605 This->tiff = NULL; 1606 This->initialized = FALSE; 1607 1608 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1609 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1610 1611 return ret; 1612 } 1613 1614 struct tiff_encode_format { 1615 const WICPixelFormatGUID *guid; 1616 int photometric; 1617 int bps; 1618 int samples; 1619 int bpp; 1620 int extra_sample; 1621 int extra_sample_type; 1622 int reverse_bgr; 1623 }; 1624 1625 static const struct tiff_encode_format formats[] = { 1626 {&GUID_WICPixelFormat24bppBGR, 2, 8, 3, 24, 0, 0, 1}, 1627 {&GUID_WICPixelFormat24bppRGB, 2, 8, 3, 24, 0, 0, 0}, 1628 {&GUID_WICPixelFormatBlackWhite, 1, 1, 1, 1, 0, 0, 0}, 1629 {&GUID_WICPixelFormat4bppGray, 1, 4, 1, 4, 0, 0, 0}, 1630 {&GUID_WICPixelFormat8bppGray, 1, 8, 1, 8, 0, 0, 0}, 1631 {&GUID_WICPixelFormat32bppBGRA, 2, 8, 4, 32, 1, 2, 1}, 1632 {&GUID_WICPixelFormat32bppPBGRA, 2, 8, 4, 32, 1, 1, 1}, 1633 {&GUID_WICPixelFormat48bppRGB, 2, 16, 3, 48, 0, 0, 0}, 1634 {&GUID_WICPixelFormat64bppRGBA, 2, 16, 4, 64, 1, 2, 0}, 1635 {&GUID_WICPixelFormat64bppPRGBA, 2, 16, 4, 64, 1, 1, 0}, 1636 {&GUID_WICPixelFormat1bppIndexed, 3, 1, 1, 1, 0, 0, 0}, 1637 {&GUID_WICPixelFormat2bppIndexed, 3, 2, 1, 2, 0, 0, 0}, 1638 {&GUID_WICPixelFormat4bppIndexed, 3, 4, 1, 4, 0, 0, 0}, 1639 {&GUID_WICPixelFormat8bppIndexed, 3, 8, 1, 8, 0, 0, 0}, 1640 {0} 1641 }; 1642 1643 typedef struct TiffEncoder { 1644 IWICBitmapEncoder IWICBitmapEncoder_iface; 1645 LONG ref; 1646 IStream *stream; 1647 CRITICAL_SECTION lock; /* Must be held when tiff is used or fields below are set */ 1648 TIFF *tiff; 1649 BOOL initialized; 1650 BOOL committed; 1651 ULONG num_frames; 1652 ULONG num_frames_committed; 1653 } TiffEncoder; 1654 1655 static inline TiffEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 1656 { 1657 return CONTAINING_RECORD(iface, TiffEncoder, IWICBitmapEncoder_iface); 1658 } 1659 1660 typedef struct TiffFrameEncode { 1661 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 1662 LONG ref; 1663 TiffEncoder *parent; 1664 /* fields below are protected by parent->lock */ 1665 BOOL initialized; 1666 BOOL info_written; 1667 BOOL committed; 1668 const struct tiff_encode_format *format; 1669 UINT width, height; 1670 double xres, yres; 1671 UINT lines_written; 1672 WICColor palette[256]; 1673 UINT colors; 1674 } TiffFrameEncode; 1675 1676 static inline TiffFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 1677 { 1678 return CONTAINING_RECORD(iface, TiffFrameEncode, IWICBitmapFrameEncode_iface); 1679 } 1680 1681 static HRESULT WINAPI TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, 1682 void **ppv) 1683 { 1684 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1685 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1686 1687 if (!ppv) return E_INVALIDARG; 1688 1689 if (IsEqualIID(&IID_IUnknown, iid) || 1690 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 1691 { 1692 *ppv = &This->IWICBitmapFrameEncode_iface; 1693 } 1694 else 1695 { 1696 *ppv = NULL; 1697 return E_NOINTERFACE; 1698 } 1699 1700 IUnknown_AddRef((IUnknown*)*ppv); 1701 return S_OK; 1702 } 1703 1704 static ULONG WINAPI TiffFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 1705 { 1706 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1707 ULONG ref = InterlockedIncrement(&This->ref); 1708 1709 TRACE("(%p) refcount=%u\n", iface, ref); 1710 1711 return ref; 1712 } 1713 1714 static ULONG WINAPI TiffFrameEncode_Release(IWICBitmapFrameEncode *iface) 1715 { 1716 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1717 ULONG ref = InterlockedDecrement(&This->ref); 1718 1719 TRACE("(%p) refcount=%u\n", iface, ref); 1720 1721 if (ref == 0) 1722 { 1723 IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface); 1724 HeapFree(GetProcessHeap(), 0, This); 1725 } 1726 1727 return ref; 1728 } 1729 1730 static HRESULT WINAPI TiffFrameEncode_Initialize(IWICBitmapFrameEncode *iface, 1731 IPropertyBag2 *pIEncoderOptions) 1732 { 1733 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1734 TRACE("(%p,%p)\n", iface, pIEncoderOptions); 1735 1736 EnterCriticalSection(&This->parent->lock); 1737 1738 if (This->initialized) 1739 { 1740 LeaveCriticalSection(&This->parent->lock); 1741 return WINCODEC_ERR_WRONGSTATE; 1742 } 1743 1744 This->initialized = TRUE; 1745 1746 LeaveCriticalSection(&This->parent->lock); 1747 1748 return S_OK; 1749 } 1750 1751 static HRESULT WINAPI TiffFrameEncode_SetSize(IWICBitmapFrameEncode *iface, 1752 UINT uiWidth, UINT uiHeight) 1753 { 1754 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1755 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); 1756 1757 EnterCriticalSection(&This->parent->lock); 1758 1759 if (!This->initialized || This->info_written) 1760 { 1761 LeaveCriticalSection(&This->parent->lock); 1762 return WINCODEC_ERR_WRONGSTATE; 1763 } 1764 1765 This->width = uiWidth; 1766 This->height = uiHeight; 1767 1768 LeaveCriticalSection(&This->parent->lock); 1769 1770 return S_OK; 1771 } 1772 1773 static HRESULT WINAPI TiffFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, 1774 double dpiX, double dpiY) 1775 { 1776 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1777 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); 1778 1779 EnterCriticalSection(&This->parent->lock); 1780 1781 if (!This->initialized || This->info_written) 1782 { 1783 LeaveCriticalSection(&This->parent->lock); 1784 return WINCODEC_ERR_WRONGSTATE; 1785 } 1786 1787 This->xres = dpiX; 1788 This->yres = dpiY; 1789 1790 LeaveCriticalSection(&This->parent->lock); 1791 1792 return S_OK; 1793 } 1794 1795 static HRESULT WINAPI TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, 1796 WICPixelFormatGUID *pPixelFormat) 1797 { 1798 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1799 int i; 1800 1801 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); 1802 1803 EnterCriticalSection(&This->parent->lock); 1804 1805 if (!This->initialized || This->info_written) 1806 { 1807 LeaveCriticalSection(&This->parent->lock); 1808 return WINCODEC_ERR_WRONGSTATE; 1809 } 1810 1811 for (i=0; formats[i].guid; i++) 1812 { 1813 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0) 1814 break; 1815 } 1816 1817 if (!formats[i].guid) i = 0; 1818 1819 This->format = &formats[i]; 1820 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 1821 1822 LeaveCriticalSection(&This->parent->lock); 1823 1824 return S_OK; 1825 } 1826 1827 static HRESULT WINAPI TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, 1828 UINT cCount, IWICColorContext **ppIColorContext) 1829 { 1830 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 1831 return E_NOTIMPL; 1832 } 1833 1834 static HRESULT WINAPI TiffFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, 1835 IWICPalette *palette) 1836 { 1837 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1838 HRESULT hr; 1839 1840 TRACE("(%p,%p)\n", iface, palette); 1841 1842 if (!palette) return E_INVALIDARG; 1843 1844 EnterCriticalSection(&This->parent->lock); 1845 1846 if (This->initialized) 1847 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 1848 else 1849 hr = WINCODEC_ERR_NOTINITIALIZED; 1850 1851 LeaveCriticalSection(&This->parent->lock); 1852 return hr; 1853 } 1854 1855 static HRESULT WINAPI TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, 1856 IWICBitmapSource *pIThumbnail) 1857 { 1858 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 1859 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1860 } 1861 1862 static HRESULT WINAPI TiffFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, 1863 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 1864 { 1865 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1866 BYTE *row_data, *swapped_data = NULL; 1867 UINT i, j, line_size; 1868 1869 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 1870 1871 EnterCriticalSection(&This->parent->lock); 1872 1873 if (!This->initialized || !This->width || !This->height || !This->format) 1874 { 1875 LeaveCriticalSection(&This->parent->lock); 1876 return WINCODEC_ERR_WRONGSTATE; 1877 } 1878 1879 if (lineCount == 0 || lineCount + This->lines_written > This->height) 1880 { 1881 LeaveCriticalSection(&This->parent->lock); 1882 return E_INVALIDARG; 1883 } 1884 1885 line_size = ((This->width * This->format->bpp)+7)/8; 1886 1887 if (This->format->reverse_bgr) 1888 { 1889 swapped_data = HeapAlloc(GetProcessHeap(), 0, line_size); 1890 if (!swapped_data) 1891 { 1892 LeaveCriticalSection(&This->parent->lock); 1893 return E_OUTOFMEMORY; 1894 } 1895 } 1896 1897 if (!This->info_written) 1898 { 1899 pTIFFSetField(This->parent->tiff, TIFFTAG_PHOTOMETRIC, (uint16)This->format->photometric); 1900 pTIFFSetField(This->parent->tiff, TIFFTAG_PLANARCONFIG, (uint16)1); 1901 pTIFFSetField(This->parent->tiff, TIFFTAG_BITSPERSAMPLE, (uint16)This->format->bps); 1902 pTIFFSetField(This->parent->tiff, TIFFTAG_SAMPLESPERPIXEL, (uint16)This->format->samples); 1903 1904 if (This->format->extra_sample) 1905 { 1906 uint16 extra_samples; 1907 extra_samples = This->format->extra_sample_type; 1908 1909 pTIFFSetField(This->parent->tiff, TIFFTAG_EXTRASAMPLES, (uint16)1, &extra_samples); 1910 } 1911 1912 pTIFFSetField(This->parent->tiff, TIFFTAG_IMAGEWIDTH, (uint32)This->width); 1913 pTIFFSetField(This->parent->tiff, TIFFTAG_IMAGELENGTH, (uint32)This->height); 1914 1915 if (This->xres != 0.0 && This->yres != 0.0) 1916 { 1917 pTIFFSetField(This->parent->tiff, TIFFTAG_RESOLUTIONUNIT, (uint16)2); /* Inch */ 1918 pTIFFSetField(This->parent->tiff, TIFFTAG_XRESOLUTION, (float)This->xres); 1919 pTIFFSetField(This->parent->tiff, TIFFTAG_YRESOLUTION, (float)This->yres); 1920 } 1921 1922 if (This->format->bpp <= 8 && This->colors && !IsEqualGUID(This->format->guid, &GUID_WICPixelFormatBlackWhite)) 1923 { 1924 uint16 red[256], green[256], blue[256]; 1925 UINT i; 1926 1927 for (i = 0; i < This->colors; i++) 1928 { 1929 red[i] = (This->palette[i] >> 8) & 0xff00; 1930 green[i] = This->palette[i] & 0xff00; 1931 blue[i] = (This->palette[i] << 8) & 0xff00; 1932 } 1933 1934 pTIFFSetField(This->parent->tiff, TIFFTAG_COLORMAP, red, green, blue); 1935 } 1936 1937 This->info_written = TRUE; 1938 } 1939 1940 for (i=0; i<lineCount; i++) 1941 { 1942 row_data = pbPixels + i * cbStride; 1943 1944 if (This->format->reverse_bgr && This->format->bps == 8) 1945 { 1946 memcpy(swapped_data, row_data, line_size); 1947 for (j=0; j<line_size; j += This->format->samples) 1948 { 1949 BYTE temp; 1950 temp = swapped_data[j]; 1951 swapped_data[j] = swapped_data[j+2]; 1952 swapped_data[j+2] = temp; 1953 } 1954 row_data = swapped_data; 1955 } 1956 1957 pTIFFWriteScanline(This->parent->tiff, (tdata_t)row_data, i+This->lines_written, 0); 1958 } 1959 1960 This->lines_written += lineCount; 1961 1962 LeaveCriticalSection(&This->parent->lock); 1963 1964 HeapFree(GetProcessHeap(), 0, swapped_data); 1965 1966 return S_OK; 1967 } 1968 1969 static HRESULT WINAPI TiffFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, 1970 IWICBitmapSource *pIBitmapSource, WICRect *prc) 1971 { 1972 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1973 HRESULT hr; 1974 1975 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc); 1976 1977 if (!This->initialized) 1978 return WINCODEC_ERR_WRONGSTATE; 1979 1980 hr = configure_write_source(iface, pIBitmapSource, prc, 1981 This->format ? This->format->guid : NULL, This->width, This->height, 1982 This->xres, This->yres); 1983 1984 if (SUCCEEDED(hr)) 1985 { 1986 hr = write_source(iface, pIBitmapSource, prc, 1987 This->format->guid, This->format->bpp, This->width, This->height); 1988 } 1989 1990 return hr; 1991 } 1992 1993 static HRESULT WINAPI TiffFrameEncode_Commit(IWICBitmapFrameEncode *iface) 1994 { 1995 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1996 1997 TRACE("(%p)\n", iface); 1998 1999 EnterCriticalSection(&This->parent->lock); 2000 2001 if (!This->info_written || This->lines_written != This->height || This->committed) 2002 { 2003 LeaveCriticalSection(&This->parent->lock); 2004 return WINCODEC_ERR_WRONGSTATE; 2005 } 2006 2007 /* libtiff will commit the data when creating a new frame or closing the file */ 2008 2009 This->committed = TRUE; 2010 This->parent->num_frames_committed++; 2011 2012 LeaveCriticalSection(&This->parent->lock); 2013 2014 return S_OK; 2015 } 2016 2017 static HRESULT WINAPI TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, 2018 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 2019 { 2020 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); 2021 return E_NOTIMPL; 2022 } 2023 2024 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl = { 2025 TiffFrameEncode_QueryInterface, 2026 TiffFrameEncode_AddRef, 2027 TiffFrameEncode_Release, 2028 TiffFrameEncode_Initialize, 2029 TiffFrameEncode_SetSize, 2030 TiffFrameEncode_SetResolution, 2031 TiffFrameEncode_SetPixelFormat, 2032 TiffFrameEncode_SetColorContexts, 2033 TiffFrameEncode_SetPalette, 2034 TiffFrameEncode_SetThumbnail, 2035 TiffFrameEncode_WritePixels, 2036 TiffFrameEncode_WriteSource, 2037 TiffFrameEncode_Commit, 2038 TiffFrameEncode_GetMetadataQueryWriter 2039 }; 2040 2041 static HRESULT WINAPI TiffEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, 2042 void **ppv) 2043 { 2044 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2045 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 2046 2047 if (!ppv) return E_INVALIDARG; 2048 2049 if (IsEqualIID(&IID_IUnknown, iid) || 2050 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 2051 { 2052 *ppv = &This->IWICBitmapEncoder_iface; 2053 } 2054 else 2055 { 2056 *ppv = NULL; 2057 return E_NOINTERFACE; 2058 } 2059 2060 IUnknown_AddRef((IUnknown*)*ppv); 2061 return S_OK; 2062 } 2063 2064 static ULONG WINAPI TiffEncoder_AddRef(IWICBitmapEncoder *iface) 2065 { 2066 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2067 ULONG ref = InterlockedIncrement(&This->ref); 2068 2069 TRACE("(%p) refcount=%u\n", iface, ref); 2070 2071 return ref; 2072 } 2073 2074 static ULONG WINAPI TiffEncoder_Release(IWICBitmapEncoder *iface) 2075 { 2076 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2077 ULONG ref = InterlockedDecrement(&This->ref); 2078 2079 TRACE("(%p) refcount=%u\n", iface, ref); 2080 2081 if (ref == 0) 2082 { 2083 if (This->tiff) pTIFFClose(This->tiff); 2084 if (This->stream) IStream_Release(This->stream); 2085 This->lock.DebugInfo->Spare[0] = 0; 2086 DeleteCriticalSection(&This->lock); 2087 HeapFree(GetProcessHeap(), 0, This); 2088 } 2089 2090 return ref; 2091 } 2092 2093 static HRESULT WINAPI TiffEncoder_Initialize(IWICBitmapEncoder *iface, 2094 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption) 2095 { 2096 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2097 TIFF *tiff; 2098 HRESULT hr=S_OK; 2099 2100 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption); 2101 2102 EnterCriticalSection(&This->lock); 2103 2104 if (This->initialized || This->committed) 2105 { 2106 hr = WINCODEC_ERR_WRONGSTATE; 2107 goto exit; 2108 } 2109 2110 tiff = tiff_open_stream(pIStream, "w"); 2111 2112 if (!tiff) 2113 { 2114 hr = E_FAIL; 2115 goto exit; 2116 } 2117 2118 This->tiff = tiff; 2119 This->stream = pIStream; 2120 IStream_AddRef(pIStream); 2121 This->initialized = TRUE; 2122 2123 exit: 2124 LeaveCriticalSection(&This->lock); 2125 return hr; 2126 } 2127 2128 static HRESULT WINAPI TiffEncoder_GetContainerFormat(IWICBitmapEncoder *iface, 2129 GUID *pguidContainerFormat) 2130 { 2131 memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)); 2132 return S_OK; 2133 } 2134 2135 static HRESULT WINAPI TiffEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 2136 { 2137 IWICComponentInfo *comp_info; 2138 HRESULT hr; 2139 2140 TRACE("%p,%p\n", iface, info); 2141 2142 if (!info) return E_INVALIDARG; 2143 2144 hr = CreateComponentInfo(&CLSID_WICTiffEncoder, &comp_info); 2145 if (hr == S_OK) 2146 { 2147 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 2148 IWICComponentInfo_Release(comp_info); 2149 } 2150 return hr; 2151 } 2152 2153 static HRESULT WINAPI TiffEncoder_SetColorContexts(IWICBitmapEncoder *iface, 2154 UINT cCount, IWICColorContext **ppIColorContext) 2155 { 2156 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 2157 return E_NOTIMPL; 2158 } 2159 2160 static HRESULT WINAPI TiffEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) 2161 { 2162 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2163 HRESULT hr; 2164 2165 TRACE("(%p,%p)\n", iface, palette); 2166 2167 EnterCriticalSection(&This->lock); 2168 2169 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED; 2170 2171 LeaveCriticalSection(&This->lock); 2172 2173 return hr; 2174 } 2175 2176 static HRESULT WINAPI TiffEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) 2177 { 2178 TRACE("(%p,%p)\n", iface, pIThumbnail); 2179 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2180 } 2181 2182 static HRESULT WINAPI TiffEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) 2183 { 2184 TRACE("(%p,%p)\n", iface, pIPreview); 2185 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2186 } 2187 2188 static HRESULT WINAPI TiffEncoder_CreateNewFrame(IWICBitmapEncoder *iface, 2189 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions) 2190 { 2191 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2192 TiffFrameEncode *result; 2193 static const PROPBAG2 opts[2] = 2194 { 2195 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszTiffCompressionMethod }, 2196 { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszCompressionQuality }, 2197 }; 2198 HRESULT hr=S_OK; 2199 2200 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); 2201 2202 EnterCriticalSection(&This->lock); 2203 2204 if (!This->initialized || This->committed) 2205 { 2206 hr = WINCODEC_ERR_WRONGSTATE; 2207 } 2208 else if (This->num_frames != This->num_frames_committed) 2209 { 2210 FIXME("New frame created before previous frame was committed\n"); 2211 hr = E_FAIL; 2212 } 2213 2214 if (ppIEncoderOptions && SUCCEEDED(hr)) 2215 { 2216 hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); 2217 if (SUCCEEDED(hr)) 2218 { 2219 VARIANT v; 2220 VariantInit(&v); 2221 V_VT(&v) = VT_UI1; 2222 V_UI1(&v) = WICTiffCompressionDontCare; 2223 hr = IPropertyBag2_Write(*ppIEncoderOptions, 1, (PROPBAG2 *)opts, &v); 2224 VariantClear(&v); 2225 if (FAILED(hr)) 2226 { 2227 IPropertyBag2_Release(*ppIEncoderOptions); 2228 *ppIEncoderOptions = NULL; 2229 } 2230 } 2231 } 2232 2233 if (SUCCEEDED(hr)) 2234 { 2235 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result)); 2236 2237 if (result) 2238 { 2239 result->IWICBitmapFrameEncode_iface.lpVtbl = &TiffFrameEncode_Vtbl; 2240 result->ref = 1; 2241 result->parent = This; 2242 result->initialized = FALSE; 2243 result->info_written = FALSE; 2244 result->committed = FALSE; 2245 result->format = NULL; 2246 result->width = 0; 2247 result->height = 0; 2248 result->xres = 0.0; 2249 result->yres = 0.0; 2250 result->lines_written = 0; 2251 result->colors = 0; 2252 2253 IWICBitmapEncoder_AddRef(iface); 2254 *ppIFrameEncode = &result->IWICBitmapFrameEncode_iface; 2255 2256 if (This->num_frames != 0) 2257 pTIFFWriteDirectory(This->tiff); 2258 2259 This->num_frames++; 2260 } 2261 else 2262 hr = E_OUTOFMEMORY; 2263 2264 if (FAILED(hr)) 2265 { 2266 IPropertyBag2_Release(*ppIEncoderOptions); 2267 *ppIEncoderOptions = NULL; 2268 } 2269 } 2270 2271 LeaveCriticalSection(&This->lock); 2272 2273 return hr; 2274 } 2275 2276 static HRESULT WINAPI TiffEncoder_Commit(IWICBitmapEncoder *iface) 2277 { 2278 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2279 2280 TRACE("(%p)\n", iface); 2281 2282 EnterCriticalSection(&This->lock); 2283 2284 if (!This->initialized || This->committed) 2285 { 2286 LeaveCriticalSection(&This->lock); 2287 return WINCODEC_ERR_WRONGSTATE; 2288 } 2289 2290 pTIFFClose(This->tiff); 2291 IStream_Release(This->stream); 2292 This->stream = NULL; 2293 This->tiff = NULL; 2294 2295 This->committed = TRUE; 2296 2297 LeaveCriticalSection(&This->lock); 2298 2299 return S_OK; 2300 } 2301 2302 static HRESULT WINAPI TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, 2303 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 2304 { 2305 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); 2306 return E_NOTIMPL; 2307 } 2308 2309 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl = { 2310 TiffEncoder_QueryInterface, 2311 TiffEncoder_AddRef, 2312 TiffEncoder_Release, 2313 TiffEncoder_Initialize, 2314 TiffEncoder_GetContainerFormat, 2315 TiffEncoder_GetEncoderInfo, 2316 TiffEncoder_SetColorContexts, 2317 TiffEncoder_SetPalette, 2318 TiffEncoder_SetThumbnail, 2319 TiffEncoder_SetPreview, 2320 TiffEncoder_CreateNewFrame, 2321 TiffEncoder_Commit, 2322 TiffEncoder_GetMetadataQueryWriter 2323 }; 2324 2325 HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv) 2326 { 2327 TiffEncoder *This; 2328 HRESULT ret; 2329 2330 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 2331 2332 *ppv = NULL; 2333 2334 if (!load_libtiff()) 2335 { 2336 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF); 2337 return E_FAIL; 2338 } 2339 2340 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder)); 2341 if (!This) return E_OUTOFMEMORY; 2342 2343 This->IWICBitmapEncoder_iface.lpVtbl = &TiffEncoder_Vtbl; 2344 This->ref = 1; 2345 This->stream = NULL; 2346 InitializeCriticalSection(&This->lock); 2347 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffEncoder.lock"); 2348 This->tiff = NULL; 2349 This->initialized = FALSE; 2350 This->num_frames = 0; 2351 This->num_frames_committed = 0; 2352 This->committed = FALSE; 2353 2354 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 2355 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 2356 2357 return ret; 2358 } 2359 2360 #else /* !SONAME_LIBTIFF */ 2361 2362 HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv) 2363 { 2364 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n"); 2365 return E_FAIL; 2366 } 2367 2368 HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv) 2369 { 2370 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n"); 2371 return E_FAIL; 2372 } 2373 2374 #endif 2375