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