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
20 #include "wincodecs_private.h"
31 /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which
32 * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they
33 * are supposed to be always 64-bit.
34 * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x.
38 # define toff_t UINT64
41 static CRITICAL_SECTION init_tiff_cs
;
42 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
45 { &init_tiff_cs_debug
.ProcessLocksList
,
46 &init_tiff_cs_debug
.ProcessLocksList
},
47 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
49 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
51 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};
52 static const WCHAR wszCompressionQuality
[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
54 static void *libtiff_handle
;
55 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
56 MAKE_FUNCPTR(TIFFClientOpen
);
57 MAKE_FUNCPTR(TIFFClose
);
58 MAKE_FUNCPTR(TIFFCurrentDirOffset
);
59 MAKE_FUNCPTR(TIFFGetField
);
60 MAKE_FUNCPTR(TIFFIsByteSwapped
);
61 MAKE_FUNCPTR(TIFFNumberOfDirectories
);
62 MAKE_FUNCPTR(TIFFReadDirectory
);
63 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
64 MAKE_FUNCPTR(TIFFReadEncodedTile
);
65 MAKE_FUNCPTR(TIFFSetDirectory
);
66 MAKE_FUNCPTR(TIFFSetField
);
67 MAKE_FUNCPTR(TIFFWriteDirectory
);
68 MAKE_FUNCPTR(TIFFWriteScanline
);
71 static void *load_libtiff(void)
75 EnterCriticalSection(&init_tiff_cs
);
77 if (!libtiff_handle
&&
78 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
80 void * (*pTIFFSetWarningHandler
)(void *);
81 void * (*pTIFFSetWarningHandlerExt
)(void *);
83 #define LOAD_FUNCPTR(f) \
84 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
85 ERR("failed to load symbol %s\n", #f); \
86 libtiff_handle = NULL; \
87 LeaveCriticalSection(&init_tiff_cs); \
90 LOAD_FUNCPTR(TIFFClientOpen
);
91 LOAD_FUNCPTR(TIFFClose
);
92 LOAD_FUNCPTR(TIFFCurrentDirOffset
);
93 LOAD_FUNCPTR(TIFFGetField
);
94 LOAD_FUNCPTR(TIFFIsByteSwapped
);
95 LOAD_FUNCPTR(TIFFNumberOfDirectories
);
96 LOAD_FUNCPTR(TIFFReadDirectory
);
97 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
98 LOAD_FUNCPTR(TIFFReadEncodedTile
);
99 LOAD_FUNCPTR(TIFFSetDirectory
);
100 LOAD_FUNCPTR(TIFFSetField
);
101 LOAD_FUNCPTR(TIFFWriteDirectory
);
102 LOAD_FUNCPTR(TIFFWriteScanline
);
105 if ((pTIFFSetWarningHandler
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandler", NULL
, 0)))
106 pTIFFSetWarningHandler(NULL
);
107 if ((pTIFFSetWarningHandlerExt
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandlerExt", NULL
, 0)))
108 pTIFFSetWarningHandlerExt(NULL
);
111 result
= libtiff_handle
;
113 LeaveCriticalSection(&init_tiff_cs
);
117 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
119 IStream
*stream
= (IStream
*)client_data
;
123 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
124 if (FAILED(hr
)) bytes_read
= 0;
128 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
130 IStream
*stream
= (IStream
*)client_data
;
134 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
135 if (FAILED(hr
)) bytes_written
= 0;
136 return bytes_written
;
139 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
141 IStream
*stream
= (IStream
*)client_data
;
144 ULARGE_INTEGER new_position
;
147 move
.QuadPart
= offset
;
151 origin
= STREAM_SEEK_SET
;
154 origin
= STREAM_SEEK_CUR
;
157 origin
= STREAM_SEEK_END
;
160 ERR("unknown whence value %i\n", whence
);
164 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
165 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
169 static int tiff_stream_close(thandle_t client_data
)
171 /* Caller is responsible for releasing the stream object. */
175 static toff_t
tiff_stream_size(thandle_t client_data
)
177 IStream
*stream
= (IStream
*)client_data
;
181 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
183 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
187 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
189 /* Cannot mmap streams */
193 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
195 /* No need to ever do this, since we can't map things. */
198 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
203 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
205 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
206 tiff_stream_write
, (void *)tiff_stream_seek
, tiff_stream_close
,
207 (void *)tiff_stream_size
, (void *)tiff_stream_map
, (void *)tiff_stream_unmap
);
211 IWICBitmapDecoder IWICBitmapDecoder_iface
;
214 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initialized is set */
220 const WICPixelFormatGUID
*format
;
227 int invert_grayscale
;
229 UINT tile_width
, tile_height
;
234 UINT resolution_unit
;
239 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
240 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
244 tiff_decode_info decode_info
;
245 INT cached_tile_x
, cached_tile_y
;
249 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
250 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
252 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
254 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
257 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
259 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
262 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
264 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
267 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
269 uint16 photometric
, bps
, samples
, planar
;
270 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
273 decode_info
->indexed
= 0;
274 decode_info
->reverse_bgr
= 0;
275 decode_info
->invert_grayscale
= 0;
276 decode_info
->tiled
= 0;
278 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
281 WARN("missing PhotometricInterpretation tag\n");
285 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
287 decode_info
->bps
= bps
;
289 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
290 if (!ret
) samples
= 1;
291 decode_info
->samples
= samples
;
297 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
298 if (!ret
) planar
= 1;
301 FIXME("unhandled planar configuration %u\n", planar
);
305 decode_info
->planar
= planar
;
307 TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar
, photometric
, samples
, bps
);
311 case 0: /* WhiteIsZero */
312 decode_info
->invert_grayscale
= 1;
314 case 1: /* BlackIsZero */
317 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
320 extra_sample_count
= 1;
322 extra_samples
= &extra_sample
;
325 else if (samples
!= 1)
327 FIXME("unhandled %dbpp sample count %u\n", bps
, samples
);
331 decode_info
->bpp
= bps
* samples
;
332 decode_info
->source_bpp
= decode_info
->bpp
;
338 FIXME("unhandled 1bpp sample count %u\n", samples
);
341 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
346 FIXME("unhandled 4bpp grayscale sample count %u\n", samples
);
349 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
353 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
356 decode_info
->bpp
= 32;
358 switch(extra_samples
[0])
360 case 1: /* Associated (pre-multiplied) alpha data */
361 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
363 case 0: /* Unspecified data */
364 case 2: /* Unassociated alpha data */
365 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
368 FIXME("unhandled extra sample type %u\n", extra_samples
[0]);
376 FIXME("unhandled 16bpp grayscale sample count %u\n", samples
);
377 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
379 decode_info
->format
= &GUID_WICPixelFormat16bppGray
;
384 FIXME("unhandled 32bpp grayscale sample count %u\n", samples
);
385 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
387 decode_info
->format
= &GUID_WICPixelFormat32bppGrayFloat
;
390 WARN("unhandled greyscale bit count %u\n", bps
);
391 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
397 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
400 extra_sample_count
= 1;
402 extra_samples
= &extra_sample
;
405 else if (samples
!= 3)
407 FIXME("unhandled RGB sample count %u\n", samples
);
411 decode_info
->bpp
= max(bps
, 8) * samples
;
412 decode_info
->source_bpp
= bps
* samples
;
418 decode_info
->reverse_bgr
= 1;
420 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
422 switch(extra_samples
[0])
424 case 1: /* Associated (pre-multiplied) alpha data */
425 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
427 case 0: /* Unspecified data */
428 case 2: /* Unassociated alpha data */
429 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
432 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
438 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
440 switch(extra_samples
[0])
442 case 1: /* Associated (pre-multiplied) alpha data */
443 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
445 case 0: /* Unspecified data */
446 case 2: /* Unassociated alpha data */
447 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
450 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
457 FIXME("unhandled 32bpp RGB sample count %u\n", samples
);
458 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
460 decode_info
->format
= &GUID_WICPixelFormat128bppRGBAFloat
;
463 WARN("unhandled RGB bit count %u\n", bps
);
464 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
467 case 3: /* RGB Palette */
470 FIXME("unhandled indexed sample count %u\n", samples
);
474 decode_info
->indexed
= 1;
475 decode_info
->bpp
= bps
;
479 decode_info
->format
= &GUID_WICPixelFormat1bppIndexed
;
482 decode_info
->format
= &GUID_WICPixelFormat2bppIndexed
;
485 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
488 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
491 FIXME("unhandled indexed bit count %u\n", bps
);
496 case 5: /* Separated */
499 FIXME("unhandled Separated sample count %u\n", samples
);
503 decode_info
->bpp
= bps
* samples
;
507 decode_info
->format
= &GUID_WICPixelFormat32bppCMYK
;
510 decode_info
->format
= &GUID_WICPixelFormat64bppCMYK
;
514 WARN("unhandled Separated bit count %u\n", bps
);
515 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
519 case 4: /* Transparency mask */
523 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
527 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
530 WARN("missing image width\n");
534 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
537 WARN("missing image length\n");
541 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
543 decode_info
->tiled
= 1;
545 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
548 WARN("missing tile height\n");
552 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
553 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
554 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
556 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
558 if (decode_info
->tile_height
> decode_info
->height
)
559 decode_info
->tile_height
= decode_info
->height
;
560 decode_info
->tile_width
= decode_info
->width
;
561 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
562 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
566 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
567 decode_info
->tile_height
= decode_info
->height
;
568 decode_info
->tile_width
= decode_info
->width
;
569 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
570 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
573 decode_info
->resolution_unit
= 0;
574 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
575 if (decode_info
->resolution_unit
!= 0)
577 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
580 WARN("missing X resolution\n");
581 decode_info
->resolution_unit
= 0;
584 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
587 WARN("missing Y resolution\n");
588 decode_info
->resolution_unit
= 0;
595 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
598 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
599 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
601 if (!ppv
) return E_INVALIDARG
;
603 if (IsEqualIID(&IID_IUnknown
, iid
) ||
604 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
606 *ppv
= &This
->IWICBitmapDecoder_iface
;
611 return E_NOINTERFACE
;
614 IUnknown_AddRef((IUnknown
*)*ppv
);
618 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
620 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
621 ULONG ref
= InterlockedIncrement(&This
->ref
);
623 TRACE("(%p) refcount=%u\n", iface
, ref
);
628 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
630 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
631 ULONG ref
= InterlockedDecrement(&This
->ref
);
633 TRACE("(%p) refcount=%u\n", iface
, ref
);
637 if (This
->tiff
) pTIFFClose(This
->tiff
);
638 if (This
->stream
) IStream_Release(This
->stream
);
639 This
->lock
.DebugInfo
->Spare
[0] = 0;
640 DeleteCriticalSection(&This
->lock
);
641 HeapFree(GetProcessHeap(), 0, This
);
647 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
652 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
654 if (!stream
|| !capability
) return E_INVALIDARG
;
656 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
657 if (hr
!= S_OK
) return hr
;
659 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
660 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
661 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
665 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
666 WICDecodeOptions cacheOptions
)
668 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
670 tiff_decode_info decode_info
;
673 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
675 EnterCriticalSection(&This
->lock
);
677 if (This
->initialized
)
679 hr
= WINCODEC_ERR_WRONGSTATE
;
683 tiff
= tiff_open_stream(pIStream
, "r");
690 /* make sure that TIFF format is supported */
691 hr
= tiff_get_decode_info(tiff
, &decode_info
);
699 This
->stream
= pIStream
;
700 IStream_AddRef(pIStream
);
701 This
->initialized
= TRUE
;
704 LeaveCriticalSection(&This
->lock
);
708 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
709 GUID
*pguidContainerFormat
)
711 if (!pguidContainerFormat
) return E_INVALIDARG
;
713 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
717 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
718 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
721 IWICComponentInfo
*compinfo
;
723 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
725 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
726 if (FAILED(hr
)) return hr
;
728 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
729 (void**)ppIDecoderInfo
);
731 IWICComponentInfo_Release(compinfo
);
736 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
737 IWICPalette
*palette
)
739 TRACE("(%p,%p)\n", iface
, palette
);
740 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
743 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
744 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
746 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
748 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
750 *ppIMetadataQueryReader
= NULL
;
751 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
754 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
755 IWICBitmapSource
**ppIBitmapSource
)
757 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
759 if (!ppIBitmapSource
) return E_INVALIDARG
;
761 *ppIBitmapSource
= NULL
;
762 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
765 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
766 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
768 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
769 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
772 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
773 IWICBitmapSource
**ppIThumbnail
)
775 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
777 if (!ppIThumbnail
) return E_INVALIDARG
;
779 *ppIThumbnail
= NULL
;
780 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
783 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
786 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
788 if (!pCount
) return E_INVALIDARG
;
790 EnterCriticalSection(&This
->lock
);
791 *pCount
= This
->tiff
? pTIFFNumberOfDirectories(This
->tiff
) : 0;
792 LeaveCriticalSection(&This
->lock
);
794 TRACE("(%p) <-- %i\n", iface
, *pCount
);
799 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
800 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
802 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
803 TiffFrameDecode
*result
;
805 tiff_decode_info decode_info
;
808 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
811 return WINCODEC_ERR_FRAMEMISSING
;
813 EnterCriticalSection(&This
->lock
);
814 res
= pTIFFSetDirectory(This
->tiff
, index
);
815 if (!res
) hr
= E_INVALIDARG
;
816 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
817 LeaveCriticalSection(&This
->lock
);
821 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
825 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
826 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
828 result
->parent
= This
;
829 result
->index
= index
;
830 result
->decode_info
= decode_info
;
831 result
->cached_tile_x
= -1;
832 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
834 if (result
->cached_tile
)
835 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
839 HeapFree(GetProcessHeap(), 0, result
);
842 else hr
= E_OUTOFMEMORY
;
845 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
850 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
851 TiffDecoder_QueryInterface
,
854 TiffDecoder_QueryCapability
,
855 TiffDecoder_Initialize
,
856 TiffDecoder_GetContainerFormat
,
857 TiffDecoder_GetDecoderInfo
,
858 TiffDecoder_CopyPalette
,
859 TiffDecoder_GetMetadataQueryReader
,
860 TiffDecoder_GetPreview
,
861 TiffDecoder_GetColorContexts
,
862 TiffDecoder_GetThumbnail
,
863 TiffDecoder_GetFrameCount
,
867 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
870 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
871 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
873 if (!ppv
) return E_INVALIDARG
;
875 if (IsEqualIID(&IID_IUnknown
, iid
) ||
876 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
877 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
879 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
881 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
883 *ppv
= &This
->IWICMetadataBlockReader_iface
;
888 return E_NOINTERFACE
;
891 IUnknown_AddRef((IUnknown
*)*ppv
);
895 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
897 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
898 ULONG ref
= InterlockedIncrement(&This
->ref
);
900 TRACE("(%p) refcount=%u\n", iface
, ref
);
905 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
907 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
908 ULONG ref
= InterlockedDecrement(&This
->ref
);
910 TRACE("(%p) refcount=%u\n", iface
, ref
);
914 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
915 HeapFree(GetProcessHeap(), 0, This
);
921 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
922 UINT
*puiWidth
, UINT
*puiHeight
)
924 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
926 *puiWidth
= This
->decode_info
.width
;
927 *puiHeight
= This
->decode_info
.height
;
929 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
934 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
935 WICPixelFormatGUID
*pPixelFormat
)
937 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
939 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
941 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
946 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
947 double *pDpiX
, double *pDpiY
)
949 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
951 switch (This
->decode_info
.resolution_unit
)
954 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
956 case 0: /* Not set */
957 *pDpiX
= *pDpiY
= 96.0;
959 case 1: /* Relative measurements */
961 *pDpiY
= 96.0 * This
->decode_info
.yres
/ This
->decode_info
.xres
;
964 *pDpiX
= This
->decode_info
.xres
;
965 *pDpiY
= This
->decode_info
.yres
;
967 case 3: /* Centimeter */
968 *pDpiX
= This
->decode_info
.xres
/ 2.54;
969 *pDpiY
= This
->decode_info
.yres
/ 2.54;
973 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
978 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
979 IWICPalette
*pIPalette
)
981 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
982 uint16
*red
, *green
, *blue
;
983 WICColor colors
[256];
984 int color_count
, ret
, i
;
986 TRACE("(%p,%p)\n", iface
, pIPalette
);
988 color_count
= 1<<This
->decode_info
.bps
;
990 EnterCriticalSection(&This
->parent
->lock
);
991 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
992 LeaveCriticalSection(&This
->parent
->lock
);
996 WARN("Couldn't read color map\n");
997 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1000 for (i
=0; i
<color_count
; i
++)
1002 colors
[i
] = 0xff000000 |
1003 ((red
[i
]<<8) & 0xff0000) |
1004 (green
[i
] & 0xff00) |
1005 ((blue
[i
]>>8) & 0xff);
1008 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
1011 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
1016 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1018 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
1022 if (This
->decode_info
.tiled
)
1023 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
1025 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
1031 if (This
->decode_info
.source_bpp
== 3 && This
->decode_info
.samples
== 3 && This
->decode_info
.bpp
== 24)
1033 BYTE
*srcdata
, *src
, *dst
;
1034 DWORD x
, y
, count
, width_bytes
= (This
->decode_info
.tile_width
* 3 + 7) / 8;
1036 count
= width_bytes
* This
->decode_info
.tile_height
;
1038 srcdata
= HeapAlloc(GetProcessHeap(), 0, count
);
1039 if (!srcdata
) return E_OUTOFMEMORY
;
1040 memcpy(srcdata
, This
->cached_tile
, count
);
1042 for (y
= 0; y
< This
->decode_info
.tile_height
; y
++)
1044 src
= srcdata
+ y
* width_bytes
;
1045 dst
= This
->cached_tile
+ y
* This
->decode_info
.tile_width
* 3;
1047 for (x
= 0; x
< This
->decode_info
.tile_width
; x
+= 8)
1049 dst
[2] = (src
[0] & 0x80) ? 0xff : 0; /* R */
1050 dst
[1] = (src
[0] & 0x40) ? 0xff : 0; /* G */
1051 dst
[0] = (src
[0] & 0x20) ? 0xff : 0; /* B */
1052 if (x
+ 1 < This
->decode_info
.tile_width
)
1054 dst
[5] = (src
[0] & 0x10) ? 0xff : 0; /* R */
1055 dst
[4] = (src
[0] & 0x08) ? 0xff : 0; /* G */
1056 dst
[3] = (src
[0] & 0x04) ? 0xff : 0; /* B */
1058 if (x
+ 2 < This
->decode_info
.tile_width
)
1060 dst
[8] = (src
[0] & 0x02) ? 0xff : 0; /* R */
1061 dst
[7] = (src
[0] & 0x01) ? 0xff : 0; /* G */
1062 dst
[6] = (src
[1] & 0x80) ? 0xff : 0; /* B */
1064 if (x
+ 3 < This
->decode_info
.tile_width
)
1066 dst
[11] = (src
[1] & 0x40) ? 0xff : 0; /* R */
1067 dst
[10] = (src
[1] & 0x20) ? 0xff : 0; /* G */
1068 dst
[9] = (src
[1] & 0x10) ? 0xff : 0; /* B */
1070 if (x
+ 4 < This
->decode_info
.tile_width
)
1072 dst
[14] = (src
[1] & 0x08) ? 0xff : 0; /* R */
1073 dst
[13] = (src
[1] & 0x04) ? 0xff : 0; /* G */
1074 dst
[12] = (src
[1] & 0x02) ? 0xff : 0; /* B */
1076 if (x
+ 5 < This
->decode_info
.tile_width
)
1078 dst
[17] = (src
[1] & 0x01) ? 0xff : 0; /* R */
1079 dst
[16] = (src
[2] & 0x80) ? 0xff : 0; /* G */
1080 dst
[15] = (src
[2] & 0x40) ? 0xff : 0; /* B */
1082 if (x
+ 6 < This
->decode_info
.tile_width
)
1084 dst
[20] = (src
[2] & 0x20) ? 0xff : 0; /* R */
1085 dst
[19] = (src
[2] & 0x10) ? 0xff : 0; /* G */
1086 dst
[18] = (src
[2] & 0x08) ? 0xff : 0; /* B */
1088 if (x
+ 7 < This
->decode_info
.tile_width
)
1090 dst
[23] = (src
[2] & 0x04) ? 0xff : 0; /* R */
1091 dst
[22] = (src
[2] & 0x02) ? 0xff : 0; /* G */
1092 dst
[21] = (src
[2] & 0x01) ? 0xff : 0; /* B */
1099 HeapFree(GetProcessHeap(), 0, srcdata
);
1102 else if (This
->decode_info
.source_bpp
== 12 && This
->decode_info
.samples
== 3 && This
->decode_info
.bpp
== 24)
1104 BYTE
*srcdata
, *src
, *dst
;
1105 DWORD x
, y
, count
, width_bytes
= (This
->decode_info
.tile_width
* 12 + 7) / 8;
1107 count
= width_bytes
* This
->decode_info
.tile_height
;
1109 srcdata
= HeapAlloc(GetProcessHeap(), 0, count
);
1110 if (!srcdata
) return E_OUTOFMEMORY
;
1111 memcpy(srcdata
, This
->cached_tile
, count
);
1113 for (y
= 0; y
< This
->decode_info
.tile_height
; y
++)
1115 src
= srcdata
+ y
* width_bytes
;
1116 dst
= This
->cached_tile
+ y
* This
->decode_info
.tile_width
* 3;
1118 for (x
= 0; x
< This
->decode_info
.tile_width
; x
+= 2)
1120 dst
[0] = ((src
[1] & 0xf0) >> 4) * 17; /* B */
1121 dst
[1] = (src
[0] & 0x0f) * 17; /* G */
1122 dst
[2] = ((src
[0] & 0xf0) >> 4) * 17; /* R */
1123 if (x
+ 1 < This
->decode_info
.tile_width
)
1125 dst
[5] = (src
[1] & 0x0f) * 17; /* B */
1126 dst
[4] = ((src
[2] & 0xf0) >> 4) * 17; /* G */
1127 dst
[3] = (src
[2] & 0x0f) * 17; /* R */
1134 HeapFree(GetProcessHeap(), 0, srcdata
);
1137 else if (This
->decode_info
.source_bpp
== 4 && This
->decode_info
.samples
== 4 && This
->decode_info
.bpp
== 32)
1142 /* 1 source byte expands to 2 BGRA samples */
1143 count
= (This
->decode_info
.tile_width
* This
->decode_info
.tile_height
+ 1) / 2;
1145 src
= This
->cached_tile
+ count
- 1;
1146 dst
= This
->cached_tile
+ This
->decode_info
.tile_size
;
1153 dst
[2] = (b
& 0x80) ? 0xff : 0; /* R */
1154 dst
[1] = (b
& 0x40) ? 0xff : 0; /* G */
1155 dst
[0] = (b
& 0x20) ? 0xff : 0; /* B */
1156 dst
[3] = (b
& 0x10) ? 0xff : 0; /* A */
1157 dst
[6] = (b
& 0x08) ? 0xff : 0; /* R */
1158 dst
[5] = (b
& 0x04) ? 0xff : 0; /* G */
1159 dst
[4] = (b
& 0x02) ? 0xff : 0; /* B */
1160 dst
[7] = (b
& 0x01) ? 0xff : 0; /* A */
1164 else if (This
->decode_info
.source_bpp
== 16 && This
->decode_info
.samples
== 4 && This
->decode_info
.bpp
== 32)
1167 DWORD count
= This
->decode_info
.tile_width
* This
->decode_info
.tile_height
;
1169 src
= This
->cached_tile
+ count
* 2;
1170 dst
= This
->cached_tile
+ This
->decode_info
.tile_size
;
1182 dst
[0] = ((b
[1] & 0xf0) >> 4) * 17; /* B */
1183 dst
[1] = (b
[0] & 0x0f) * 17; /* G */
1184 dst
[2] = ((b
[0] & 0xf0) >> 4) * 17; /* R */
1185 dst
[3] = (b
[1] & 0x0f) * 17; /* A */
1188 /* 8bpp grayscale with extra alpha */
1189 else if (This
->decode_info
.source_bpp
== 16 && This
->decode_info
.samples
== 2 && This
->decode_info
.bpp
== 32)
1192 DWORD
*dst
, count
= This
->decode_info
.tile_width
* This
->decode_info
.tile_height
;
1194 src
= This
->cached_tile
+ This
->decode_info
.tile_width
* This
->decode_info
.tile_height
* 2 - 2;
1195 dst
= (DWORD
*)(This
->cached_tile
+ This
->decode_info
.tile_size
- 4);
1199 *dst
-- = src
[0] | (src
[0] << 8) | (src
[0] << 16) | (src
[1] << 24);
1204 if (This
->decode_info
.reverse_bgr
)
1206 if (This
->decode_info
.bps
== 8)
1208 UINT sample_count
= This
->decode_info
.samples
;
1210 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
1211 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
1215 if (swap_bytes
&& This
->decode_info
.bps
> 8)
1217 UINT row
, i
, samples_per_row
;
1220 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
1222 switch(This
->decode_info
.bps
)
1225 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
1227 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
1228 for (i
=0; i
<samples_per_row
; i
++)
1231 sample
[1] = sample
[0];
1238 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
1243 if (This
->decode_info
.invert_grayscale
)
1247 if (This
->decode_info
.samples
!= 1)
1249 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
1253 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
1255 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
1259 This
->cached_tile_x
= tile_x
;
1260 This
->cached_tile_y
= tile_y
;
1265 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
1266 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
1268 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1269 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
1270 UINT tile_x
, tile_y
;
1277 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1283 rect
.Width
= This
->decode_info
.width
;
1284 rect
.Height
= This
->decode_info
.height
;
1289 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
1290 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1291 return E_INVALIDARG
;
1294 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1296 if (cbStride
< bytesperrow
)
1297 return E_INVALIDARG
;
1299 if ((cbStride
* (prc
->Height
-1)) + ((prc
->Width
* This
->decode_info
.bpp
) + 7)/8 > cbBufferSize
)
1300 return E_INVALIDARG
;
1302 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1303 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1304 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1305 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1307 EnterCriticalSection(&This
->parent
->lock
);
1309 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1311 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1313 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1315 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1320 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1323 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1325 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1328 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1330 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1331 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1332 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1333 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1335 rc
.Width
= prc
->Width
;
1337 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1338 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1339 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1340 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1342 rc
.Height
= prc
->Height
;
1344 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1345 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1347 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1348 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1349 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1354 LeaveCriticalSection(&This
->parent
->lock
);
1355 TRACE("<-- 0x%x\n", hr
);
1361 LeaveCriticalSection(&This
->parent
->lock
);
1366 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1367 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1369 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1371 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1373 if (!ppIMetadataQueryReader
)
1374 return E_INVALIDARG
;
1376 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
1379 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1380 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1382 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1383 const BYTE
*profile
;
1387 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1389 EnterCriticalSection(&This
->parent
->lock
);
1391 if (pTIFFGetField(This
->parent
->tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
1393 if (cCount
&& ppIColorContexts
)
1395 hr
= IWICColorContext_InitializeFromMemory(*ppIColorContexts
, profile
, len
);
1398 LeaveCriticalSection(&This
->parent
->lock
);
1407 LeaveCriticalSection(&This
->parent
->lock
);
1412 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1413 IWICBitmapSource
**ppIThumbnail
)
1415 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1417 if (!ppIThumbnail
) return E_INVALIDARG
;
1419 *ppIThumbnail
= NULL
;
1420 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1423 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1424 TiffFrameDecode_QueryInterface
,
1425 TiffFrameDecode_AddRef
,
1426 TiffFrameDecode_Release
,
1427 TiffFrameDecode_GetSize
,
1428 TiffFrameDecode_GetPixelFormat
,
1429 TiffFrameDecode_GetResolution
,
1430 TiffFrameDecode_CopyPalette
,
1431 TiffFrameDecode_CopyPixels
,
1432 TiffFrameDecode_GetMetadataQueryReader
,
1433 TiffFrameDecode_GetColorContexts
,
1434 TiffFrameDecode_GetThumbnail
1437 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1438 REFIID iid
, void **ppv
)
1440 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1441 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1444 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1446 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1447 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1450 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1452 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1453 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1456 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1459 TRACE("(%p,%p)\n", iface
, guid
);
1461 if (!guid
) return E_INVALIDARG
;
1463 *guid
= GUID_ContainerFormatTiff
;
1467 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1470 TRACE("%p,%p\n", iface
, count
);
1472 if (!count
) return E_INVALIDARG
;
1478 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1481 LARGE_INTEGER dir_offset
;
1482 IWICMetadataReader
*metadata_reader
;
1483 IWICPersistStream
*persist
;
1485 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1487 hr
= IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
1488 if (FAILED(hr
)) return hr
;
1490 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1493 IWICMetadataReader_Release(metadata_reader
);
1497 EnterCriticalSection(&This
->parent
->lock
);
1499 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1500 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1503 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1504 #ifdef WORDS_BIGENDIAN
1505 DWORD persist_options
= byte_swapped
? WICPersistOptionLittleEndian
: WICPersistOptionBigEndian
;
1507 DWORD persist_options
= byte_swapped
? WICPersistOptionBigEndian
: WICPersistOptionLittleEndian
;
1509 persist_options
|= WICPersistOptionNoCacheStream
;
1510 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1512 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1515 LeaveCriticalSection(&This
->parent
->lock
);
1517 IWICPersistStream_Release(persist
);
1521 IWICMetadataReader_Release(metadata_reader
);
1525 *reader
= metadata_reader
;
1529 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1530 UINT index
, IWICMetadataReader
**reader
)
1532 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1534 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1536 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1538 return create_metadata_reader(This
, reader
);
1541 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1542 IEnumUnknown
**enum_metadata
)
1544 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1548 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1550 TiffFrameDecode_Block_QueryInterface
,
1551 TiffFrameDecode_Block_AddRef
,
1552 TiffFrameDecode_Block_Release
,
1553 TiffFrameDecode_Block_GetContainerFormat
,
1554 TiffFrameDecode_Block_GetCount
,
1555 TiffFrameDecode_Block_GetReaderByIndex
,
1556 TiffFrameDecode_Block_GetEnumerator
1559 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
1564 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1568 if (!load_libtiff())
1570 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1574 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1575 if (!This
) return E_OUTOFMEMORY
;
1577 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1579 This
->stream
= NULL
;
1580 InitializeCriticalSection(&This
->lock
);
1581 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1583 This
->initialized
= FALSE
;
1585 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1586 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1591 struct tiff_encode_format
{
1592 const WICPixelFormatGUID
*guid
;
1598 int extra_sample_type
;
1602 static const struct tiff_encode_format formats
[] = {
1603 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1604 {&GUID_WICPixelFormat24bppRGB
, 2, 8, 3, 24, 0, 0, 0},
1605 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1606 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1607 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1608 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1609 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1610 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1611 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1612 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1613 {&GUID_WICPixelFormat1bppIndexed
, 3, 1, 1, 1, 0, 0, 0},
1614 {&GUID_WICPixelFormat2bppIndexed
, 3, 2, 1, 2, 0, 0, 0},
1615 {&GUID_WICPixelFormat4bppIndexed
, 3, 4, 1, 4, 0, 0, 0},
1616 {&GUID_WICPixelFormat8bppIndexed
, 3, 8, 1, 8, 0, 0, 0},
1620 typedef struct TiffEncoder
{
1621 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1624 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1629 ULONG num_frames_committed
;
1632 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1634 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1637 typedef struct TiffFrameEncode
{
1638 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1640 TiffEncoder
*parent
;
1641 /* fields below are protected by parent->lock */
1645 const struct tiff_encode_format
*format
;
1649 WICColor palette
[256];
1653 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1655 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1658 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1661 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1662 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1664 if (!ppv
) return E_INVALIDARG
;
1666 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1667 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1669 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1674 return E_NOINTERFACE
;
1677 IUnknown_AddRef((IUnknown
*)*ppv
);
1681 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1683 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1684 ULONG ref
= InterlockedIncrement(&This
->ref
);
1686 TRACE("(%p) refcount=%u\n", iface
, ref
);
1691 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1693 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1694 ULONG ref
= InterlockedDecrement(&This
->ref
);
1696 TRACE("(%p) refcount=%u\n", iface
, ref
);
1700 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1701 HeapFree(GetProcessHeap(), 0, This
);
1707 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1708 IPropertyBag2
*pIEncoderOptions
)
1710 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1711 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1713 EnterCriticalSection(&This
->parent
->lock
);
1715 if (This
->initialized
)
1717 LeaveCriticalSection(&This
->parent
->lock
);
1718 return WINCODEC_ERR_WRONGSTATE
;
1721 This
->initialized
= TRUE
;
1723 LeaveCriticalSection(&This
->parent
->lock
);
1728 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1729 UINT uiWidth
, UINT uiHeight
)
1731 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1732 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1734 EnterCriticalSection(&This
->parent
->lock
);
1736 if (!This
->initialized
|| This
->info_written
)
1738 LeaveCriticalSection(&This
->parent
->lock
);
1739 return WINCODEC_ERR_WRONGSTATE
;
1742 This
->width
= uiWidth
;
1743 This
->height
= uiHeight
;
1745 LeaveCriticalSection(&This
->parent
->lock
);
1750 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1751 double dpiX
, double dpiY
)
1753 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1754 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1756 EnterCriticalSection(&This
->parent
->lock
);
1758 if (!This
->initialized
|| This
->info_written
)
1760 LeaveCriticalSection(&This
->parent
->lock
);
1761 return WINCODEC_ERR_WRONGSTATE
;
1767 LeaveCriticalSection(&This
->parent
->lock
);
1772 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1773 WICPixelFormatGUID
*pPixelFormat
)
1775 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1778 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1780 EnterCriticalSection(&This
->parent
->lock
);
1782 if (!This
->initialized
|| This
->info_written
)
1784 LeaveCriticalSection(&This
->parent
->lock
);
1785 return WINCODEC_ERR_WRONGSTATE
;
1788 for (i
=0; formats
[i
].guid
; i
++)
1790 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1794 if (!formats
[i
].guid
) i
= 0;
1796 This
->format
= &formats
[i
];
1797 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1799 LeaveCriticalSection(&This
->parent
->lock
);
1804 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1805 UINT cCount
, IWICColorContext
**ppIColorContext
)
1807 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1811 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1812 IWICPalette
*palette
)
1814 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1817 TRACE("(%p,%p)\n", iface
, palette
);
1819 if (!palette
) return E_INVALIDARG
;
1821 EnterCriticalSection(&This
->parent
->lock
);
1823 if (This
->initialized
)
1824 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
1826 hr
= WINCODEC_ERR_NOTINITIALIZED
;
1828 LeaveCriticalSection(&This
->parent
->lock
);
1832 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1833 IWICBitmapSource
*pIThumbnail
)
1835 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1836 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1839 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1840 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1842 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1843 BYTE
*row_data
, *swapped_data
= NULL
;
1844 UINT i
, j
, line_size
;
1846 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1848 EnterCriticalSection(&This
->parent
->lock
);
1850 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1852 LeaveCriticalSection(&This
->parent
->lock
);
1853 return WINCODEC_ERR_WRONGSTATE
;
1856 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1858 LeaveCriticalSection(&This
->parent
->lock
);
1859 return E_INVALIDARG
;
1862 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1864 if (This
->format
->reverse_bgr
)
1866 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1869 LeaveCriticalSection(&This
->parent
->lock
);
1870 return E_OUTOFMEMORY
;
1874 if (!This
->info_written
)
1876 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1877 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1878 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1879 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1881 if (This
->format
->extra_sample
)
1883 uint16 extra_samples
;
1884 extra_samples
= This
->format
->extra_sample_type
;
1886 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1889 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1890 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1892 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1894 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1895 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1896 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1899 if (This
->format
->bpp
<= 8 && This
->colors
&& !IsEqualGUID(This
->format
->guid
, &GUID_WICPixelFormatBlackWhite
))
1901 uint16 red
[256], green
[256], blue
[256];
1904 for (i
= 0; i
< This
->colors
; i
++)
1906 red
[i
] = (This
->palette
[i
] >> 8) & 0xff00;
1907 green
[i
] = This
->palette
[i
] & 0xff00;
1908 blue
[i
] = (This
->palette
[i
] << 8) & 0xff00;
1911 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, red
, green
, blue
);
1914 This
->info_written
= TRUE
;
1917 for (i
=0; i
<lineCount
; i
++)
1919 row_data
= pbPixels
+ i
* cbStride
;
1921 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1923 memcpy(swapped_data
, row_data
, line_size
);
1924 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1927 temp
= swapped_data
[j
];
1928 swapped_data
[j
] = swapped_data
[j
+2];
1929 swapped_data
[j
+2] = temp
;
1931 row_data
= swapped_data
;
1934 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1937 This
->lines_written
+= lineCount
;
1939 LeaveCriticalSection(&This
->parent
->lock
);
1941 HeapFree(GetProcessHeap(), 0, swapped_data
);
1946 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1947 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1949 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1952 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1954 if (!This
->initialized
)
1955 return WINCODEC_ERR_WRONGSTATE
;
1957 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
1958 This
->format
? This
->format
->guid
: NULL
, This
->width
, This
->height
,
1959 This
->xres
, This
->yres
);
1963 hr
= write_source(iface
, pIBitmapSource
, prc
,
1964 This
->format
->guid
, This
->format
->bpp
, This
->width
, This
->height
);
1970 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1972 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1974 TRACE("(%p)\n", iface
);
1976 EnterCriticalSection(&This
->parent
->lock
);
1978 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1980 LeaveCriticalSection(&This
->parent
->lock
);
1981 return WINCODEC_ERR_WRONGSTATE
;
1984 /* libtiff will commit the data when creating a new frame or closing the file */
1986 This
->committed
= TRUE
;
1987 This
->parent
->num_frames_committed
++;
1989 LeaveCriticalSection(&This
->parent
->lock
);
1994 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1995 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1997 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
2001 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
2002 TiffFrameEncode_QueryInterface
,
2003 TiffFrameEncode_AddRef
,
2004 TiffFrameEncode_Release
,
2005 TiffFrameEncode_Initialize
,
2006 TiffFrameEncode_SetSize
,
2007 TiffFrameEncode_SetResolution
,
2008 TiffFrameEncode_SetPixelFormat
,
2009 TiffFrameEncode_SetColorContexts
,
2010 TiffFrameEncode_SetPalette
,
2011 TiffFrameEncode_SetThumbnail
,
2012 TiffFrameEncode_WritePixels
,
2013 TiffFrameEncode_WriteSource
,
2014 TiffFrameEncode_Commit
,
2015 TiffFrameEncode_GetMetadataQueryWriter
2018 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
2021 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2022 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
2024 if (!ppv
) return E_INVALIDARG
;
2026 if (IsEqualIID(&IID_IUnknown
, iid
) ||
2027 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
2029 *ppv
= &This
->IWICBitmapEncoder_iface
;
2034 return E_NOINTERFACE
;
2037 IUnknown_AddRef((IUnknown
*)*ppv
);
2041 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
2043 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2044 ULONG ref
= InterlockedIncrement(&This
->ref
);
2046 TRACE("(%p) refcount=%u\n", iface
, ref
);
2051 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
2053 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2054 ULONG ref
= InterlockedDecrement(&This
->ref
);
2056 TRACE("(%p) refcount=%u\n", iface
, ref
);
2060 if (This
->tiff
) pTIFFClose(This
->tiff
);
2061 if (This
->stream
) IStream_Release(This
->stream
);
2062 This
->lock
.DebugInfo
->Spare
[0] = 0;
2063 DeleteCriticalSection(&This
->lock
);
2064 HeapFree(GetProcessHeap(), 0, This
);
2070 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
2071 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
2073 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2077 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
2079 EnterCriticalSection(&This
->lock
);
2081 if (This
->initialized
|| This
->committed
)
2083 hr
= WINCODEC_ERR_WRONGSTATE
;
2087 tiff
= tiff_open_stream(pIStream
, "w");
2096 This
->stream
= pIStream
;
2097 IStream_AddRef(pIStream
);
2098 This
->initialized
= TRUE
;
2101 LeaveCriticalSection(&This
->lock
);
2105 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
2106 GUID
*pguidContainerFormat
)
2108 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
2112 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
, IWICBitmapEncoderInfo
**info
)
2114 IWICComponentInfo
*comp_info
;
2117 TRACE("%p,%p\n", iface
, info
);
2119 if (!info
) return E_INVALIDARG
;
2121 hr
= CreateComponentInfo(&CLSID_WICTiffEncoder
, &comp_info
);
2124 hr
= IWICComponentInfo_QueryInterface(comp_info
, &IID_IWICBitmapEncoderInfo
, (void **)info
);
2125 IWICComponentInfo_Release(comp_info
);
2130 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
2131 UINT cCount
, IWICColorContext
**ppIColorContext
)
2133 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
2137 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
2139 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2142 TRACE("(%p,%p)\n", iface
, palette
);
2144 EnterCriticalSection(&This
->lock
);
2146 hr
= This
->stream
? WINCODEC_ERR_UNSUPPORTEDOPERATION
: WINCODEC_ERR_NOTINITIALIZED
;
2148 LeaveCriticalSection(&This
->lock
);
2153 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
2155 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
2156 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2159 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
2161 TRACE("(%p,%p)\n", iface
, pIPreview
);
2162 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2165 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
2166 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
2168 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2169 TiffFrameEncode
*result
;
2173 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
2175 EnterCriticalSection(&This
->lock
);
2177 if (!This
->initialized
|| This
->committed
)
2179 hr
= WINCODEC_ERR_WRONGSTATE
;
2181 else if (This
->num_frames
!= This
->num_frames_committed
)
2183 FIXME("New frame created before previous frame was committed\n");
2187 if (SUCCEEDED(hr
) && ppIEncoderOptions
)
2189 PROPBAG2 opts
[2]= {{0}};
2190 opts
[0].pstrName
= (LPOLESTR
)wszTiffCompressionMethod
;
2191 opts
[0].vt
= VT_UI1
;
2192 opts
[0].dwType
= PROPBAG2_TYPE_DATA
;
2194 opts
[1].pstrName
= (LPOLESTR
)wszCompressionQuality
;
2196 opts
[1].dwType
= PROPBAG2_TYPE_DATA
;
2198 hr
= CreatePropertyBag2(opts
, 2, ppIEncoderOptions
);
2205 V_UI1(&v
) = WICTiffCompressionDontCare
;
2206 hr
= IPropertyBag2_Write(*ppIEncoderOptions
, 1, opts
, &v
);
2210 IPropertyBag2_Release(*ppIEncoderOptions
);
2211 *ppIEncoderOptions
= NULL
;
2218 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
2222 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
2224 result
->parent
= This
;
2225 result
->initialized
= FALSE
;
2226 result
->info_written
= FALSE
;
2227 result
->committed
= FALSE
;
2228 result
->format
= NULL
;
2233 result
->lines_written
= 0;
2236 IWICBitmapEncoder_AddRef(iface
);
2237 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
2239 if (This
->num_frames
!= 0)
2240 pTIFFWriteDirectory(This
->tiff
);
2247 if (FAILED(hr
) && ppIEncoderOptions
)
2249 IPropertyBag2_Release(*ppIEncoderOptions
);
2250 *ppIEncoderOptions
= NULL
;
2254 LeaveCriticalSection(&This
->lock
);
2259 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
2261 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2263 TRACE("(%p)\n", iface
);
2265 EnterCriticalSection(&This
->lock
);
2267 if (!This
->initialized
|| This
->committed
)
2269 LeaveCriticalSection(&This
->lock
);
2270 return WINCODEC_ERR_WRONGSTATE
;
2273 pTIFFClose(This
->tiff
);
2274 IStream_Release(This
->stream
);
2275 This
->stream
= NULL
;
2278 This
->committed
= TRUE
;
2280 LeaveCriticalSection(&This
->lock
);
2285 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
2286 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
2288 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
2292 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
2293 TiffEncoder_QueryInterface
,
2295 TiffEncoder_Release
,
2296 TiffEncoder_Initialize
,
2297 TiffEncoder_GetContainerFormat
,
2298 TiffEncoder_GetEncoderInfo
,
2299 TiffEncoder_SetColorContexts
,
2300 TiffEncoder_SetPalette
,
2301 TiffEncoder_SetThumbnail
,
2302 TiffEncoder_SetPreview
,
2303 TiffEncoder_CreateNewFrame
,
2305 TiffEncoder_GetMetadataQueryWriter
2308 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2313 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
2317 if (!load_libtiff())
2319 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
2323 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
2324 if (!This
) return E_OUTOFMEMORY
;
2326 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
2328 This
->stream
= NULL
;
2329 InitializeCriticalSection(&This
->lock
);
2330 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
2332 This
->initialized
= FALSE
;
2333 This
->num_frames
= 0;
2334 This
->num_frames_committed
= 0;
2335 This
->committed
= FALSE
;
2337 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2338 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
2343 #else /* !SONAME_LIBTIFF */
2345 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
2347 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
2351 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2353 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");