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