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 /* 4bpp RGBA */ 1152 else if (This->decode_info.source_bpp == 4 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) 1153 { 1154 BYTE *src, *dst; 1155 DWORD count; 1156 1157 /* 1 source byte expands to 2 BGRA samples */ 1158 count = (This->decode_info.tile_width * This->decode_info.tile_height + 1) / 2; 1159 1160 src = This->cached_tile + count - 1; 1161 dst = This->cached_tile + This->decode_info.tile_size; 1162 1163 while (count--) 1164 { 1165 BYTE b = *src--; 1166 1167 dst -= 8; 1168 dst[2] = (b & 0x80) ? 0xff : 0; /* R */ 1169 dst[1] = (b & 0x40) ? 0xff : 0; /* G */ 1170 dst[0] = (b & 0x20) ? 0xff : 0; /* B */ 1171 dst[3] = (b & 0x10) ? 0xff : 0; /* A */ 1172 dst[6] = (b & 0x08) ? 0xff : 0; /* R */ 1173 dst[5] = (b & 0x04) ? 0xff : 0; /* G */ 1174 dst[4] = (b & 0x02) ? 0xff : 0; /* B */ 1175 dst[7] = (b & 0x01) ? 0xff : 0; /* A */ 1176 } 1177 } 1178 /* 16bpp RGBA */ 1179 else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) 1180 { 1181 BYTE *src, *dst; 1182 DWORD count = This->decode_info.tile_width * This->decode_info.tile_height; 1183 1184 src = This->cached_tile + count * 2; 1185 dst = This->cached_tile + This->decode_info.tile_size; 1186 1187 while (count--) 1188 { 1189 BYTE b[2]; 1190 1191 src -= 2; 1192 dst -= 4; 1193 1194 b[0] = src[0]; 1195 b[1] = src[1]; 1196 1197 dst[0] = ((b[1] & 0xf0) >> 4) * 17; /* B */ 1198 dst[1] = (b[0] & 0x0f) * 17; /* G */ 1199 dst[2] = ((b[0] & 0xf0) >> 4) * 17; /* R */ 1200 dst[3] = (b[1] & 0x0f) * 17; /* A */ 1201 } 1202 } 1203 /* 8bpp grayscale with extra alpha */ 1204 else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32) 1205 { 1206 BYTE *src; 1207 DWORD *dst, count = This->decode_info.tile_width * This->decode_info.tile_height; 1208 1209 src = This->cached_tile + This->decode_info.tile_width * This->decode_info.tile_height * 2 - 2; 1210 dst = (DWORD *)(This->cached_tile + This->decode_info.tile_size - 4); 1211 1212 while (count--) 1213 { 1214 *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24); 1215 src -= 2; 1216 } 1217 } 1218 1219 if (This->decode_info.reverse_bgr) 1220 { 1221 if (This->decode_info.bps == 8) 1222 { 1223 UINT sample_count = This->decode_info.samples; 1224 1225 reverse_bgr8(sample_count, This->cached_tile, This->decode_info.tile_width, 1226 This->decode_info.tile_height, This->decode_info.tile_width * sample_count); 1227 } 1228 } 1229 1230 if (swap_bytes && This->decode_info.bps > 8) 1231 { 1232 UINT row, i, samples_per_row; 1233 BYTE *sample, temp; 1234 1235 samples_per_row = This->decode_info.tile_width * This->decode_info.samples; 1236 1237 switch(This->decode_info.bps) 1238 { 1239 case 16: 1240 for (row=0; row<This->decode_info.tile_height; row++) 1241 { 1242 sample = This->cached_tile + row * This->decode_info.tile_stride; 1243 for (i=0; i<samples_per_row; i++) 1244 { 1245 temp = sample[1]; 1246 sample[1] = sample[0]; 1247 sample[0] = temp; 1248 sample += 2; 1249 } 1250 } 1251 break; 1252 default: 1253 ERR("unhandled bps for byte swap %u\n", This->decode_info.bps); 1254 return E_FAIL; 1255 } 1256 } 1257 1258 if (This->decode_info.invert_grayscale) 1259 { 1260 BYTE *byte, *end; 1261 1262 if (This->decode_info.samples != 1) 1263 { 1264 ERR("cannot invert grayscale image with %u samples\n", This->decode_info.samples); 1265 return E_FAIL; 1266 } 1267 1268 end = This->cached_tile+This->decode_info.tile_size; 1269 1270 for (byte = This->cached_tile; byte != end; byte++) 1271 *byte = ~(*byte); 1272 } 1273 1274 This->cached_tile_x = tile_x; 1275 This->cached_tile_y = tile_y; 1276 1277 return S_OK; 1278 } 1279 1280 static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 1281 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 1282 { 1283 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1284 UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y; 1285 UINT tile_x, tile_y; 1286 WICRect rc; 1287 HRESULT hr=S_OK; 1288 BYTE *dst_tilepos; 1289 UINT bytesperrow; 1290 WICRect rect; 1291 1292 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); 1293 1294 if (!prc) 1295 { 1296 rect.X = 0; 1297 rect.Y = 0; 1298 rect.Width = This->decode_info.width; 1299 rect.Height = This->decode_info.height; 1300 prc = ▭ 1301 } 1302 else 1303 { 1304 if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->decode_info.width || 1305 prc->Y+prc->Height > This->decode_info.height) 1306 return E_INVALIDARG; 1307 } 1308 1309 bytesperrow = ((This->decode_info.bpp * prc->Width)+7)/8; 1310 1311 if (cbStride < bytesperrow) 1312 return E_INVALIDARG; 1313 1314 if ((cbStride * (prc->Height-1)) + bytesperrow > cbBufferSize) 1315 return E_INVALIDARG; 1316 1317 min_tile_x = prc->X / This->decode_info.tile_width; 1318 min_tile_y = prc->Y / This->decode_info.tile_height; 1319 max_tile_x = (prc->X+prc->Width-1) / This->decode_info.tile_width; 1320 max_tile_y = (prc->Y+prc->Height-1) / This->decode_info.tile_height; 1321 1322 EnterCriticalSection(&This->parent->lock); 1323 1324 for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++) 1325 { 1326 for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++) 1327 { 1328 if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y) 1329 { 1330 hr = TiffFrameDecode_ReadTile(This, tile_x, tile_y); 1331 } 1332 1333 if (SUCCEEDED(hr)) 1334 { 1335 if (prc->X < tile_x * This->decode_info.tile_width) 1336 rc.X = 0; 1337 else 1338 rc.X = prc->X - tile_x * This->decode_info.tile_width; 1339 1340 if (prc->Y < tile_y * This->decode_info.tile_height) 1341 rc.Y = 0; 1342 else 1343 rc.Y = prc->Y - tile_y * This->decode_info.tile_height; 1344 1345 if (prc->X+prc->Width > (tile_x+1) * This->decode_info.tile_width) 1346 rc.Width = This->decode_info.tile_width - rc.X; 1347 else if (prc->X < tile_x * This->decode_info.tile_width) 1348 rc.Width = prc->Width + prc->X - tile_x * This->decode_info.tile_width; 1349 else 1350 rc.Width = prc->Width; 1351 1352 if (prc->Y+prc->Height > (tile_y+1) * This->decode_info.tile_height) 1353 rc.Height = This->decode_info.tile_height - rc.Y; 1354 else if (prc->Y < tile_y * This->decode_info.tile_height) 1355 rc.Height = prc->Height + prc->Y - tile_y * This->decode_info.tile_height; 1356 else 1357 rc.Height = prc->Height; 1358 1359 dst_tilepos = pbBuffer + (cbStride * ((rc.Y + tile_y * This->decode_info.tile_height) - prc->Y)) + 1360 ((This->decode_info.bpp * ((rc.X + tile_x * This->decode_info.tile_width) - prc->X) + 7) / 8); 1361 1362 hr = copy_pixels(This->decode_info.bpp, This->cached_tile, 1363 This->decode_info.tile_width, This->decode_info.tile_height, This->decode_info.tile_stride, 1364 &rc, cbStride, cbBufferSize, dst_tilepos); 1365 } 1366 1367 if (FAILED(hr)) 1368 { 1369 LeaveCriticalSection(&This->parent->lock); 1370 TRACE("<-- 0x%x\n", hr); 1371 return hr; 1372 } 1373 } 1374 } 1375 1376 LeaveCriticalSection(&This->parent->lock); 1377 1378 return S_OK; 1379 } 1380 1381 static HRESULT WINAPI TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 1382 IWICMetadataQueryReader **ppIMetadataQueryReader) 1383 { 1384 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1385 1386 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1387 1388 if (!ppIMetadataQueryReader) 1389 return E_INVALIDARG; 1390 1391 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 1392 } 1393 1394 static HRESULT WINAPI TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 1395 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1396 { 1397 TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 1398 const BYTE *profile; 1399 UINT len; 1400 HRESULT hr; 1401 1402 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1403 1404 EnterCriticalSection(&This->parent->lock); 1405 1406 if (pTIFFGetField(This->parent->tiff, TIFFTAG_ICCPROFILE, &len, &profile)) 1407 { 1408 if (cCount && ppIColorContexts) 1409 { 1410 hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, len); 1411 if (FAILED(hr)) 1412 { 1413 LeaveCriticalSection(&This->parent->lock); 1414 return hr; 1415 } 1416 } 1417 *pcActualCount = 1; 1418 } 1419 else 1420 *pcActualCount = 0; 1421 1422 LeaveCriticalSection(&This->parent->lock); 1423 1424 return S_OK; 1425 } 1426 1427 static HRESULT WINAPI TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 1428 IWICBitmapSource **ppIThumbnail) 1429 { 1430 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1431 1432 if (!ppIThumbnail) return E_INVALIDARG; 1433 1434 *ppIThumbnail = NULL; 1435 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1436 } 1437 1438 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl = { 1439 TiffFrameDecode_QueryInterface, 1440 TiffFrameDecode_AddRef, 1441 TiffFrameDecode_Release, 1442 TiffFrameDecode_GetSize, 1443 TiffFrameDecode_GetPixelFormat, 1444 TiffFrameDecode_GetResolution, 1445 TiffFrameDecode_CopyPalette, 1446 TiffFrameDecode_CopyPixels, 1447 TiffFrameDecode_GetMetadataQueryReader, 1448 TiffFrameDecode_GetColorContexts, 1449 TiffFrameDecode_GetThumbnail 1450 }; 1451 1452 static HRESULT WINAPI TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface, 1453 REFIID iid, void **ppv) 1454 { 1455 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1456 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); 1457 } 1458 1459 static ULONG WINAPI TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface) 1460 { 1461 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1462 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); 1463 } 1464 1465 static ULONG WINAPI TiffFrameDecode_Block_Release(IWICMetadataBlockReader *iface) 1466 { 1467 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1468 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); 1469 } 1470 1471 static HRESULT WINAPI TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 1472 GUID *guid) 1473 { 1474 TRACE("(%p,%p)\n", iface, guid); 1475 1476 if (!guid) return E_INVALIDARG; 1477 1478 *guid = GUID_ContainerFormatTiff; 1479 return S_OK; 1480 } 1481 1482 static HRESULT WINAPI TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface, 1483 UINT *count) 1484 { 1485 TRACE("%p,%p\n", iface, count); 1486 1487 if (!count) return E_INVALIDARG; 1488 1489 *count = 1; 1490 return S_OK; 1491 } 1492 1493 static HRESULT create_metadata_reader(TiffFrameDecode *This, IWICMetadataReader **reader) 1494 { 1495 HRESULT hr; 1496 LARGE_INTEGER dir_offset; 1497 IWICMetadataReader *metadata_reader; 1498 IWICPersistStream *persist; 1499 1500 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ 1501 1502 hr = IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); 1503 if (FAILED(hr)) return hr; 1504 1505 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); 1506 if (FAILED(hr)) 1507 { 1508 IWICMetadataReader_Release(metadata_reader); 1509 return hr; 1510 } 1511 1512 EnterCriticalSection(&This->parent->lock); 1513 1514 dir_offset.QuadPart = pTIFFCurrentDirOffset(This->parent->tiff); 1515 hr = IStream_Seek(This->parent->stream, dir_offset, STREAM_SEEK_SET, NULL); 1516 if (SUCCEEDED(hr)) 1517 { 1518 BOOL byte_swapped = pTIFFIsByteSwapped(This->parent->tiff); 1519 #ifdef WORDS_BIGENDIAN 1520 DWORD persist_options = byte_swapped ? WICPersistOptionLittleEndian : WICPersistOptionBigEndian; 1521 #else 1522 DWORD persist_options = byte_swapped ? WICPersistOptionBigEndian : WICPersistOptionLittleEndian; 1523 #endif 1524 persist_options |= WICPersistOptionNoCacheStream; 1525 hr = IWICPersistStream_LoadEx(persist, This->parent->stream, NULL, persist_options); 1526 if (FAILED(hr)) 1527 ERR("IWICPersistStream_LoadEx error %#x\n", hr); 1528 } 1529 1530 LeaveCriticalSection(&This->parent->lock); 1531 1532 IWICPersistStream_Release(persist); 1533 1534 if (FAILED(hr)) 1535 { 1536 IWICMetadataReader_Release(metadata_reader); 1537 return hr; 1538 } 1539 1540 *reader = metadata_reader; 1541 return S_OK; 1542 } 1543 1544 static HRESULT WINAPI TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 1545 UINT index, IWICMetadataReader **reader) 1546 { 1547 TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface); 1548 1549 TRACE("(%p,%u,%p)\n", iface, index, reader); 1550 1551 if (!reader || index != 0) return E_INVALIDARG; 1552 1553 return create_metadata_reader(This, reader); 1554 } 1555 1556 static HRESULT WINAPI TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1557 IEnumUnknown **enum_metadata) 1558 { 1559 FIXME("(%p,%p): stub\n", iface, enum_metadata); 1560 return E_NOTIMPL; 1561 } 1562 1563 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl = 1564 { 1565 TiffFrameDecode_Block_QueryInterface, 1566 TiffFrameDecode_Block_AddRef, 1567 TiffFrameDecode_Block_Release, 1568 TiffFrameDecode_Block_GetContainerFormat, 1569 TiffFrameDecode_Block_GetCount, 1570 TiffFrameDecode_Block_GetReaderByIndex, 1571 TiffFrameDecode_Block_GetEnumerator 1572 }; 1573 1574 HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv) 1575 { 1576 HRESULT ret; 1577 TiffDecoder *This; 1578 1579 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1580 1581 *ppv = NULL; 1582 1583 if (!load_libtiff()) 1584 { 1585 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF); 1586 return E_FAIL; 1587 } 1588 1589 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder)); 1590 if (!This) return E_OUTOFMEMORY; 1591 1592 This->IWICBitmapDecoder_iface.lpVtbl = &TiffDecoder_Vtbl; 1593 This->ref = 1; 1594 This->stream = NULL; 1595 InitializeCriticalSection(&This->lock); 1596 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffDecoder.lock"); 1597 This->tiff = NULL; 1598 This->initialized = FALSE; 1599 1600 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1601 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1602 1603 return ret; 1604 } 1605 1606 struct tiff_encode_format { 1607 const WICPixelFormatGUID *guid; 1608 int photometric; 1609 int bps; 1610 int samples; 1611 int bpp; 1612 int extra_sample; 1613 int extra_sample_type; 1614 int reverse_bgr; 1615 }; 1616 1617 static const struct tiff_encode_format formats[] = { 1618 {&GUID_WICPixelFormat24bppBGR, 2, 8, 3, 24, 0, 0, 1}, 1619 {&GUID_WICPixelFormat24bppRGB, 2, 8, 3, 24, 0, 0, 0}, 1620 {&GUID_WICPixelFormatBlackWhite, 1, 1, 1, 1, 0, 0, 0}, 1621 {&GUID_WICPixelFormat4bppGray, 1, 4, 1, 4, 0, 0, 0}, 1622 {&GUID_WICPixelFormat8bppGray, 1, 8, 1, 8, 0, 0, 0}, 1623 {&GUID_WICPixelFormat32bppBGRA, 2, 8, 4, 32, 1, 2, 1}, 1624 {&GUID_WICPixelFormat32bppPBGRA, 2, 8, 4, 32, 1, 1, 1}, 1625 {&GUID_WICPixelFormat48bppRGB, 2, 16, 3, 48, 0, 0, 0}, 1626 {&GUID_WICPixelFormat64bppRGBA, 2, 16, 4, 64, 1, 2, 0}, 1627 {&GUID_WICPixelFormat64bppPRGBA, 2, 16, 4, 64, 1, 1, 0}, 1628 {&GUID_WICPixelFormat1bppIndexed, 3, 1, 1, 1, 0, 0, 0}, 1629 {&GUID_WICPixelFormat4bppIndexed, 3, 4, 1, 4, 0, 0, 0}, 1630 {&GUID_WICPixelFormat8bppIndexed, 3, 8, 1, 8, 0, 0, 0}, 1631 {0} 1632 }; 1633 1634 typedef struct TiffEncoder { 1635 IWICBitmapEncoder IWICBitmapEncoder_iface; 1636 LONG ref; 1637 IStream *stream; 1638 CRITICAL_SECTION lock; /* Must be held when tiff is used or fields below are set */ 1639 TIFF *tiff; 1640 BOOL initialized; 1641 BOOL committed; 1642 ULONG num_frames; 1643 ULONG num_frames_committed; 1644 } TiffEncoder; 1645 1646 static inline TiffEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 1647 { 1648 return CONTAINING_RECORD(iface, TiffEncoder, IWICBitmapEncoder_iface); 1649 } 1650 1651 typedef struct TiffFrameEncode { 1652 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 1653 LONG ref; 1654 TiffEncoder *parent; 1655 /* fields below are protected by parent->lock */ 1656 BOOL initialized; 1657 BOOL info_written; 1658 BOOL committed; 1659 const struct tiff_encode_format *format; 1660 UINT width, height; 1661 double xres, yres; 1662 UINT lines_written; 1663 WICColor palette[256]; 1664 UINT colors; 1665 } TiffFrameEncode; 1666 1667 static inline TiffFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 1668 { 1669 return CONTAINING_RECORD(iface, TiffFrameEncode, IWICBitmapFrameEncode_iface); 1670 } 1671 1672 static HRESULT WINAPI TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, 1673 void **ppv) 1674 { 1675 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1676 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1677 1678 if (!ppv) return E_INVALIDARG; 1679 1680 if (IsEqualIID(&IID_IUnknown, iid) || 1681 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 1682 { 1683 *ppv = &This->IWICBitmapFrameEncode_iface; 1684 } 1685 else 1686 { 1687 *ppv = NULL; 1688 return E_NOINTERFACE; 1689 } 1690 1691 IUnknown_AddRef((IUnknown*)*ppv); 1692 return S_OK; 1693 } 1694 1695 static ULONG WINAPI TiffFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 1696 { 1697 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1698 ULONG ref = InterlockedIncrement(&This->ref); 1699 1700 TRACE("(%p) refcount=%u\n", iface, ref); 1701 1702 return ref; 1703 } 1704 1705 static ULONG WINAPI TiffFrameEncode_Release(IWICBitmapFrameEncode *iface) 1706 { 1707 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1708 ULONG ref = InterlockedDecrement(&This->ref); 1709 1710 TRACE("(%p) refcount=%u\n", iface, ref); 1711 1712 if (ref == 0) 1713 { 1714 IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface); 1715 HeapFree(GetProcessHeap(), 0, This); 1716 } 1717 1718 return ref; 1719 } 1720 1721 static HRESULT WINAPI TiffFrameEncode_Initialize(IWICBitmapFrameEncode *iface, 1722 IPropertyBag2 *pIEncoderOptions) 1723 { 1724 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1725 TRACE("(%p,%p)\n", iface, pIEncoderOptions); 1726 1727 EnterCriticalSection(&This->parent->lock); 1728 1729 if (This->initialized) 1730 { 1731 LeaveCriticalSection(&This->parent->lock); 1732 return WINCODEC_ERR_WRONGSTATE; 1733 } 1734 1735 This->initialized = TRUE; 1736 1737 LeaveCriticalSection(&This->parent->lock); 1738 1739 return S_OK; 1740 } 1741 1742 static HRESULT WINAPI TiffFrameEncode_SetSize(IWICBitmapFrameEncode *iface, 1743 UINT uiWidth, UINT uiHeight) 1744 { 1745 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1746 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); 1747 1748 EnterCriticalSection(&This->parent->lock); 1749 1750 if (!This->initialized || This->info_written) 1751 { 1752 LeaveCriticalSection(&This->parent->lock); 1753 return WINCODEC_ERR_WRONGSTATE; 1754 } 1755 1756 This->width = uiWidth; 1757 This->height = uiHeight; 1758 1759 LeaveCriticalSection(&This->parent->lock); 1760 1761 return S_OK; 1762 } 1763 1764 static HRESULT WINAPI TiffFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, 1765 double dpiX, double dpiY) 1766 { 1767 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1768 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); 1769 1770 EnterCriticalSection(&This->parent->lock); 1771 1772 if (!This->initialized || This->info_written) 1773 { 1774 LeaveCriticalSection(&This->parent->lock); 1775 return WINCODEC_ERR_WRONGSTATE; 1776 } 1777 1778 This->xres = dpiX; 1779 This->yres = dpiY; 1780 1781 LeaveCriticalSection(&This->parent->lock); 1782 1783 return S_OK; 1784 } 1785 1786 static HRESULT WINAPI TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, 1787 WICPixelFormatGUID *pPixelFormat) 1788 { 1789 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1790 int i; 1791 1792 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); 1793 1794 EnterCriticalSection(&This->parent->lock); 1795 1796 if (!This->initialized || This->info_written) 1797 { 1798 LeaveCriticalSection(&This->parent->lock); 1799 return WINCODEC_ERR_WRONGSTATE; 1800 } 1801 1802 if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormat2bppIndexed)) 1803 *pPixelFormat = GUID_WICPixelFormat4bppIndexed; 1804 1805 for (i=0; formats[i].guid; i++) 1806 { 1807 if (IsEqualGUID(formats[i].guid, pPixelFormat)) 1808 break; 1809 } 1810 1811 if (!formats[i].guid) i = 0; 1812 1813 This->format = &formats[i]; 1814 memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); 1815 1816 LeaveCriticalSection(&This->parent->lock); 1817 1818 return S_OK; 1819 } 1820 1821 static HRESULT WINAPI TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, 1822 UINT cCount, IWICColorContext **ppIColorContext) 1823 { 1824 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 1825 return E_NOTIMPL; 1826 } 1827 1828 static HRESULT WINAPI TiffFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, 1829 IWICPalette *palette) 1830 { 1831 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1832 HRESULT hr; 1833 1834 TRACE("(%p,%p)\n", iface, palette); 1835 1836 if (!palette) return E_INVALIDARG; 1837 1838 EnterCriticalSection(&This->parent->lock); 1839 1840 if (This->initialized) 1841 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 1842 else 1843 hr = WINCODEC_ERR_NOTINITIALIZED; 1844 1845 LeaveCriticalSection(&This->parent->lock); 1846 return hr; 1847 } 1848 1849 static HRESULT WINAPI TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, 1850 IWICBitmapSource *pIThumbnail) 1851 { 1852 FIXME("(%p,%p): stub\n", iface, pIThumbnail); 1853 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1854 } 1855 1856 static HRESULT WINAPI TiffFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, 1857 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels) 1858 { 1859 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1860 BYTE *row_data, *swapped_data = NULL; 1861 UINT i, j, line_size; 1862 1863 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels); 1864 1865 EnterCriticalSection(&This->parent->lock); 1866 1867 if (!This->initialized || !This->width || !This->height || !This->format) 1868 { 1869 LeaveCriticalSection(&This->parent->lock); 1870 return WINCODEC_ERR_WRONGSTATE; 1871 } 1872 1873 if (lineCount == 0 || lineCount + This->lines_written > This->height) 1874 { 1875 LeaveCriticalSection(&This->parent->lock); 1876 return E_INVALIDARG; 1877 } 1878 1879 line_size = ((This->width * This->format->bpp)+7)/8; 1880 1881 if (This->format->reverse_bgr) 1882 { 1883 swapped_data = HeapAlloc(GetProcessHeap(), 0, line_size); 1884 if (!swapped_data) 1885 { 1886 LeaveCriticalSection(&This->parent->lock); 1887 return E_OUTOFMEMORY; 1888 } 1889 } 1890 1891 if (!This->info_written) 1892 { 1893 pTIFFSetField(This->parent->tiff, TIFFTAG_PHOTOMETRIC, (uint16)This->format->photometric); 1894 pTIFFSetField(This->parent->tiff, TIFFTAG_PLANARCONFIG, (uint16)1); 1895 pTIFFSetField(This->parent->tiff, TIFFTAG_BITSPERSAMPLE, (uint16)This->format->bps); 1896 pTIFFSetField(This->parent->tiff, TIFFTAG_SAMPLESPERPIXEL, (uint16)This->format->samples); 1897 1898 if (This->format->extra_sample) 1899 { 1900 uint16 extra_samples; 1901 extra_samples = This->format->extra_sample_type; 1902 1903 pTIFFSetField(This->parent->tiff, TIFFTAG_EXTRASAMPLES, (uint16)1, &extra_samples); 1904 } 1905 1906 pTIFFSetField(This->parent->tiff, TIFFTAG_IMAGEWIDTH, (uint32)This->width); 1907 pTIFFSetField(This->parent->tiff, TIFFTAG_IMAGELENGTH, (uint32)This->height); 1908 1909 if (This->xres != 0.0 && This->yres != 0.0) 1910 { 1911 pTIFFSetField(This->parent->tiff, TIFFTAG_RESOLUTIONUNIT, (uint16)2); /* Inch */ 1912 pTIFFSetField(This->parent->tiff, TIFFTAG_XRESOLUTION, (float)This->xres); 1913 pTIFFSetField(This->parent->tiff, TIFFTAG_YRESOLUTION, (float)This->yres); 1914 } 1915 1916 if (This->format->bpp <= 8 && This->colors && !IsEqualGUID(This->format->guid, &GUID_WICPixelFormatBlackWhite)) 1917 { 1918 uint16 red[256], green[256], blue[256]; 1919 UINT i; 1920 1921 for (i = 0; i < This->colors; i++) 1922 { 1923 red[i] = (This->palette[i] >> 8) & 0xff00; 1924 green[i] = This->palette[i] & 0xff00; 1925 blue[i] = (This->palette[i] << 8) & 0xff00; 1926 } 1927 1928 pTIFFSetField(This->parent->tiff, TIFFTAG_COLORMAP, red, green, blue); 1929 } 1930 1931 This->info_written = TRUE; 1932 } 1933 1934 for (i=0; i<lineCount; i++) 1935 { 1936 row_data = pbPixels + i * cbStride; 1937 1938 if (This->format->reverse_bgr && This->format->bps == 8) 1939 { 1940 memcpy(swapped_data, row_data, line_size); 1941 for (j=0; j<line_size; j += This->format->samples) 1942 { 1943 BYTE temp; 1944 temp = swapped_data[j]; 1945 swapped_data[j] = swapped_data[j+2]; 1946 swapped_data[j+2] = temp; 1947 } 1948 row_data = swapped_data; 1949 } 1950 1951 pTIFFWriteScanline(This->parent->tiff, (tdata_t)row_data, i+This->lines_written, 0); 1952 } 1953 1954 This->lines_written += lineCount; 1955 1956 LeaveCriticalSection(&This->parent->lock); 1957 1958 HeapFree(GetProcessHeap(), 0, swapped_data); 1959 1960 return S_OK; 1961 } 1962 1963 static HRESULT WINAPI TiffFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, 1964 IWICBitmapSource *pIBitmapSource, WICRect *prc) 1965 { 1966 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1967 HRESULT hr; 1968 1969 TRACE("(%p,%p,%s)\n", iface, pIBitmapSource, debug_wic_rect(prc)); 1970 1971 if (!This->initialized) 1972 return WINCODEC_ERR_WRONGSTATE; 1973 1974 hr = configure_write_source(iface, pIBitmapSource, prc, 1975 This->format ? This->format->guid : NULL, This->width, This->height, 1976 This->xres, This->yres); 1977 1978 if (SUCCEEDED(hr)) 1979 { 1980 hr = write_source(iface, pIBitmapSource, prc, 1981 This->format->guid, This->format->bpp, This->width, This->height); 1982 } 1983 1984 return hr; 1985 } 1986 1987 static HRESULT WINAPI TiffFrameEncode_Commit(IWICBitmapFrameEncode *iface) 1988 { 1989 TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1990 1991 TRACE("(%p)\n", iface); 1992 1993 EnterCriticalSection(&This->parent->lock); 1994 1995 if (!This->info_written || This->lines_written != This->height || This->committed) 1996 { 1997 LeaveCriticalSection(&This->parent->lock); 1998 return WINCODEC_ERR_WRONGSTATE; 1999 } 2000 2001 /* libtiff will commit the data when creating a new frame or closing the file */ 2002 2003 This->committed = TRUE; 2004 This->parent->num_frames_committed++; 2005 2006 LeaveCriticalSection(&This->parent->lock); 2007 2008 return S_OK; 2009 } 2010 2011 static HRESULT WINAPI TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, 2012 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 2013 { 2014 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); 2015 return E_NOTIMPL; 2016 } 2017 2018 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl = { 2019 TiffFrameEncode_QueryInterface, 2020 TiffFrameEncode_AddRef, 2021 TiffFrameEncode_Release, 2022 TiffFrameEncode_Initialize, 2023 TiffFrameEncode_SetSize, 2024 TiffFrameEncode_SetResolution, 2025 TiffFrameEncode_SetPixelFormat, 2026 TiffFrameEncode_SetColorContexts, 2027 TiffFrameEncode_SetPalette, 2028 TiffFrameEncode_SetThumbnail, 2029 TiffFrameEncode_WritePixels, 2030 TiffFrameEncode_WriteSource, 2031 TiffFrameEncode_Commit, 2032 TiffFrameEncode_GetMetadataQueryWriter 2033 }; 2034 2035 static HRESULT WINAPI TiffEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, 2036 void **ppv) 2037 { 2038 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2039 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 2040 2041 if (!ppv) return E_INVALIDARG; 2042 2043 if (IsEqualIID(&IID_IUnknown, iid) || 2044 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 2045 { 2046 *ppv = &This->IWICBitmapEncoder_iface; 2047 } 2048 else 2049 { 2050 *ppv = NULL; 2051 return E_NOINTERFACE; 2052 } 2053 2054 IUnknown_AddRef((IUnknown*)*ppv); 2055 return S_OK; 2056 } 2057 2058 static ULONG WINAPI TiffEncoder_AddRef(IWICBitmapEncoder *iface) 2059 { 2060 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2061 ULONG ref = InterlockedIncrement(&This->ref); 2062 2063 TRACE("(%p) refcount=%u\n", iface, ref); 2064 2065 return ref; 2066 } 2067 2068 static ULONG WINAPI TiffEncoder_Release(IWICBitmapEncoder *iface) 2069 { 2070 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2071 ULONG ref = InterlockedDecrement(&This->ref); 2072 2073 TRACE("(%p) refcount=%u\n", iface, ref); 2074 2075 if (ref == 0) 2076 { 2077 if (This->tiff) pTIFFClose(This->tiff); 2078 if (This->stream) IStream_Release(This->stream); 2079 This->lock.DebugInfo->Spare[0] = 0; 2080 DeleteCriticalSection(&This->lock); 2081 HeapFree(GetProcessHeap(), 0, This); 2082 } 2083 2084 return ref; 2085 } 2086 2087 static HRESULT WINAPI TiffEncoder_Initialize(IWICBitmapEncoder *iface, 2088 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption) 2089 { 2090 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2091 TIFF *tiff; 2092 HRESULT hr=S_OK; 2093 2094 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption); 2095 2096 EnterCriticalSection(&This->lock); 2097 2098 if (This->initialized || This->committed) 2099 { 2100 hr = WINCODEC_ERR_WRONGSTATE; 2101 goto exit; 2102 } 2103 2104 tiff = tiff_open_stream(pIStream, "w"); 2105 2106 if (!tiff) 2107 { 2108 hr = E_FAIL; 2109 goto exit; 2110 } 2111 2112 This->tiff = tiff; 2113 This->stream = pIStream; 2114 IStream_AddRef(pIStream); 2115 This->initialized = TRUE; 2116 2117 exit: 2118 LeaveCriticalSection(&This->lock); 2119 return hr; 2120 } 2121 2122 static HRESULT WINAPI TiffEncoder_GetContainerFormat(IWICBitmapEncoder *iface, 2123 GUID *pguidContainerFormat) 2124 { 2125 TRACE("(%p,%p)\n", iface, pguidContainerFormat); 2126 2127 if (!pguidContainerFormat) 2128 return E_INVALIDARG; 2129 2130 memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID)); 2131 return S_OK; 2132 } 2133 2134 static HRESULT WINAPI TiffEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 2135 { 2136 IWICComponentInfo *comp_info; 2137 HRESULT hr; 2138 2139 TRACE("%p,%p\n", iface, info); 2140 2141 if (!info) return E_INVALIDARG; 2142 2143 hr = CreateComponentInfo(&CLSID_WICTiffEncoder, &comp_info); 2144 if (hr == S_OK) 2145 { 2146 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 2147 IWICComponentInfo_Release(comp_info); 2148 } 2149 return hr; 2150 } 2151 2152 static HRESULT WINAPI TiffEncoder_SetColorContexts(IWICBitmapEncoder *iface, 2153 UINT cCount, IWICColorContext **ppIColorContext) 2154 { 2155 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); 2156 return E_NOTIMPL; 2157 } 2158 2159 static HRESULT WINAPI TiffEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) 2160 { 2161 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2162 HRESULT hr; 2163 2164 TRACE("(%p,%p)\n", iface, palette); 2165 2166 EnterCriticalSection(&This->lock); 2167 2168 hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED; 2169 2170 LeaveCriticalSection(&This->lock); 2171 2172 return hr; 2173 } 2174 2175 static HRESULT WINAPI TiffEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) 2176 { 2177 TRACE("(%p,%p)\n", iface, pIThumbnail); 2178 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2179 } 2180 2181 static HRESULT WINAPI TiffEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) 2182 { 2183 TRACE("(%p,%p)\n", iface, pIPreview); 2184 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2185 } 2186 2187 static HRESULT WINAPI TiffEncoder_CreateNewFrame(IWICBitmapEncoder *iface, 2188 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions) 2189 { 2190 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2191 TiffFrameEncode *result; 2192 static const PROPBAG2 opts[2] = 2193 { 2194 { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszTiffCompressionMethod }, 2195 { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszCompressionQuality }, 2196 }; 2197 HRESULT hr=S_OK; 2198 2199 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); 2200 2201 EnterCriticalSection(&This->lock); 2202 2203 if (!This->initialized || This->committed) 2204 { 2205 hr = WINCODEC_ERR_WRONGSTATE; 2206 } 2207 else if (This->num_frames != This->num_frames_committed) 2208 { 2209 FIXME("New frame created before previous frame was committed\n"); 2210 hr = E_FAIL; 2211 } 2212 2213 if (ppIEncoderOptions && SUCCEEDED(hr)) 2214 { 2215 hr = CreatePropertyBag2(opts, ARRAY_SIZE(opts), ppIEncoderOptions); 2216 if (SUCCEEDED(hr)) 2217 { 2218 VARIANT v; 2219 VariantInit(&v); 2220 V_VT(&v) = VT_UI1; 2221 V_UI1(&v) = WICTiffCompressionDontCare; 2222 hr = IPropertyBag2_Write(*ppIEncoderOptions, 1, (PROPBAG2 *)opts, &v); 2223 VariantClear(&v); 2224 if (FAILED(hr)) 2225 { 2226 IPropertyBag2_Release(*ppIEncoderOptions); 2227 *ppIEncoderOptions = NULL; 2228 } 2229 } 2230 } 2231 2232 if (SUCCEEDED(hr)) 2233 { 2234 result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result)); 2235 2236 if (result) 2237 { 2238 result->IWICBitmapFrameEncode_iface.lpVtbl = &TiffFrameEncode_Vtbl; 2239 result->ref = 1; 2240 result->parent = This; 2241 result->initialized = FALSE; 2242 result->info_written = FALSE; 2243 result->committed = FALSE; 2244 result->format = NULL; 2245 result->width = 0; 2246 result->height = 0; 2247 result->xres = 0.0; 2248 result->yres = 0.0; 2249 result->lines_written = 0; 2250 result->colors = 0; 2251 2252 IWICBitmapEncoder_AddRef(iface); 2253 *ppIFrameEncode = &result->IWICBitmapFrameEncode_iface; 2254 2255 if (This->num_frames != 0) 2256 pTIFFWriteDirectory(This->tiff); 2257 2258 This->num_frames++; 2259 } 2260 else 2261 hr = E_OUTOFMEMORY; 2262 2263 if (FAILED(hr)) 2264 { 2265 IPropertyBag2_Release(*ppIEncoderOptions); 2266 *ppIEncoderOptions = NULL; 2267 } 2268 } 2269 2270 LeaveCriticalSection(&This->lock); 2271 2272 return hr; 2273 } 2274 2275 static HRESULT WINAPI TiffEncoder_Commit(IWICBitmapEncoder *iface) 2276 { 2277 TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); 2278 2279 TRACE("(%p)\n", iface); 2280 2281 EnterCriticalSection(&This->lock); 2282 2283 if (!This->initialized || This->committed) 2284 { 2285 LeaveCriticalSection(&This->lock); 2286 return WINCODEC_ERR_WRONGSTATE; 2287 } 2288 2289 pTIFFClose(This->tiff); 2290 IStream_Release(This->stream); 2291 This->stream = NULL; 2292 This->tiff = NULL; 2293 2294 This->committed = TRUE; 2295 2296 LeaveCriticalSection(&This->lock); 2297 2298 return S_OK; 2299 } 2300 2301 static HRESULT WINAPI TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, 2302 IWICMetadataQueryWriter **ppIMetadataQueryWriter) 2303 { 2304 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); 2305 return E_NOTIMPL; 2306 } 2307 2308 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl = { 2309 TiffEncoder_QueryInterface, 2310 TiffEncoder_AddRef, 2311 TiffEncoder_Release, 2312 TiffEncoder_Initialize, 2313 TiffEncoder_GetContainerFormat, 2314 TiffEncoder_GetEncoderInfo, 2315 TiffEncoder_SetColorContexts, 2316 TiffEncoder_SetPalette, 2317 TiffEncoder_SetThumbnail, 2318 TiffEncoder_SetPreview, 2319 TiffEncoder_CreateNewFrame, 2320 TiffEncoder_Commit, 2321 TiffEncoder_GetMetadataQueryWriter 2322 }; 2323 2324 HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv) 2325 { 2326 TiffEncoder *This; 2327 HRESULT ret; 2328 2329 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 2330 2331 *ppv = NULL; 2332 2333 if (!load_libtiff()) 2334 { 2335 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF); 2336 return E_FAIL; 2337 } 2338 2339 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder)); 2340 if (!This) return E_OUTOFMEMORY; 2341 2342 This->IWICBitmapEncoder_iface.lpVtbl = &TiffEncoder_Vtbl; 2343 This->ref = 1; 2344 This->stream = NULL; 2345 InitializeCriticalSection(&This->lock); 2346 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffEncoder.lock"); 2347 This->tiff = NULL; 2348 This->initialized = FALSE; 2349 This->num_frames = 0; 2350 This->num_frames_committed = 0; 2351 This->committed = FALSE; 2352 2353 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 2354 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 2355 2356 return ret; 2357 } 2358 2359 #else /* !SONAME_LIBTIFF */ 2360 2361 HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv) 2362 { 2363 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n"); 2364 return E_FAIL; 2365 } 2366 2367 HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv) 2368 { 2369 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n"); 2370 return E_FAIL; 2371 } 2372 2373 #endif 2374