2 * Copyright 2010 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
36 #include "wincodecsdk.h"
38 #include "wincodecs_private.h"
40 #include "wine/debug.h"
41 #include "wine/library.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
47 /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which
48 * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they
49 * are supposed to be always 64-bit.
50 * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x.
54 # define toff_t UINT64
57 static CRITICAL_SECTION init_tiff_cs
;
58 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
61 { &init_tiff_cs_debug
.ProcessLocksList
,
62 &init_tiff_cs_debug
.ProcessLocksList
},
63 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
65 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
67 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};
68 static const WCHAR wszCompressionQuality
[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
70 static void *libtiff_handle
;
71 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
72 MAKE_FUNCPTR(TIFFClientOpen
);
73 MAKE_FUNCPTR(TIFFClose
);
74 MAKE_FUNCPTR(TIFFCurrentDirOffset
);
75 MAKE_FUNCPTR(TIFFGetField
);
76 MAKE_FUNCPTR(TIFFIsByteSwapped
);
77 MAKE_FUNCPTR(TIFFNumberOfDirectories
);
78 MAKE_FUNCPTR(TIFFReadDirectory
);
79 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
80 MAKE_FUNCPTR(TIFFReadEncodedTile
);
81 MAKE_FUNCPTR(TIFFSetDirectory
);
82 MAKE_FUNCPTR(TIFFSetField
);
83 MAKE_FUNCPTR(TIFFWriteDirectory
);
84 MAKE_FUNCPTR(TIFFWriteScanline
);
87 static void *load_libtiff(void)
91 EnterCriticalSection(&init_tiff_cs
);
93 if (!libtiff_handle
&&
94 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
96 void * (*pTIFFSetWarningHandler
)(void *);
97 void * (*pTIFFSetWarningHandlerExt
)(void *);
99 #define LOAD_FUNCPTR(f) \
100 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
101 ERR("failed to load symbol %s\n", #f); \
102 libtiff_handle = NULL; \
103 LeaveCriticalSection(&init_tiff_cs); \
106 LOAD_FUNCPTR(TIFFClientOpen
);
107 LOAD_FUNCPTR(TIFFClose
);
108 LOAD_FUNCPTR(TIFFCurrentDirOffset
);
109 LOAD_FUNCPTR(TIFFGetField
);
110 LOAD_FUNCPTR(TIFFIsByteSwapped
);
111 LOAD_FUNCPTR(TIFFNumberOfDirectories
);
112 LOAD_FUNCPTR(TIFFReadDirectory
);
113 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
114 LOAD_FUNCPTR(TIFFReadEncodedTile
);
115 LOAD_FUNCPTR(TIFFSetDirectory
);
116 LOAD_FUNCPTR(TIFFSetField
);
117 LOAD_FUNCPTR(TIFFWriteDirectory
);
118 LOAD_FUNCPTR(TIFFWriteScanline
);
121 if ((pTIFFSetWarningHandler
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandler", NULL
, 0)))
122 pTIFFSetWarningHandler(NULL
);
123 if ((pTIFFSetWarningHandlerExt
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandlerExt", NULL
, 0)))
124 pTIFFSetWarningHandlerExt(NULL
);
127 result
= libtiff_handle
;
129 LeaveCriticalSection(&init_tiff_cs
);
133 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
135 IStream
*stream
= (IStream
*)client_data
;
139 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
140 if (FAILED(hr
)) bytes_read
= 0;
144 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
146 IStream
*stream
= (IStream
*)client_data
;
150 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
151 if (FAILED(hr
)) bytes_written
= 0;
152 return bytes_written
;
155 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
157 IStream
*stream
= (IStream
*)client_data
;
160 ULARGE_INTEGER new_position
;
163 move
.QuadPart
= offset
;
167 origin
= STREAM_SEEK_SET
;
170 origin
= STREAM_SEEK_CUR
;
173 origin
= STREAM_SEEK_END
;
176 ERR("unknown whence value %i\n", whence
);
180 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
181 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
185 static int tiff_stream_close(thandle_t client_data
)
187 /* Caller is responsible for releasing the stream object. */
191 static toff_t
tiff_stream_size(thandle_t client_data
)
193 IStream
*stream
= (IStream
*)client_data
;
197 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
199 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
203 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
205 /* Cannot mmap streams */
209 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
211 /* No need to ever do this, since we can't map things. */
214 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
219 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
221 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
222 tiff_stream_write
, (void *)tiff_stream_seek
, tiff_stream_close
,
223 (void *)tiff_stream_size
, (void *)tiff_stream_map
, (void *)tiff_stream_unmap
);
227 IWICBitmapDecoder IWICBitmapDecoder_iface
;
230 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initiailzed is set */
236 const WICPixelFormatGUID
*format
;
243 int invert_grayscale
;
245 UINT tile_width
, tile_height
;
250 UINT resolution_unit
;
255 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
256 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
260 tiff_decode_info decode_info
;
261 INT cached_tile_x
, cached_tile_y
;
265 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
266 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
268 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
270 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
273 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
275 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
278 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
280 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
283 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
285 uint16 photometric
, bps
, samples
, planar
;
286 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
289 decode_info
->indexed
= 0;
290 decode_info
->reverse_bgr
= 0;
291 decode_info
->invert_grayscale
= 0;
292 decode_info
->tiled
= 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
;
325 case 0: /* WhiteIsZero */
326 decode_info
->invert_grayscale
= 1;
328 case 1: /* BlackIsZero */
331 FIXME("unhandled grayscale sample count %u\n", samples
);
335 decode_info
->bpp
= bps
;
339 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
342 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
345 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
348 FIXME("unhandled greyscale bit count %u\n", bps
);
353 decode_info
->bpp
= bps
* samples
;
357 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
360 extra_sample_count
= 1;
362 extra_samples
= &extra_sample
;
365 else if (samples
!= 3)
367 FIXME("unhandled RGB sample count %u\n", samples
);
374 decode_info
->reverse_bgr
= 1;
376 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
378 switch(extra_samples
[0])
380 case 1: /* Associated (pre-multiplied) alpha data */
381 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
383 case 0: /* Unspecified data */
384 case 2: /* Unassociated alpha data */
385 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
388 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
394 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
396 switch(extra_samples
[0])
398 case 1: /* Associated (pre-multiplied) alpha data */
399 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
401 case 0: /* Unspecified data */
402 case 2: /* Unassociated alpha data */
403 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
406 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
411 FIXME("unhandled RGB bit count %u\n", bps
);
415 case 3: /* RGB Palette */
418 FIXME("unhandled indexed sample count %u\n", samples
);
422 decode_info
->indexed
= 1;
423 decode_info
->bpp
= bps
;
427 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
430 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
433 FIXME("unhandled indexed bit count %u\n", bps
);
437 case 4: /* Transparency mask */
442 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
446 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
449 WARN("missing image width\n");
453 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
456 WARN("missing image length\n");
460 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
462 decode_info
->tiled
= 1;
464 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
467 WARN("missing tile height\n");
471 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
472 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
473 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
475 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
477 if (decode_info
->tile_height
> decode_info
->height
)
478 decode_info
->tile_height
= decode_info
->height
;
479 decode_info
->tile_width
= decode_info
->width
;
480 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
481 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
485 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
486 decode_info
->tile_height
= decode_info
->height
;
487 decode_info
->tile_width
= decode_info
->width
;
488 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
489 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
492 decode_info
->resolution_unit
= 0;
493 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
494 if (decode_info
->resolution_unit
!= 0)
496 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
499 WARN("missing X resolution\n");
500 decode_info
->resolution_unit
= 0;
503 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
506 WARN("missing Y resolution\n");
507 decode_info
->resolution_unit
= 0;
514 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
517 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
518 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
520 if (!ppv
) return E_INVALIDARG
;
522 if (IsEqualIID(&IID_IUnknown
, iid
) ||
523 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
525 *ppv
= &This
->IWICBitmapDecoder_iface
;
530 return E_NOINTERFACE
;
533 IUnknown_AddRef((IUnknown
*)*ppv
);
537 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
539 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
540 ULONG ref
= InterlockedIncrement(&This
->ref
);
542 TRACE("(%p) refcount=%u\n", iface
, ref
);
547 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
549 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
550 ULONG ref
= InterlockedDecrement(&This
->ref
);
552 TRACE("(%p) refcount=%u\n", iface
, ref
);
556 if (This
->tiff
) pTIFFClose(This
->tiff
);
557 if (This
->stream
) IStream_Release(This
->stream
);
558 This
->lock
.DebugInfo
->Spare
[0] = 0;
559 DeleteCriticalSection(&This
->lock
);
560 HeapFree(GetProcessHeap(), 0, This
);
566 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
571 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
573 if (!stream
|| !capability
) return E_INVALIDARG
;
575 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
576 if (hr
!= S_OK
) return hr
;
578 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
579 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
580 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
584 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
585 WICDecodeOptions cacheOptions
)
587 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
591 TRACE("(%p,%p,%x): stub\n", iface
, pIStream
, cacheOptions
);
593 EnterCriticalSection(&This
->lock
);
595 if (This
->initialized
)
597 hr
= WINCODEC_ERR_WRONGSTATE
;
601 tiff
= tiff_open_stream(pIStream
, "r");
610 This
->stream
= pIStream
;
611 IStream_AddRef(pIStream
);
612 This
->initialized
= TRUE
;
615 LeaveCriticalSection(&This
->lock
);
619 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
620 GUID
*pguidContainerFormat
)
622 if (!pguidContainerFormat
) return E_INVALIDARG
;
624 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
628 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
629 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
632 IWICComponentInfo
*compinfo
;
634 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
636 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
637 if (FAILED(hr
)) return hr
;
639 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
640 (void**)ppIDecoderInfo
);
642 IWICComponentInfo_Release(compinfo
);
647 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
648 IWICPalette
*pIPalette
)
650 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
654 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
655 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
657 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
661 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
662 IWICBitmapSource
**ppIBitmapSource
)
664 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
666 if (!ppIBitmapSource
) return E_INVALIDARG
;
668 *ppIBitmapSource
= NULL
;
669 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
672 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
673 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
675 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
676 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
679 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
680 IWICBitmapSource
**ppIThumbnail
)
682 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
684 if (!ppIThumbnail
) return E_INVALIDARG
;
686 *ppIThumbnail
= NULL
;
687 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
690 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
693 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
695 if (!pCount
) return E_INVALIDARG
;
697 EnterCriticalSection(&This
->lock
);
698 *pCount
= This
->tiff
? pTIFFNumberOfDirectories(This
->tiff
) : 0;
699 LeaveCriticalSection(&This
->lock
);
701 TRACE("(%p) <-- %i\n", iface
, *pCount
);
706 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
707 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
709 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
710 TiffFrameDecode
*result
;
712 tiff_decode_info decode_info
;
715 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
718 return WINCODEC_ERR_FRAMEMISSING
;
720 EnterCriticalSection(&This
->lock
);
721 res
= pTIFFSetDirectory(This
->tiff
, index
);
722 if (!res
) hr
= E_INVALIDARG
;
723 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
724 LeaveCriticalSection(&This
->lock
);
728 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
732 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
733 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
735 result
->parent
= This
;
736 result
->index
= index
;
737 result
->decode_info
= decode_info
;
738 result
->cached_tile_x
= -1;
739 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
741 if (result
->cached_tile
)
742 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
746 HeapFree(GetProcessHeap(), 0, result
);
749 else hr
= E_OUTOFMEMORY
;
752 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
757 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
758 TiffDecoder_QueryInterface
,
761 TiffDecoder_QueryCapability
,
762 TiffDecoder_Initialize
,
763 TiffDecoder_GetContainerFormat
,
764 TiffDecoder_GetDecoderInfo
,
765 TiffDecoder_CopyPalette
,
766 TiffDecoder_GetMetadataQueryReader
,
767 TiffDecoder_GetPreview
,
768 TiffDecoder_GetColorContexts
,
769 TiffDecoder_GetThumbnail
,
770 TiffDecoder_GetFrameCount
,
774 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
777 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
778 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
780 if (!ppv
) return E_INVALIDARG
;
782 if (IsEqualIID(&IID_IUnknown
, iid
) ||
783 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
784 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
786 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
788 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
790 *ppv
= &This
->IWICMetadataBlockReader_iface
;
795 return E_NOINTERFACE
;
798 IUnknown_AddRef((IUnknown
*)*ppv
);
802 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
804 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
805 ULONG ref
= InterlockedIncrement(&This
->ref
);
807 TRACE("(%p) refcount=%u\n", iface
, ref
);
812 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
814 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
815 ULONG ref
= InterlockedDecrement(&This
->ref
);
817 TRACE("(%p) refcount=%u\n", iface
, ref
);
821 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
822 HeapFree(GetProcessHeap(), 0, This
);
828 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
829 UINT
*puiWidth
, UINT
*puiHeight
)
831 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
833 *puiWidth
= This
->decode_info
.width
;
834 *puiHeight
= This
->decode_info
.height
;
836 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
841 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
842 WICPixelFormatGUID
*pPixelFormat
)
844 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
846 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
848 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
853 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
854 double *pDpiX
, double *pDpiY
)
856 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
858 switch (This
->decode_info
.resolution_unit
)
861 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
863 case 0: /* Not set */
864 *pDpiX
= *pDpiY
= 96.0;
866 case 1: /* Relative measurements */
868 *pDpiY
= 96.0 * This
->decode_info
.yres
/ This
->decode_info
.xres
;
871 *pDpiX
= This
->decode_info
.xres
;
872 *pDpiY
= This
->decode_info
.yres
;
874 case 3: /* Centimeter */
875 *pDpiX
= This
->decode_info
.xres
/ 2.54;
876 *pDpiY
= This
->decode_info
.yres
/ 2.54;
880 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
885 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
886 IWICPalette
*pIPalette
)
888 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
889 uint16
*red
, *green
, *blue
;
890 WICColor colors
[256];
891 int color_count
, ret
, i
;
893 TRACE("(%p,%p)\n", iface
, pIPalette
);
895 color_count
= 1<<This
->decode_info
.bps
;
897 EnterCriticalSection(&This
->parent
->lock
);
898 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
899 LeaveCriticalSection(&This
->parent
->lock
);
903 WARN("Couldn't read color map\n");
904 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
907 for (i
=0; i
<color_count
; i
++)
909 colors
[i
] = 0xff000000 |
910 ((red
[i
]<<8) & 0xff0000) |
911 (green
[i
] & 0xff00) |
912 ((blue
[i
]>>8) & 0xff);
915 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
918 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
924 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
926 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
933 if (This
->decode_info
.tiled
)
935 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
939 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
946 if (hr
== S_OK
&& This
->decode_info
.reverse_bgr
)
948 if (This
->decode_info
.bps
== 8)
950 UINT sample_count
= This
->decode_info
.samples
;
952 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
953 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
957 if (hr
== S_OK
&& swap_bytes
&& This
->decode_info
.bps
> 8)
959 UINT row
, i
, samples_per_row
;
962 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
964 switch(This
->decode_info
.bps
)
967 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
969 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
970 for (i
=0; i
<samples_per_row
; i
++)
973 sample
[1] = sample
[0];
980 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
985 if (hr
== S_OK
&& This
->decode_info
.invert_grayscale
)
989 if (This
->decode_info
.samples
!= 1)
991 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
995 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
997 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
1003 This
->cached_tile_x
= tile_x
;
1004 This
->cached_tile_y
= tile_y
;
1010 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
1011 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
1013 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1014 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
1015 UINT tile_x
, tile_y
;
1022 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1028 rect
.Width
= This
->decode_info
.width
;
1029 rect
.Height
= This
->decode_info
.height
;
1034 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
1035 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1036 return E_INVALIDARG
;
1039 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1041 if (cbStride
< bytesperrow
)
1042 return E_INVALIDARG
;
1044 if ((cbStride
* prc
->Height
) > cbBufferSize
)
1045 return E_INVALIDARG
;
1047 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1048 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1049 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1050 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1052 EnterCriticalSection(&This
->parent
->lock
);
1054 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1056 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1058 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1060 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1065 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1068 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1070 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1073 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1075 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1076 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1077 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1078 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1080 rc
.Width
= prc
->Width
;
1082 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1083 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1084 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1085 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1087 rc
.Height
= prc
->Height
;
1089 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1090 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1092 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1093 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1094 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1099 LeaveCriticalSection(&This
->parent
->lock
);
1100 TRACE("<-- 0x%x\n", hr
);
1106 LeaveCriticalSection(&This
->parent
->lock
);
1111 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1112 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1114 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
1118 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1119 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1121 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1122 const BYTE
*profile
;
1126 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1128 EnterCriticalSection(&This
->parent
->lock
);
1130 if (pTIFFGetField(This
->parent
->tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
1132 if (cCount
&& ppIColorContexts
)
1134 hr
= IWICColorContext_InitializeFromMemory(*ppIColorContexts
, profile
, len
);
1137 LeaveCriticalSection(&This
->parent
->lock
);
1146 LeaveCriticalSection(&This
->parent
->lock
);
1151 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1152 IWICBitmapSource
**ppIThumbnail
)
1154 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1156 if (!ppIThumbnail
) return E_INVALIDARG
;
1158 *ppIThumbnail
= NULL
;
1159 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1162 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1163 TiffFrameDecode_QueryInterface
,
1164 TiffFrameDecode_AddRef
,
1165 TiffFrameDecode_Release
,
1166 TiffFrameDecode_GetSize
,
1167 TiffFrameDecode_GetPixelFormat
,
1168 TiffFrameDecode_GetResolution
,
1169 TiffFrameDecode_CopyPalette
,
1170 TiffFrameDecode_CopyPixels
,
1171 TiffFrameDecode_GetMetadataQueryReader
,
1172 TiffFrameDecode_GetColorContexts
,
1173 TiffFrameDecode_GetThumbnail
1176 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1177 REFIID iid
, void **ppv
)
1179 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1180 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1183 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1185 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1186 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1189 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1191 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1192 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1195 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1198 TRACE("(%p,%p)\n", iface
, guid
);
1200 if (!guid
) return E_INVALIDARG
;
1202 *guid
= GUID_ContainerFormatTiff
;
1206 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1209 TRACE("%p,%p\n", iface
, count
);
1211 if (!count
) return E_INVALIDARG
;
1217 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1220 LARGE_INTEGER dir_offset
;
1221 IWICMetadataReader
*metadata_reader
;
1222 IWICPersistStream
*persist
;
1224 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1226 hr
= IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
1227 if (FAILED(hr
)) return hr
;
1229 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1232 IWICMetadataReader_Release(metadata_reader
);
1236 EnterCriticalSection(&This
->parent
->lock
);
1238 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1239 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1242 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1243 #ifdef WORDS_BIGENDIAN
1244 DWORD persist_options
= byte_swapped
? WICPersistOptionsLittleEndian
: WICPersistOptionsBigEndian
;
1246 DWORD persist_options
= byte_swapped
? WICPersistOptionsBigEndian
: WICPersistOptionsLittleEndian
;
1248 persist_options
|= WICPersistOptionsNoCacheStream
;
1249 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1251 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1254 LeaveCriticalSection(&This
->parent
->lock
);
1256 IWICPersistStream_Release(persist
);
1260 IWICMetadataReader_Release(metadata_reader
);
1264 *reader
= metadata_reader
;
1268 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1269 UINT index
, IWICMetadataReader
**reader
)
1271 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1273 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1275 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1277 return create_metadata_reader(This
, reader
);
1280 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1281 IEnumUnknown
**enum_metadata
)
1283 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1287 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1289 TiffFrameDecode_Block_QueryInterface
,
1290 TiffFrameDecode_Block_AddRef
,
1291 TiffFrameDecode_Block_Release
,
1292 TiffFrameDecode_Block_GetContainerFormat
,
1293 TiffFrameDecode_Block_GetCount
,
1294 TiffFrameDecode_Block_GetReaderByIndex
,
1295 TiffFrameDecode_Block_GetEnumerator
1298 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
1303 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1307 if (!load_libtiff())
1309 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1313 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1314 if (!This
) return E_OUTOFMEMORY
;
1316 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1318 This
->stream
= NULL
;
1319 InitializeCriticalSection(&This
->lock
);
1320 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1322 This
->initialized
= FALSE
;
1324 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1325 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1330 struct tiff_encode_format
{
1331 const WICPixelFormatGUID
*guid
;
1337 int extra_sample_type
;
1341 static const struct tiff_encode_format formats
[] = {
1342 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1343 {&GUID_WICPixelFormat24bppRGB
, 2, 8, 3, 24, 0, 0, 0},
1344 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1345 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1346 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1347 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1348 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1349 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1350 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1351 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1355 typedef struct TiffEncoder
{
1356 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1359 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1364 ULONG num_frames_committed
;
1367 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1369 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1372 typedef struct TiffFrameEncode
{
1373 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1375 TiffEncoder
*parent
;
1376 /* fields below are protected by parent->lock */
1380 const struct tiff_encode_format
*format
;
1386 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1388 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1391 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1394 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1395 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1397 if (!ppv
) return E_INVALIDARG
;
1399 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1400 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1402 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1407 return E_NOINTERFACE
;
1410 IUnknown_AddRef((IUnknown
*)*ppv
);
1414 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1416 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1417 ULONG ref
= InterlockedIncrement(&This
->ref
);
1419 TRACE("(%p) refcount=%u\n", iface
, ref
);
1424 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1426 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1427 ULONG ref
= InterlockedDecrement(&This
->ref
);
1429 TRACE("(%p) refcount=%u\n", iface
, ref
);
1433 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1434 HeapFree(GetProcessHeap(), 0, This
);
1440 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1441 IPropertyBag2
*pIEncoderOptions
)
1443 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1444 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1446 EnterCriticalSection(&This
->parent
->lock
);
1448 if (This
->initialized
)
1450 LeaveCriticalSection(&This
->parent
->lock
);
1451 return WINCODEC_ERR_WRONGSTATE
;
1454 This
->initialized
= TRUE
;
1456 LeaveCriticalSection(&This
->parent
->lock
);
1461 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1462 UINT uiWidth
, UINT uiHeight
)
1464 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1465 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1467 EnterCriticalSection(&This
->parent
->lock
);
1469 if (!This
->initialized
|| This
->info_written
)
1471 LeaveCriticalSection(&This
->parent
->lock
);
1472 return WINCODEC_ERR_WRONGSTATE
;
1475 This
->width
= uiWidth
;
1476 This
->height
= uiHeight
;
1478 LeaveCriticalSection(&This
->parent
->lock
);
1483 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1484 double dpiX
, double dpiY
)
1486 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1487 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1489 EnterCriticalSection(&This
->parent
->lock
);
1491 if (!This
->initialized
|| This
->info_written
)
1493 LeaveCriticalSection(&This
->parent
->lock
);
1494 return WINCODEC_ERR_WRONGSTATE
;
1500 LeaveCriticalSection(&This
->parent
->lock
);
1505 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1506 WICPixelFormatGUID
*pPixelFormat
)
1508 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1511 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1513 EnterCriticalSection(&This
->parent
->lock
);
1515 if (!This
->initialized
|| This
->info_written
)
1517 LeaveCriticalSection(&This
->parent
->lock
);
1518 return WINCODEC_ERR_WRONGSTATE
;
1521 for (i
=0; formats
[i
].guid
; i
++)
1523 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1527 if (!formats
[i
].guid
) i
= 0;
1529 This
->format
= &formats
[i
];
1530 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1532 LeaveCriticalSection(&This
->parent
->lock
);
1537 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1538 UINT cCount
, IWICColorContext
**ppIColorContext
)
1540 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1544 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1545 IWICPalette
*pIPalette
)
1547 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
1548 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1551 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1552 IWICBitmapSource
*pIThumbnail
)
1554 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1555 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1558 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1559 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1561 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1562 BYTE
*row_data
, *swapped_data
= NULL
;
1563 UINT i
, j
, line_size
;
1565 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1567 EnterCriticalSection(&This
->parent
->lock
);
1569 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1571 LeaveCriticalSection(&This
->parent
->lock
);
1572 return WINCODEC_ERR_WRONGSTATE
;
1575 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1577 LeaveCriticalSection(&This
->parent
->lock
);
1578 return E_INVALIDARG
;
1581 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1583 if (This
->format
->reverse_bgr
)
1585 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1588 LeaveCriticalSection(&This
->parent
->lock
);
1589 return E_OUTOFMEMORY
;
1593 if (!This
->info_written
)
1595 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1596 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1597 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1598 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1600 if (This
->format
->extra_sample
)
1602 uint16 extra_samples
;
1603 extra_samples
= This
->format
->extra_sample_type
;
1605 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1608 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1609 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1611 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1613 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1614 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1615 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1618 This
->info_written
= TRUE
;
1621 for (i
=0; i
<lineCount
; i
++)
1623 row_data
= pbPixels
+ i
* cbStride
;
1625 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1627 memcpy(swapped_data
, row_data
, line_size
);
1628 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1631 temp
= swapped_data
[j
];
1632 swapped_data
[j
] = swapped_data
[j
+2];
1633 swapped_data
[j
+2] = temp
;
1635 row_data
= swapped_data
;
1638 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1641 This
->lines_written
+= lineCount
;
1643 LeaveCriticalSection(&This
->parent
->lock
);
1645 HeapFree(GetProcessHeap(), 0, swapped_data
);
1650 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1651 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1653 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1656 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1658 if (!This
->initialized
)
1659 return WINCODEC_ERR_WRONGSTATE
;
1661 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
1662 This
->format
? This
->format
->guid
: NULL
, This
->width
, This
->height
,
1663 This
->xres
, This
->yres
);
1667 hr
= write_source(iface
, pIBitmapSource
, prc
,
1668 This
->format
->guid
, This
->format
->bpp
, This
->width
, This
->height
);
1674 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1676 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1678 TRACE("(%p)\n", iface
);
1680 EnterCriticalSection(&This
->parent
->lock
);
1682 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1684 LeaveCriticalSection(&This
->parent
->lock
);
1685 return WINCODEC_ERR_WRONGSTATE
;
1688 /* libtiff will commit the data when creating a new frame or closing the file */
1690 This
->committed
= TRUE
;
1691 This
->parent
->num_frames_committed
++;
1693 LeaveCriticalSection(&This
->parent
->lock
);
1698 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1699 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1701 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1705 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
1706 TiffFrameEncode_QueryInterface
,
1707 TiffFrameEncode_AddRef
,
1708 TiffFrameEncode_Release
,
1709 TiffFrameEncode_Initialize
,
1710 TiffFrameEncode_SetSize
,
1711 TiffFrameEncode_SetResolution
,
1712 TiffFrameEncode_SetPixelFormat
,
1713 TiffFrameEncode_SetColorContexts
,
1714 TiffFrameEncode_SetPalette
,
1715 TiffFrameEncode_SetThumbnail
,
1716 TiffFrameEncode_WritePixels
,
1717 TiffFrameEncode_WriteSource
,
1718 TiffFrameEncode_Commit
,
1719 TiffFrameEncode_GetMetadataQueryWriter
1722 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1725 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1726 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1728 if (!ppv
) return E_INVALIDARG
;
1730 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1731 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1733 *ppv
= &This
->IWICBitmapEncoder_iface
;
1738 return E_NOINTERFACE
;
1741 IUnknown_AddRef((IUnknown
*)*ppv
);
1745 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
1747 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1748 ULONG ref
= InterlockedIncrement(&This
->ref
);
1750 TRACE("(%p) refcount=%u\n", iface
, ref
);
1755 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
1757 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1758 ULONG ref
= InterlockedDecrement(&This
->ref
);
1760 TRACE("(%p) refcount=%u\n", iface
, ref
);
1764 if (This
->tiff
) pTIFFClose(This
->tiff
);
1765 if (This
->stream
) IStream_Release(This
->stream
);
1766 This
->lock
.DebugInfo
->Spare
[0] = 0;
1767 DeleteCriticalSection(&This
->lock
);
1768 HeapFree(GetProcessHeap(), 0, This
);
1774 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
1775 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1777 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1781 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1783 EnterCriticalSection(&This
->lock
);
1785 if (This
->initialized
|| This
->committed
)
1787 hr
= WINCODEC_ERR_WRONGSTATE
;
1791 tiff
= tiff_open_stream(pIStream
, "w");
1800 This
->stream
= pIStream
;
1801 IStream_AddRef(pIStream
);
1802 This
->initialized
= TRUE
;
1805 LeaveCriticalSection(&This
->lock
);
1809 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1810 GUID
*pguidContainerFormat
)
1812 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
1816 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1817 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1819 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1823 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1824 UINT cCount
, IWICColorContext
**ppIColorContext
)
1826 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1830 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1832 TRACE("(%p,%p)\n", iface
, pIPalette
);
1833 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1836 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1838 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1839 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1842 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1844 TRACE("(%p,%p)\n", iface
, pIPreview
);
1845 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1848 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1849 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1851 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1852 TiffFrameEncode
*result
;
1856 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1858 EnterCriticalSection(&This
->lock
);
1860 if (!This
->initialized
|| This
->committed
)
1862 hr
= WINCODEC_ERR_WRONGSTATE
;
1864 else if (This
->num_frames
!= This
->num_frames_committed
)
1866 FIXME("New frame created before previous frame was committed\n");
1872 PROPBAG2 opts
[2]= {{0}};
1873 opts
[0].pstrName
= (LPOLESTR
)wszTiffCompressionMethod
;
1874 opts
[0].vt
= VT_UI1
;
1875 opts
[0].dwType
= PROPBAG2_TYPE_DATA
;
1877 opts
[1].pstrName
= (LPOLESTR
)wszCompressionQuality
;
1879 opts
[1].dwType
= PROPBAG2_TYPE_DATA
;
1881 hr
= CreatePropertyBag2(opts
, 2, ppIEncoderOptions
);
1888 V_UNION(&v
, bVal
) = WICTiffCompressionDontCare
;
1889 hr
= IPropertyBag2_Write(*ppIEncoderOptions
, 1, opts
, &v
);
1893 IPropertyBag2_Release(*ppIEncoderOptions
);
1894 *ppIEncoderOptions
= NULL
;
1901 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
1905 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
1907 result
->parent
= This
;
1908 result
->initialized
= FALSE
;
1909 result
->info_written
= FALSE
;
1910 result
->committed
= FALSE
;
1911 result
->format
= NULL
;
1916 result
->lines_written
= 0;
1918 IWICBitmapEncoder_AddRef(iface
);
1919 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
1921 if (This
->num_frames
!= 0)
1922 pTIFFWriteDirectory(This
->tiff
);
1931 IPropertyBag2_Release(*ppIEncoderOptions
);
1932 *ppIEncoderOptions
= NULL
;
1936 LeaveCriticalSection(&This
->lock
);
1941 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
1943 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1945 TRACE("(%p)\n", iface
);
1947 EnterCriticalSection(&This
->lock
);
1949 if (!This
->initialized
|| This
->committed
)
1951 LeaveCriticalSection(&This
->lock
);
1952 return WINCODEC_ERR_WRONGSTATE
;
1955 pTIFFClose(This
->tiff
);
1956 IStream_Release(This
->stream
);
1957 This
->stream
= NULL
;
1960 This
->committed
= TRUE
;
1962 LeaveCriticalSection(&This
->lock
);
1967 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
1968 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1970 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
1974 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
1975 TiffEncoder_QueryInterface
,
1977 TiffEncoder_Release
,
1978 TiffEncoder_Initialize
,
1979 TiffEncoder_GetContainerFormat
,
1980 TiffEncoder_GetEncoderInfo
,
1981 TiffEncoder_SetColorContexts
,
1982 TiffEncoder_SetPalette
,
1983 TiffEncoder_SetThumbnail
,
1984 TiffEncoder_SetPreview
,
1985 TiffEncoder_CreateNewFrame
,
1987 TiffEncoder_GetMetadataQueryWriter
1990 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
1995 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1999 if (!load_libtiff())
2001 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
2005 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
2006 if (!This
) return E_OUTOFMEMORY
;
2008 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
2010 This
->stream
= NULL
;
2011 InitializeCriticalSection(&This
->lock
);
2012 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
2014 This
->initialized
= FALSE
;
2015 This
->num_frames
= 0;
2016 This
->num_frames_committed
= 0;
2017 This
->committed
= FALSE
;
2019 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2020 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
2025 #else /* !SONAME_LIBTIFF */
2027 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
2029 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
2033 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2035 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");