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