2 * Copyright 2010 Vincent Povirk for CodeWeavers
3 * Copyright 2016 Dmitry Timoshkov
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.
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.
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
21 #include "wine/port.h"
37 #include "wincodecs_private.h"
39 #include "wine/debug.h"
40 #include "wine/library.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
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.
53 # define toff_t UINT64
56 static CRITICAL_SECTION init_tiff_cs
;
57 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
60 { &init_tiff_cs_debug
.ProcessLocksList
,
61 &init_tiff_cs_debug
.ProcessLocksList
},
62 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
64 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
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};
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
);
86 static void *load_libtiff(void)
90 EnterCriticalSection(&init_tiff_cs
);
92 if (!libtiff_handle
&&
93 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
95 void * (*pTIFFSetWarningHandler
)(void *);
96 void * (*pTIFFSetWarningHandlerExt
)(void *);
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); \
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
);
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
);
126 result
= libtiff_handle
;
128 LeaveCriticalSection(&init_tiff_cs
);
132 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
134 IStream
*stream
= (IStream
*)client_data
;
138 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
139 if (FAILED(hr
)) bytes_read
= 0;
143 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
145 IStream
*stream
= (IStream
*)client_data
;
149 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
150 if (FAILED(hr
)) bytes_written
= 0;
151 return bytes_written
;
154 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
156 IStream
*stream
= (IStream
*)client_data
;
159 ULARGE_INTEGER new_position
;
162 move
.QuadPart
= offset
;
166 origin
= STREAM_SEEK_SET
;
169 origin
= STREAM_SEEK_CUR
;
172 origin
= STREAM_SEEK_END
;
175 ERR("unknown whence value %i\n", whence
);
179 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
180 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
184 static int tiff_stream_close(thandle_t client_data
)
186 /* Caller is responsible for releasing the stream object. */
190 static toff_t
tiff_stream_size(thandle_t client_data
)
192 IStream
*stream
= (IStream
*)client_data
;
196 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
198 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
202 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
204 /* Cannot mmap streams */
208 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
210 /* No need to ever do this, since we can't map things. */
213 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
218 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
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
);
226 IWICBitmapDecoder IWICBitmapDecoder_iface
;
229 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initialized is set */
235 const WICPixelFormatGUID
*format
;
242 int invert_grayscale
;
244 UINT tile_width
, tile_height
;
249 UINT resolution_unit
;
254 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
255 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
259 tiff_decode_info decode_info
;
260 INT cached_tile_x
, cached_tile_y
;
264 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
265 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
267 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
269 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
272 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
274 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
277 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
279 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
282 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
284 uint16 photometric
, bps
, samples
, planar
;
285 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
288 decode_info
->indexed
= 0;
289 decode_info
->reverse_bgr
= 0;
290 decode_info
->invert_grayscale
= 0;
291 decode_info
->tiled
= 0;
292 decode_info
->source_bpp
= 0;
294 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
297 WARN("missing PhotometricInterpretation tag\n");
301 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
303 decode_info
->bps
= bps
;
305 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
306 if (!ret
) samples
= 1;
307 decode_info
->samples
= samples
;
313 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
314 if (!ret
) planar
= 1;
317 FIXME("unhandled planar configuration %u\n", planar
);
321 decode_info
->planar
= planar
;
323 TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar
, photometric
, samples
, bps
);
327 case 0: /* WhiteIsZero */
328 decode_info
->invert_grayscale
= 1;
330 case 1: /* BlackIsZero */
333 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
336 extra_sample_count
= 1;
338 extra_samples
= &extra_sample
;
341 else if (samples
!= 1)
343 FIXME("unhandled %dbpp sample count %u\n", bps
, samples
);
347 decode_info
->bpp
= bps
* samples
;
348 decode_info
->source_bpp
= decode_info
->bpp
;
354 FIXME("unhandled 1bpp sample count %u\n", samples
);
357 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
362 FIXME("unhandled 4bpp grayscale sample count %u\n", samples
);
365 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
369 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
372 decode_info
->bpp
= 32;
374 switch(extra_samples
[0])
376 case 1: /* Associated (pre-multiplied) alpha data */
377 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
379 case 0: /* Unspecified data */
380 case 2: /* Unassociated alpha data */
381 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
384 FIXME("unhandled extra sample type %u\n", extra_samples
[0]);
392 FIXME("unhandled 16bpp grayscale sample count %u\n", samples
);
393 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
395 decode_info
->format
= &GUID_WICPixelFormat16bppGray
;
400 FIXME("unhandled 32bpp grayscale sample count %u\n", samples
);
401 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
403 decode_info
->format
= &GUID_WICPixelFormat32bppGrayFloat
;
406 WARN("unhandled greyscale bit count %u\n", bps
);
407 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
413 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
416 extra_sample_count
= 1;
418 extra_samples
= &extra_sample
;
421 else if (samples
!= 3)
423 FIXME("unhandled RGB sample count %u\n", samples
);
427 decode_info
->bpp
= max(bps
, 8) * samples
;
428 decode_info
->source_bpp
= bps
* samples
;
434 decode_info
->reverse_bgr
= 1;
436 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
438 switch(extra_samples
[0])
440 case 1: /* Associated (pre-multiplied) alpha data */
441 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
443 case 0: /* Unspecified data */
444 case 2: /* Unassociated alpha data */
445 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
448 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
454 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
456 switch(extra_samples
[0])
458 case 1: /* Associated (pre-multiplied) alpha data */
459 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
461 case 0: /* Unspecified data */
462 case 2: /* Unassociated alpha data */
463 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
466 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
473 FIXME("unhandled 32bpp RGB sample count %u\n", samples
);
474 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
476 decode_info
->format
= &GUID_WICPixelFormat128bppRGBAFloat
;
479 WARN("unhandled RGB bit count %u\n", bps
);
480 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
483 case 3: /* RGB Palette */
486 FIXME("unhandled indexed sample count %u\n", samples
);
490 decode_info
->indexed
= 1;
491 decode_info
->bpp
= bps
;
495 decode_info
->format
= &GUID_WICPixelFormat1bppIndexed
;
498 decode_info
->format
= &GUID_WICPixelFormat2bppIndexed
;
501 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
504 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
507 FIXME("unhandled indexed bit count %u\n", bps
);
512 case 5: /* Separated */
515 FIXME("unhandled Separated sample count %u\n", samples
);
519 decode_info
->bpp
= bps
* samples
;
523 decode_info
->format
= &GUID_WICPixelFormat32bppCMYK
;
526 decode_info
->format
= &GUID_WICPixelFormat64bppCMYK
;
530 WARN("unhandled Separated bit count %u\n", bps
);
531 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
535 case 4: /* Transparency mask */
539 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
543 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
546 WARN("missing image width\n");
550 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
553 WARN("missing image length\n");
557 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
559 decode_info
->tiled
= 1;
561 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
564 WARN("missing tile height\n");
568 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
569 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
570 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
572 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
574 if (decode_info
->tile_height
> decode_info
->height
)
575 decode_info
->tile_height
= decode_info
->height
;
576 decode_info
->tile_width
= decode_info
->width
;
577 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
578 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
582 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
583 decode_info
->tile_height
= decode_info
->height
;
584 decode_info
->tile_width
= decode_info
->width
;
585 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
586 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
589 decode_info
->resolution_unit
= 0;
590 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
592 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
595 WARN("missing X resolution\n");
597 /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131)
598 * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */
599 if (!isfinite(decode_info
->xres
))
601 decode_info
->xres
= 0.0;
604 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
607 WARN("missing Y resolution\n");
609 if (!isfinite(decode_info
->yres
))
611 decode_info
->yres
= 0.0;
617 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
620 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
621 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
623 if (!ppv
) return E_INVALIDARG
;
625 if (IsEqualIID(&IID_IUnknown
, iid
) ||
626 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
628 *ppv
= &This
->IWICBitmapDecoder_iface
;
633 return E_NOINTERFACE
;
636 IUnknown_AddRef((IUnknown
*)*ppv
);
640 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
642 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
643 ULONG ref
= InterlockedIncrement(&This
->ref
);
645 TRACE("(%p) refcount=%u\n", iface
, ref
);
650 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
652 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
653 ULONG ref
= InterlockedDecrement(&This
->ref
);
655 TRACE("(%p) refcount=%u\n", iface
, ref
);
659 if (This
->tiff
) pTIFFClose(This
->tiff
);
660 if (This
->stream
) IStream_Release(This
->stream
);
661 This
->lock
.DebugInfo
->Spare
[0] = 0;
662 DeleteCriticalSection(&This
->lock
);
663 HeapFree(GetProcessHeap(), 0, This
);
669 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
674 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
676 if (!stream
|| !capability
) return E_INVALIDARG
;
678 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
679 if (hr
!= S_OK
) return hr
;
681 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
682 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
683 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
687 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
688 WICDecodeOptions cacheOptions
)
690 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
692 tiff_decode_info decode_info
;
695 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
697 EnterCriticalSection(&This
->lock
);
699 if (This
->initialized
)
701 hr
= WINCODEC_ERR_WRONGSTATE
;
705 tiff
= tiff_open_stream(pIStream
, "r");
712 /* make sure that TIFF format is supported */
713 hr
= tiff_get_decode_info(tiff
, &decode_info
);
721 This
->stream
= pIStream
;
722 IStream_AddRef(pIStream
);
723 This
->initialized
= TRUE
;
726 LeaveCriticalSection(&This
->lock
);
730 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
731 GUID
*pguidContainerFormat
)
733 if (!pguidContainerFormat
) return E_INVALIDARG
;
735 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
739 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
740 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
742 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
744 return get_decoder_info(&CLSID_WICTiffDecoder
, ppIDecoderInfo
);
747 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
748 IWICPalette
*palette
)
750 TRACE("(%p,%p)\n", iface
, palette
);
751 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
754 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
755 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
757 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
759 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
761 *ppIMetadataQueryReader
= NULL
;
762 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
765 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
766 IWICBitmapSource
**ppIBitmapSource
)
768 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
770 if (!ppIBitmapSource
) return E_INVALIDARG
;
772 *ppIBitmapSource
= NULL
;
773 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
776 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
777 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
779 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
780 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
783 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
784 IWICBitmapSource
**ppIThumbnail
)
786 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
788 if (!ppIThumbnail
) return E_INVALIDARG
;
790 *ppIThumbnail
= NULL
;
791 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
794 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
797 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
799 if (!pCount
) return E_INVALIDARG
;
801 EnterCriticalSection(&This
->lock
);
802 *pCount
= This
->tiff
? pTIFFNumberOfDirectories(This
->tiff
) : 0;
803 LeaveCriticalSection(&This
->lock
);
805 TRACE("(%p) <-- %i\n", iface
, *pCount
);
810 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
811 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
813 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
814 TiffFrameDecode
*result
;
816 tiff_decode_info decode_info
;
819 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
822 return WINCODEC_ERR_FRAMEMISSING
;
824 EnterCriticalSection(&This
->lock
);
825 res
= pTIFFSetDirectory(This
->tiff
, index
);
826 if (!res
) hr
= E_INVALIDARG
;
827 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
828 LeaveCriticalSection(&This
->lock
);
832 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
836 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
837 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
839 result
->parent
= This
;
840 IWICBitmapDecoder_AddRef(iface
);
841 result
->index
= index
;
842 result
->decode_info
= decode_info
;
843 result
->cached_tile_x
= -1;
844 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
846 if (result
->cached_tile
)
847 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
851 IWICBitmapFrameDecode_Release(&result
->IWICBitmapFrameDecode_iface
);
854 else hr
= E_OUTOFMEMORY
;
857 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
862 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
863 TiffDecoder_QueryInterface
,
866 TiffDecoder_QueryCapability
,
867 TiffDecoder_Initialize
,
868 TiffDecoder_GetContainerFormat
,
869 TiffDecoder_GetDecoderInfo
,
870 TiffDecoder_CopyPalette
,
871 TiffDecoder_GetMetadataQueryReader
,
872 TiffDecoder_GetPreview
,
873 TiffDecoder_GetColorContexts
,
874 TiffDecoder_GetThumbnail
,
875 TiffDecoder_GetFrameCount
,
879 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
882 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
883 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
885 if (!ppv
) return E_INVALIDARG
;
887 if (IsEqualIID(&IID_IUnknown
, iid
) ||
888 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
889 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
891 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
893 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
895 *ppv
= &This
->IWICMetadataBlockReader_iface
;
900 return E_NOINTERFACE
;
903 IUnknown_AddRef((IUnknown
*)*ppv
);
907 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
909 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
910 ULONG ref
= InterlockedIncrement(&This
->ref
);
912 TRACE("(%p) refcount=%u\n", iface
, ref
);
917 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
919 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
920 ULONG ref
= InterlockedDecrement(&This
->ref
);
922 TRACE("(%p) refcount=%u\n", iface
, ref
);
926 IWICBitmapDecoder_Release(&This
->parent
->IWICBitmapDecoder_iface
);
927 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
928 HeapFree(GetProcessHeap(), 0, This
);
934 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
935 UINT
*puiWidth
, UINT
*puiHeight
)
937 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
939 *puiWidth
= This
->decode_info
.width
;
940 *puiHeight
= This
->decode_info
.height
;
942 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
947 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
948 WICPixelFormatGUID
*pPixelFormat
)
950 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
952 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
954 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
959 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
960 double *pDpiX
, double *pDpiY
)
962 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
964 if (This
->decode_info
.xres
== 0 || This
->decode_info
.yres
== 0)
966 *pDpiX
= *pDpiY
= 96.0;
970 switch (This
->decode_info
.resolution_unit
)
973 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
975 case 0: /* Not set */
976 case 1: /* Relative measurements */
978 *pDpiX
= This
->decode_info
.xres
;
979 *pDpiY
= This
->decode_info
.yres
;
981 case 3: /* Centimeter */
982 *pDpiX
= This
->decode_info
.xres
* 2.54;
983 *pDpiY
= This
->decode_info
.yres
* 2.54;
988 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
993 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
994 IWICPalette
*pIPalette
)
996 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
997 uint16
*red
, *green
, *blue
;
998 WICColor colors
[256];
999 int color_count
, ret
, i
;
1001 TRACE("(%p,%p)\n", iface
, pIPalette
);
1003 color_count
= 1<<This
->decode_info
.bps
;
1005 EnterCriticalSection(&This
->parent
->lock
);
1006 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
1007 LeaveCriticalSection(&This
->parent
->lock
);
1011 WARN("Couldn't read color map\n");
1012 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1015 for (i
=0; i
<color_count
; i
++)
1017 colors
[i
] = 0xff000000 |
1018 ((red
[i
]<<8) & 0xff0000) |
1019 (green
[i
] & 0xff00) |
1020 ((blue
[i
]>>8) & 0xff);
1023 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
1026 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
1031 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1033 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
1037 if (This
->decode_info
.tiled
)
1038 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
1040 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
1046 if (This
->decode_info
.source_bpp
== 3 && This
->decode_info
.samples
== 3 && This
->decode_info
.bpp
== 24)
1048 BYTE
*srcdata
, *src
, *dst
;
1049 DWORD x
, y
, count
, width_bytes
= (This
->decode_info
.tile_width
* 3 + 7) / 8;
1051 count
= width_bytes
* This
->decode_info
.tile_height
;
1053 srcdata
= HeapAlloc(GetProcessHeap(), 0, count
);
1054 if (!srcdata
) return E_OUTOFMEMORY
;
1055 memcpy(srcdata
, This
->cached_tile
, count
);
1057 for (y
= 0; y
< This
->decode_info
.tile_height
; y
++)
1059 src
= srcdata
+ y
* width_bytes
;
1060 dst
= This
->cached_tile
+ y
* This
->decode_info
.tile_width
* 3;
1062 for (x
= 0; x
< This
->decode_info
.tile_width
; x
+= 8)
1064 dst
[2] = (src
[0] & 0x80) ? 0xff : 0; /* R */
1065 dst
[1] = (src
[0] & 0x40) ? 0xff : 0; /* G */
1066 dst
[0] = (src
[0] & 0x20) ? 0xff : 0; /* B */
1067 if (x
+ 1 < This
->decode_info
.tile_width
)
1069 dst
[5] = (src
[0] & 0x10) ? 0xff : 0; /* R */
1070 dst
[4] = (src
[0] & 0x08) ? 0xff : 0; /* G */
1071 dst
[3] = (src
[0] & 0x04) ? 0xff : 0; /* B */
1073 if (x
+ 2 < This
->decode_info
.tile_width
)
1075 dst
[8] = (src
[0] & 0x02) ? 0xff : 0; /* R */
1076 dst
[7] = (src
[0] & 0x01) ? 0xff : 0; /* G */
1077 dst
[6] = (src
[1] & 0x80) ? 0xff : 0; /* B */
1079 if (x
+ 3 < This
->decode_info
.tile_width
)
1081 dst
[11] = (src
[1] & 0x40) ? 0xff : 0; /* R */
1082 dst
[10] = (src
[1] & 0x20) ? 0xff : 0; /* G */
1083 dst
[9] = (src
[1] & 0x10) ? 0xff : 0; /* B */
1085 if (x
+ 4 < This
->decode_info
.tile_width
)
1087 dst
[14] = (src
[1] & 0x08) ? 0xff : 0; /* R */
1088 dst
[13] = (src
[1] & 0x04) ? 0xff : 0; /* G */
1089 dst
[12] = (src
[1] & 0x02) ? 0xff : 0; /* B */
1091 if (x
+ 5 < This
->decode_info
.tile_width
)
1093 dst
[17] = (src
[1] & 0x01) ? 0xff : 0; /* R */
1094 dst
[16] = (src
[2] & 0x80) ? 0xff : 0; /* G */
1095 dst
[15] = (src
[2] & 0x40) ? 0xff : 0; /* B */
1097 if (x
+ 6 < This
->decode_info
.tile_width
)
1099 dst
[20] = (src
[2] & 0x20) ? 0xff : 0; /* R */
1100 dst
[19] = (src
[2] & 0x10) ? 0xff : 0; /* G */
1101 dst
[18] = (src
[2] & 0x08) ? 0xff : 0; /* B */
1103 if (x
+ 7 < This
->decode_info
.tile_width
)
1105 dst
[23] = (src
[2] & 0x04) ? 0xff : 0; /* R */
1106 dst
[22] = (src
[2] & 0x02) ? 0xff : 0; /* G */
1107 dst
[21] = (src
[2] & 0x01) ? 0xff : 0; /* B */
1114 HeapFree(GetProcessHeap(), 0, srcdata
);
1117 else if (This
->decode_info
.source_bpp
== 12 && This
->decode_info
.samples
== 3 && This
->decode_info
.bpp
== 24)
1119 BYTE
*srcdata
, *src
, *dst
;
1120 DWORD x
, y
, count
, width_bytes
= (This
->decode_info
.tile_width
* 12 + 7) / 8;
1122 count
= width_bytes
* This
->decode_info
.tile_height
;
1124 srcdata
= HeapAlloc(GetProcessHeap(), 0, count
);
1125 if (!srcdata
) return E_OUTOFMEMORY
;
1126 memcpy(srcdata
, This
->cached_tile
, count
);
1128 for (y
= 0; y
< This
->decode_info
.tile_height
; y
++)
1130 src
= srcdata
+ y
* width_bytes
;
1131 dst
= This
->cached_tile
+ y
* This
->decode_info
.tile_width
* 3;
1133 for (x
= 0; x
< This
->decode_info
.tile_width
; x
+= 2)
1135 dst
[0] = ((src
[1] & 0xf0) >> 4) * 17; /* B */
1136 dst
[1] = (src
[0] & 0x0f) * 17; /* G */
1137 dst
[2] = ((src
[0] & 0xf0) >> 4) * 17; /* R */
1138 if (x
+ 1 < This
->decode_info
.tile_width
)
1140 dst
[5] = (src
[1] & 0x0f) * 17; /* B */
1141 dst
[4] = ((src
[2] & 0xf0) >> 4) * 17; /* G */
1142 dst
[3] = (src
[2] & 0x0f) * 17; /* R */
1149 HeapFree(GetProcessHeap(), 0, srcdata
);
1152 else if (This
->decode_info
.source_bpp
== 4 && This
->decode_info
.samples
== 4 && This
->decode_info
.bpp
== 32)
1154 BYTE
*srcdata
, *src
, *dst
;
1155 DWORD x
, y
, count
, width_bytes
= (This
->decode_info
.tile_width
* 3 + 7) / 8;
1157 count
= width_bytes
* This
->decode_info
.tile_height
;
1159 srcdata
= HeapAlloc(GetProcessHeap(), 0, count
);
1160 if (!srcdata
) return E_OUTOFMEMORY
;
1161 memcpy(srcdata
, This
->cached_tile
, count
);
1163 for (y
= 0; y
< This
->decode_info
.tile_height
; y
++)
1165 src
= srcdata
+ y
* width_bytes
;
1166 dst
= This
->cached_tile
+ y
* This
->decode_info
.tile_width
* 4;
1168 /* 1 source byte expands to 2 BGRA samples */
1170 for (x
= 0; x
< This
->decode_info
.tile_width
; x
+= 2)
1172 dst
[0] = (src
[0] & 0x20) ? 0xff : 0; /* B */
1173 dst
[1] = (src
[0] & 0x40) ? 0xff : 0; /* G */
1174 dst
[2] = (src
[0] & 0x80) ? 0xff : 0; /* R */
1175 dst
[3] = (src
[0] & 0x10) ? 0xff : 0; /* A */
1176 if (x
+ 1 < This
->decode_info
.tile_width
)
1178 dst
[4] = (src
[0] & 0x02) ? 0xff : 0; /* B */
1179 dst
[5] = (src
[0] & 0x04) ? 0xff : 0; /* G */
1180 dst
[6] = (src
[0] & 0x08) ? 0xff : 0; /* R */
1181 dst
[7] = (src
[0] & 0x01) ? 0xff : 0; /* A */
1188 HeapFree(GetProcessHeap(), 0, srcdata
);
1191 else if (This
->decode_info
.source_bpp
== 16 && This
->decode_info
.samples
== 4 && This
->decode_info
.bpp
== 32)
1194 DWORD count
= This
->decode_info
.tile_width
* This
->decode_info
.tile_height
;
1196 src
= This
->cached_tile
+ count
* 2;
1197 dst
= This
->cached_tile
+ This
->decode_info
.tile_size
;
1209 dst
[0] = ((b
[1] & 0xf0) >> 4) * 17; /* B */
1210 dst
[1] = (b
[0] & 0x0f) * 17; /* G */
1211 dst
[2] = ((b
[0] & 0xf0) >> 4) * 17; /* R */
1212 dst
[3] = (b
[1] & 0x0f) * 17; /* A */
1215 /* 8bpp grayscale with extra alpha */
1216 else if (This
->decode_info
.source_bpp
== 16 && This
->decode_info
.samples
== 2 && This
->decode_info
.bpp
== 32)
1219 DWORD
*dst
, count
= This
->decode_info
.tile_width
* This
->decode_info
.tile_height
;
1221 src
= This
->cached_tile
+ This
->decode_info
.tile_width
* This
->decode_info
.tile_height
* 2 - 2;
1222 dst
= (DWORD
*)(This
->cached_tile
+ This
->decode_info
.tile_size
- 4);
1226 *dst
-- = src
[0] | (src
[0] << 8) | (src
[0] << 16) | (src
[1] << 24);
1231 if (This
->decode_info
.reverse_bgr
)
1233 if (This
->decode_info
.bps
== 8)
1235 UINT sample_count
= This
->decode_info
.samples
;
1237 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
1238 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
1242 if (swap_bytes
&& This
->decode_info
.bps
> 8)
1244 UINT row
, i
, samples_per_row
;
1247 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
1249 switch(This
->decode_info
.bps
)
1252 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
1254 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
1255 for (i
=0; i
<samples_per_row
; i
++)
1258 sample
[1] = sample
[0];
1265 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
1270 if (This
->decode_info
.invert_grayscale
)
1274 if (This
->decode_info
.samples
!= 1)
1276 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
1280 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
1282 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
1286 This
->cached_tile_x
= tile_x
;
1287 This
->cached_tile_y
= tile_y
;
1292 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
1293 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
1295 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1296 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
1297 UINT tile_x
, tile_y
;
1304 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
1310 rect
.Width
= This
->decode_info
.width
;
1311 rect
.Height
= This
->decode_info
.height
;
1316 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
1317 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1318 return E_INVALIDARG
;
1321 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1323 if (cbStride
< bytesperrow
)
1324 return E_INVALIDARG
;
1326 if ((cbStride
* (prc
->Height
-1)) + bytesperrow
> cbBufferSize
)
1327 return E_INVALIDARG
;
1329 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1330 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1331 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1332 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1334 EnterCriticalSection(&This
->parent
->lock
);
1336 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1338 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1340 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1342 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1347 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1350 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1352 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1355 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1357 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1358 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1359 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1360 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1362 rc
.Width
= prc
->Width
;
1364 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1365 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1366 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1367 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1369 rc
.Height
= prc
->Height
;
1371 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1372 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1374 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1375 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1376 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1381 LeaveCriticalSection(&This
->parent
->lock
);
1382 TRACE("<-- 0x%x\n", hr
);
1388 LeaveCriticalSection(&This
->parent
->lock
);
1393 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1394 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1396 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1398 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1400 if (!ppIMetadataQueryReader
)
1401 return E_INVALIDARG
;
1403 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
1406 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1407 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1409 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1410 const BYTE
*profile
;
1414 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1416 EnterCriticalSection(&This
->parent
->lock
);
1418 if (pTIFFGetField(This
->parent
->tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
1420 if (cCount
&& ppIColorContexts
)
1422 hr
= IWICColorContext_InitializeFromMemory(*ppIColorContexts
, profile
, len
);
1425 LeaveCriticalSection(&This
->parent
->lock
);
1434 LeaveCriticalSection(&This
->parent
->lock
);
1439 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1440 IWICBitmapSource
**ppIThumbnail
)
1442 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1444 if (!ppIThumbnail
) return E_INVALIDARG
;
1446 *ppIThumbnail
= NULL
;
1447 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1450 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1451 TiffFrameDecode_QueryInterface
,
1452 TiffFrameDecode_AddRef
,
1453 TiffFrameDecode_Release
,
1454 TiffFrameDecode_GetSize
,
1455 TiffFrameDecode_GetPixelFormat
,
1456 TiffFrameDecode_GetResolution
,
1457 TiffFrameDecode_CopyPalette
,
1458 TiffFrameDecode_CopyPixels
,
1459 TiffFrameDecode_GetMetadataQueryReader
,
1460 TiffFrameDecode_GetColorContexts
,
1461 TiffFrameDecode_GetThumbnail
1464 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1465 REFIID iid
, void **ppv
)
1467 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1468 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1471 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1473 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1474 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1477 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1479 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1480 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1483 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1486 TRACE("(%p,%p)\n", iface
, guid
);
1488 if (!guid
) return E_INVALIDARG
;
1490 *guid
= GUID_ContainerFormatTiff
;
1494 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1497 TRACE("%p,%p\n", iface
, count
);
1499 if (!count
) return E_INVALIDARG
;
1505 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1508 LARGE_INTEGER dir_offset
;
1509 IWICMetadataReader
*metadata_reader
;
1510 IWICPersistStream
*persist
;
1512 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1514 hr
= IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
1515 if (FAILED(hr
)) return hr
;
1517 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1520 IWICMetadataReader_Release(metadata_reader
);
1524 EnterCriticalSection(&This
->parent
->lock
);
1526 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1527 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1530 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1531 #ifdef WORDS_BIGENDIAN
1532 DWORD persist_options
= byte_swapped
? WICPersistOptionLittleEndian
: WICPersistOptionBigEndian
;
1534 DWORD persist_options
= byte_swapped
? WICPersistOptionBigEndian
: WICPersistOptionLittleEndian
;
1536 persist_options
|= WICPersistOptionNoCacheStream
;
1537 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1539 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1542 LeaveCriticalSection(&This
->parent
->lock
);
1544 IWICPersistStream_Release(persist
);
1548 IWICMetadataReader_Release(metadata_reader
);
1552 *reader
= metadata_reader
;
1556 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1557 UINT index
, IWICMetadataReader
**reader
)
1559 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1561 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1563 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1565 return create_metadata_reader(This
, reader
);
1568 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1569 IEnumUnknown
**enum_metadata
)
1571 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1575 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1577 TiffFrameDecode_Block_QueryInterface
,
1578 TiffFrameDecode_Block_AddRef
,
1579 TiffFrameDecode_Block_Release
,
1580 TiffFrameDecode_Block_GetContainerFormat
,
1581 TiffFrameDecode_Block_GetCount
,
1582 TiffFrameDecode_Block_GetReaderByIndex
,
1583 TiffFrameDecode_Block_GetEnumerator
1586 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
1591 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1595 if (!load_libtiff())
1597 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1601 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1602 if (!This
) return E_OUTOFMEMORY
;
1604 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1606 This
->stream
= NULL
;
1607 InitializeCriticalSection(&This
->lock
);
1608 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1610 This
->initialized
= FALSE
;
1612 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1613 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1618 struct tiff_encode_format
{
1619 const WICPixelFormatGUID
*guid
;
1625 int extra_sample_type
;
1629 static const struct tiff_encode_format formats
[] = {
1630 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1631 {&GUID_WICPixelFormat24bppRGB
, 2, 8, 3, 24, 0, 0, 0},
1632 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1633 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1634 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1635 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1636 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1637 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1638 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1639 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1640 {&GUID_WICPixelFormat1bppIndexed
, 3, 1, 1, 1, 0, 0, 0},
1641 {&GUID_WICPixelFormat4bppIndexed
, 3, 4, 1, 4, 0, 0, 0},
1642 {&GUID_WICPixelFormat8bppIndexed
, 3, 8, 1, 8, 0, 0, 0},
1646 typedef struct TiffEncoder
{
1647 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1650 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1655 ULONG num_frames_committed
;
1658 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1660 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1663 typedef struct TiffFrameEncode
{
1664 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1666 TiffEncoder
*parent
;
1667 /* fields below are protected by parent->lock */
1671 const struct tiff_encode_format
*format
;
1675 WICColor palette
[256];
1679 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1681 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1684 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1687 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1688 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1690 if (!ppv
) return E_INVALIDARG
;
1692 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1693 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1695 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1700 return E_NOINTERFACE
;
1703 IUnknown_AddRef((IUnknown
*)*ppv
);
1707 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1709 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1710 ULONG ref
= InterlockedIncrement(&This
->ref
);
1712 TRACE("(%p) refcount=%u\n", iface
, ref
);
1717 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1719 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1720 ULONG ref
= InterlockedDecrement(&This
->ref
);
1722 TRACE("(%p) refcount=%u\n", iface
, ref
);
1726 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1727 HeapFree(GetProcessHeap(), 0, This
);
1733 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1734 IPropertyBag2
*pIEncoderOptions
)
1736 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1737 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1739 EnterCriticalSection(&This
->parent
->lock
);
1741 if (This
->initialized
)
1743 LeaveCriticalSection(&This
->parent
->lock
);
1744 return WINCODEC_ERR_WRONGSTATE
;
1747 This
->initialized
= TRUE
;
1749 LeaveCriticalSection(&This
->parent
->lock
);
1754 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1755 UINT uiWidth
, UINT uiHeight
)
1757 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1758 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1760 EnterCriticalSection(&This
->parent
->lock
);
1762 if (!This
->initialized
|| This
->info_written
)
1764 LeaveCriticalSection(&This
->parent
->lock
);
1765 return WINCODEC_ERR_WRONGSTATE
;
1768 This
->width
= uiWidth
;
1769 This
->height
= uiHeight
;
1771 LeaveCriticalSection(&This
->parent
->lock
);
1776 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1777 double dpiX
, double dpiY
)
1779 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1780 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1782 EnterCriticalSection(&This
->parent
->lock
);
1784 if (!This
->initialized
|| This
->info_written
)
1786 LeaveCriticalSection(&This
->parent
->lock
);
1787 return WINCODEC_ERR_WRONGSTATE
;
1793 LeaveCriticalSection(&This
->parent
->lock
);
1798 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1799 WICPixelFormatGUID
*pPixelFormat
)
1801 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1804 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1806 EnterCriticalSection(&This
->parent
->lock
);
1808 if (!This
->initialized
|| This
->info_written
)
1810 LeaveCriticalSection(&This
->parent
->lock
);
1811 return WINCODEC_ERR_WRONGSTATE
;
1814 if (IsEqualGUID(pPixelFormat
, &GUID_WICPixelFormat2bppIndexed
))
1815 *pPixelFormat
= GUID_WICPixelFormat4bppIndexed
;
1817 for (i
=0; formats
[i
].guid
; i
++)
1819 if (IsEqualGUID(formats
[i
].guid
, pPixelFormat
))
1823 if (!formats
[i
].guid
) i
= 0;
1825 This
->format
= &formats
[i
];
1826 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1828 LeaveCriticalSection(&This
->parent
->lock
);
1833 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1834 UINT cCount
, IWICColorContext
**ppIColorContext
)
1836 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1840 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1841 IWICPalette
*palette
)
1843 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1846 TRACE("(%p,%p)\n", iface
, palette
);
1848 if (!palette
) return E_INVALIDARG
;
1850 EnterCriticalSection(&This
->parent
->lock
);
1852 if (This
->initialized
)
1853 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
1855 hr
= WINCODEC_ERR_NOTINITIALIZED
;
1857 LeaveCriticalSection(&This
->parent
->lock
);
1861 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1862 IWICBitmapSource
*pIThumbnail
)
1864 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1865 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1868 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1869 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1871 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1872 BYTE
*row_data
, *swapped_data
= NULL
;
1873 UINT i
, j
, line_size
;
1875 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1877 EnterCriticalSection(&This
->parent
->lock
);
1879 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1881 LeaveCriticalSection(&This
->parent
->lock
);
1882 return WINCODEC_ERR_WRONGSTATE
;
1885 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1887 LeaveCriticalSection(&This
->parent
->lock
);
1888 return E_INVALIDARG
;
1891 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1893 if (This
->format
->reverse_bgr
)
1895 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1898 LeaveCriticalSection(&This
->parent
->lock
);
1899 return E_OUTOFMEMORY
;
1903 if (!This
->info_written
)
1905 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1906 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1907 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1908 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1910 if (This
->format
->extra_sample
)
1912 uint16 extra_samples
;
1913 extra_samples
= This
->format
->extra_sample_type
;
1915 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1918 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1919 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1921 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1923 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1924 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1925 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1928 if (This
->format
->bpp
<= 8 && This
->colors
&& !IsEqualGUID(This
->format
->guid
, &GUID_WICPixelFormatBlackWhite
))
1930 uint16 red
[256], green
[256], blue
[256];
1933 for (i
= 0; i
< This
->colors
; i
++)
1935 red
[i
] = (This
->palette
[i
] >> 8) & 0xff00;
1936 green
[i
] = This
->palette
[i
] & 0xff00;
1937 blue
[i
] = (This
->palette
[i
] << 8) & 0xff00;
1940 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, red
, green
, blue
);
1943 This
->info_written
= TRUE
;
1946 for (i
=0; i
<lineCount
; i
++)
1948 row_data
= pbPixels
+ i
* cbStride
;
1950 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1952 memcpy(swapped_data
, row_data
, line_size
);
1953 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1956 temp
= swapped_data
[j
];
1957 swapped_data
[j
] = swapped_data
[j
+2];
1958 swapped_data
[j
+2] = temp
;
1960 row_data
= swapped_data
;
1963 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1966 This
->lines_written
+= lineCount
;
1968 LeaveCriticalSection(&This
->parent
->lock
);
1970 HeapFree(GetProcessHeap(), 0, swapped_data
);
1975 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1976 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1978 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1981 TRACE("(%p,%p,%s)\n", iface
, pIBitmapSource
, debug_wic_rect(prc
));
1983 if (!This
->initialized
)
1984 return WINCODEC_ERR_WRONGSTATE
;
1986 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
1987 This
->format
? This
->format
->guid
: NULL
, This
->width
, This
->height
,
1988 This
->xres
, This
->yres
);
1992 hr
= write_source(iface
, pIBitmapSource
, prc
,
1993 This
->format
->guid
, This
->format
->bpp
, This
->width
, This
->height
);
1999 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
2001 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
2003 TRACE("(%p)\n", iface
);
2005 EnterCriticalSection(&This
->parent
->lock
);
2007 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
2009 LeaveCriticalSection(&This
->parent
->lock
);
2010 return WINCODEC_ERR_WRONGSTATE
;
2013 /* libtiff will commit the data when creating a new frame or closing the file */
2015 This
->committed
= TRUE
;
2016 This
->parent
->num_frames_committed
++;
2018 LeaveCriticalSection(&This
->parent
->lock
);
2023 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
2024 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
2026 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
2030 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
2031 TiffFrameEncode_QueryInterface
,
2032 TiffFrameEncode_AddRef
,
2033 TiffFrameEncode_Release
,
2034 TiffFrameEncode_Initialize
,
2035 TiffFrameEncode_SetSize
,
2036 TiffFrameEncode_SetResolution
,
2037 TiffFrameEncode_SetPixelFormat
,
2038 TiffFrameEncode_SetColorContexts
,
2039 TiffFrameEncode_SetPalette
,
2040 TiffFrameEncode_SetThumbnail
,
2041 TiffFrameEncode_WritePixels
,
2042 TiffFrameEncode_WriteSource
,
2043 TiffFrameEncode_Commit
,
2044 TiffFrameEncode_GetMetadataQueryWriter
2047 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
2050 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2051 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
2053 if (!ppv
) return E_INVALIDARG
;
2055 if (IsEqualIID(&IID_IUnknown
, iid
) ||
2056 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
2058 *ppv
= &This
->IWICBitmapEncoder_iface
;
2063 return E_NOINTERFACE
;
2066 IUnknown_AddRef((IUnknown
*)*ppv
);
2070 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
2072 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2073 ULONG ref
= InterlockedIncrement(&This
->ref
);
2075 TRACE("(%p) refcount=%u\n", iface
, ref
);
2080 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
2082 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2083 ULONG ref
= InterlockedDecrement(&This
->ref
);
2085 TRACE("(%p) refcount=%u\n", iface
, ref
);
2089 if (This
->tiff
) pTIFFClose(This
->tiff
);
2090 if (This
->stream
) IStream_Release(This
->stream
);
2091 This
->lock
.DebugInfo
->Spare
[0] = 0;
2092 DeleteCriticalSection(&This
->lock
);
2093 HeapFree(GetProcessHeap(), 0, This
);
2099 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
2100 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
2102 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2106 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
2108 EnterCriticalSection(&This
->lock
);
2110 if (This
->initialized
|| This
->committed
)
2112 hr
= WINCODEC_ERR_WRONGSTATE
;
2116 tiff
= tiff_open_stream(pIStream
, "w");
2125 This
->stream
= pIStream
;
2126 IStream_AddRef(pIStream
);
2127 This
->initialized
= TRUE
;
2130 LeaveCriticalSection(&This
->lock
);
2134 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
2135 GUID
*pguidContainerFormat
)
2137 TRACE("(%p,%p)\n", iface
, pguidContainerFormat
);
2139 if (!pguidContainerFormat
)
2140 return E_INVALIDARG
;
2142 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
2146 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
, IWICBitmapEncoderInfo
**info
)
2148 IWICComponentInfo
*comp_info
;
2151 TRACE("%p,%p\n", iface
, info
);
2153 if (!info
) return E_INVALIDARG
;
2155 hr
= CreateComponentInfo(&CLSID_WICTiffEncoder
, &comp_info
);
2158 hr
= IWICComponentInfo_QueryInterface(comp_info
, &IID_IWICBitmapEncoderInfo
, (void **)info
);
2159 IWICComponentInfo_Release(comp_info
);
2164 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
2165 UINT cCount
, IWICColorContext
**ppIColorContext
)
2167 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
2171 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
2173 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2176 TRACE("(%p,%p)\n", iface
, palette
);
2178 EnterCriticalSection(&This
->lock
);
2180 hr
= This
->stream
? WINCODEC_ERR_UNSUPPORTEDOPERATION
: WINCODEC_ERR_NOTINITIALIZED
;
2182 LeaveCriticalSection(&This
->lock
);
2187 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
2189 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
2190 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2193 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
2195 TRACE("(%p,%p)\n", iface
, pIPreview
);
2196 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2199 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
2200 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
2202 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2203 TiffFrameEncode
*result
;
2204 static const PROPBAG2 opts
[2] =
2206 { PROPBAG2_TYPE_DATA
, VT_UI1
, 0, 0, (LPOLESTR
)wszTiffCompressionMethod
},
2207 { PROPBAG2_TYPE_DATA
, VT_R4
, 0, 0, (LPOLESTR
)wszCompressionQuality
},
2211 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
2213 EnterCriticalSection(&This
->lock
);
2215 if (!This
->initialized
|| This
->committed
)
2217 hr
= WINCODEC_ERR_WRONGSTATE
;
2219 else if (This
->num_frames
!= This
->num_frames_committed
)
2221 FIXME("New frame created before previous frame was committed\n");
2225 if (ppIEncoderOptions
&& SUCCEEDED(hr
))
2227 hr
= CreatePropertyBag2(opts
, ARRAY_SIZE(opts
), ppIEncoderOptions
);
2233 V_UI1(&v
) = WICTiffCompressionDontCare
;
2234 hr
= IPropertyBag2_Write(*ppIEncoderOptions
, 1, (PROPBAG2
*)opts
, &v
);
2238 IPropertyBag2_Release(*ppIEncoderOptions
);
2239 *ppIEncoderOptions
= NULL
;
2246 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
2250 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
2252 result
->parent
= This
;
2253 result
->initialized
= FALSE
;
2254 result
->info_written
= FALSE
;
2255 result
->committed
= FALSE
;
2256 result
->format
= NULL
;
2261 result
->lines_written
= 0;
2264 IWICBitmapEncoder_AddRef(iface
);
2265 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
2267 if (This
->num_frames
!= 0)
2268 pTIFFWriteDirectory(This
->tiff
);
2277 IPropertyBag2_Release(*ppIEncoderOptions
);
2278 *ppIEncoderOptions
= NULL
;
2282 LeaveCriticalSection(&This
->lock
);
2287 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
2289 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2291 TRACE("(%p)\n", iface
);
2293 EnterCriticalSection(&This
->lock
);
2295 if (!This
->initialized
|| This
->committed
)
2297 LeaveCriticalSection(&This
->lock
);
2298 return WINCODEC_ERR_WRONGSTATE
;
2301 pTIFFClose(This
->tiff
);
2302 IStream_Release(This
->stream
);
2303 This
->stream
= NULL
;
2306 This
->committed
= TRUE
;
2308 LeaveCriticalSection(&This
->lock
);
2313 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
2314 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
2316 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
2320 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
2321 TiffEncoder_QueryInterface
,
2323 TiffEncoder_Release
,
2324 TiffEncoder_Initialize
,
2325 TiffEncoder_GetContainerFormat
,
2326 TiffEncoder_GetEncoderInfo
,
2327 TiffEncoder_SetColorContexts
,
2328 TiffEncoder_SetPalette
,
2329 TiffEncoder_SetThumbnail
,
2330 TiffEncoder_SetPreview
,
2331 TiffEncoder_CreateNewFrame
,
2333 TiffEncoder_GetMetadataQueryWriter
2336 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2341 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
2345 if (!load_libtiff())
2347 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
2351 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
2352 if (!This
) return E_OUTOFMEMORY
;
2354 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
2356 This
->stream
= NULL
;
2357 InitializeCriticalSection(&This
->lock
);
2358 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
2360 This
->initialized
= FALSE
;
2361 This
->num_frames
= 0;
2362 This
->num_frames_committed
= 0;
2363 This
->committed
= FALSE
;
2365 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2366 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
2371 #else /* !SONAME_LIBTIFF */
2373 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
2375 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
2379 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2381 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");