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
19 #include "wincodecs_private.h"
30 /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which
31 * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they
32 * are supposed to be always 64-bit.
33 * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x.
37 # define toff_t UINT64
40 static CRITICAL_SECTION init_tiff_cs
;
41 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
44 { &init_tiff_cs_debug
.ProcessLocksList
,
45 &init_tiff_cs_debug
.ProcessLocksList
},
46 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
48 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
50 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};
51 static const WCHAR wszCompressionQuality
[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
53 static void *libtiff_handle
;
54 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
55 MAKE_FUNCPTR(TIFFClientOpen
);
56 MAKE_FUNCPTR(TIFFClose
);
57 MAKE_FUNCPTR(TIFFCurrentDirOffset
);
58 MAKE_FUNCPTR(TIFFGetField
);
59 MAKE_FUNCPTR(TIFFIsByteSwapped
);
60 MAKE_FUNCPTR(TIFFNumberOfDirectories
);
61 MAKE_FUNCPTR(TIFFReadDirectory
);
62 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
63 MAKE_FUNCPTR(TIFFReadEncodedTile
);
64 MAKE_FUNCPTR(TIFFSetDirectory
);
65 MAKE_FUNCPTR(TIFFSetField
);
66 MAKE_FUNCPTR(TIFFWriteDirectory
);
67 MAKE_FUNCPTR(TIFFWriteScanline
);
70 static void *load_libtiff(void)
74 EnterCriticalSection(&init_tiff_cs
);
76 if (!libtiff_handle
&&
77 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
79 void * (*pTIFFSetWarningHandler
)(void *);
80 void * (*pTIFFSetWarningHandlerExt
)(void *);
82 #define LOAD_FUNCPTR(f) \
83 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
84 ERR("failed to load symbol %s\n", #f); \
85 libtiff_handle = NULL; \
86 LeaveCriticalSection(&init_tiff_cs); \
89 LOAD_FUNCPTR(TIFFClientOpen
);
90 LOAD_FUNCPTR(TIFFClose
);
91 LOAD_FUNCPTR(TIFFCurrentDirOffset
);
92 LOAD_FUNCPTR(TIFFGetField
);
93 LOAD_FUNCPTR(TIFFIsByteSwapped
);
94 LOAD_FUNCPTR(TIFFNumberOfDirectories
);
95 LOAD_FUNCPTR(TIFFReadDirectory
);
96 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
97 LOAD_FUNCPTR(TIFFReadEncodedTile
);
98 LOAD_FUNCPTR(TIFFSetDirectory
);
99 LOAD_FUNCPTR(TIFFSetField
);
100 LOAD_FUNCPTR(TIFFWriteDirectory
);
101 LOAD_FUNCPTR(TIFFWriteScanline
);
104 if ((pTIFFSetWarningHandler
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandler", NULL
, 0)))
105 pTIFFSetWarningHandler(NULL
);
106 if ((pTIFFSetWarningHandlerExt
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandlerExt", NULL
, 0)))
107 pTIFFSetWarningHandlerExt(NULL
);
110 result
= libtiff_handle
;
112 LeaveCriticalSection(&init_tiff_cs
);
116 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
118 IStream
*stream
= (IStream
*)client_data
;
122 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
123 if (FAILED(hr
)) bytes_read
= 0;
127 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
129 IStream
*stream
= (IStream
*)client_data
;
133 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
134 if (FAILED(hr
)) bytes_written
= 0;
135 return bytes_written
;
138 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
140 IStream
*stream
= (IStream
*)client_data
;
143 ULARGE_INTEGER new_position
;
146 move
.QuadPart
= offset
;
150 origin
= STREAM_SEEK_SET
;
153 origin
= STREAM_SEEK_CUR
;
156 origin
= STREAM_SEEK_END
;
159 ERR("unknown whence value %i\n", whence
);
163 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
164 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
168 static int tiff_stream_close(thandle_t client_data
)
170 /* Caller is responsible for releasing the stream object. */
174 static toff_t
tiff_stream_size(thandle_t client_data
)
176 IStream
*stream
= (IStream
*)client_data
;
180 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
182 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
186 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
188 /* Cannot mmap streams */
192 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
194 /* No need to ever do this, since we can't map things. */
197 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
202 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
204 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
205 tiff_stream_write
, (void *)tiff_stream_seek
, tiff_stream_close
,
206 (void *)tiff_stream_size
, (void *)tiff_stream_map
, (void *)tiff_stream_unmap
);
210 IWICBitmapDecoder IWICBitmapDecoder_iface
;
213 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initiailzed is set */
219 const WICPixelFormatGUID
*format
;
226 int invert_grayscale
;
228 UINT tile_width
, tile_height
;
233 UINT resolution_unit
;
238 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
239 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
243 tiff_decode_info decode_info
;
244 INT cached_tile_x
, cached_tile_y
;
248 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
249 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
251 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
253 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
256 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
258 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
261 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
263 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
266 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
268 uint16 photometric
, bps
, samples
, planar
;
269 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
272 decode_info
->indexed
= 0;
273 decode_info
->reverse_bgr
= 0;
274 decode_info
->invert_grayscale
= 0;
275 decode_info
->tiled
= 0;
277 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
280 WARN("missing PhotometricInterpretation tag\n");
284 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
286 decode_info
->bps
= bps
;
288 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
289 if (!ret
) samples
= 1;
290 decode_info
->samples
= samples
;
296 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
297 if (!ret
) planar
= 1;
300 FIXME("unhandled planar configuration %u\n", planar
);
304 decode_info
->planar
= planar
;
308 case 0: /* WhiteIsZero */
309 decode_info
->invert_grayscale
= 1;
311 case 1: /* BlackIsZero */
314 FIXME("unhandled grayscale sample count %u\n", samples
);
318 decode_info
->bpp
= bps
;
322 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
325 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
328 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
331 FIXME("unhandled greyscale bit count %u\n", bps
);
336 decode_info
->bpp
= bps
* samples
;
340 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
343 extra_sample_count
= 1;
345 extra_samples
= &extra_sample
;
348 else if (samples
!= 3)
350 FIXME("unhandled RGB sample count %u\n", samples
);
357 decode_info
->reverse_bgr
= 1;
359 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
361 switch(extra_samples
[0])
363 case 1: /* Associated (pre-multiplied) alpha data */
364 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
366 case 0: /* Unspecified data */
367 case 2: /* Unassociated alpha data */
368 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
371 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
377 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
379 switch(extra_samples
[0])
381 case 1: /* Associated (pre-multiplied) alpha data */
382 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
384 case 0: /* Unspecified data */
385 case 2: /* Unassociated alpha data */
386 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
389 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
394 FIXME("unhandled RGB bit count %u\n", bps
);
398 case 3: /* RGB Palette */
401 FIXME("unhandled indexed sample count %u\n", samples
);
405 decode_info
->indexed
= 1;
406 decode_info
->bpp
= bps
;
410 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
413 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
416 FIXME("unhandled indexed bit count %u\n", bps
);
420 case 4: /* Transparency mask */
425 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
429 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
432 WARN("missing image width\n");
436 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
439 WARN("missing image length\n");
443 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
445 decode_info
->tiled
= 1;
447 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
450 WARN("missing tile height\n");
454 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
455 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
456 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
458 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
460 if (decode_info
->tile_height
> decode_info
->height
)
461 decode_info
->tile_height
= decode_info
->height
;
462 decode_info
->tile_width
= decode_info
->width
;
463 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
464 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
468 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
469 decode_info
->tile_height
= decode_info
->height
;
470 decode_info
->tile_width
= decode_info
->width
;
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
;
475 decode_info
->resolution_unit
= 0;
476 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
477 if (decode_info
->resolution_unit
!= 0)
479 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
482 WARN("missing X resolution\n");
483 decode_info
->resolution_unit
= 0;
486 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
489 WARN("missing Y resolution\n");
490 decode_info
->resolution_unit
= 0;
497 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
500 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
501 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
503 if (!ppv
) return E_INVALIDARG
;
505 if (IsEqualIID(&IID_IUnknown
, iid
) ||
506 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
508 *ppv
= &This
->IWICBitmapDecoder_iface
;
513 return E_NOINTERFACE
;
516 IUnknown_AddRef((IUnknown
*)*ppv
);
520 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
522 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
523 ULONG ref
= InterlockedIncrement(&This
->ref
);
525 TRACE("(%p) refcount=%u\n", iface
, ref
);
530 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
532 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
533 ULONG ref
= InterlockedDecrement(&This
->ref
);
535 TRACE("(%p) refcount=%u\n", iface
, ref
);
539 if (This
->tiff
) pTIFFClose(This
->tiff
);
540 if (This
->stream
) IStream_Release(This
->stream
);
541 This
->lock
.DebugInfo
->Spare
[0] = 0;
542 DeleteCriticalSection(&This
->lock
);
543 HeapFree(GetProcessHeap(), 0, This
);
549 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
554 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
556 if (!stream
|| !capability
) return E_INVALIDARG
;
558 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
559 if (hr
!= S_OK
) return hr
;
561 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
562 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
563 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
567 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
568 WICDecodeOptions cacheOptions
)
570 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
574 TRACE("(%p,%p,%x): stub\n", iface
, pIStream
, cacheOptions
);
576 EnterCriticalSection(&This
->lock
);
578 if (This
->initialized
)
580 hr
= WINCODEC_ERR_WRONGSTATE
;
584 tiff
= tiff_open_stream(pIStream
, "r");
593 This
->stream
= pIStream
;
594 IStream_AddRef(pIStream
);
595 This
->initialized
= TRUE
;
598 LeaveCriticalSection(&This
->lock
);
602 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
603 GUID
*pguidContainerFormat
)
605 if (!pguidContainerFormat
) return E_INVALIDARG
;
607 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
611 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
612 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
615 IWICComponentInfo
*compinfo
;
617 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
619 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
620 if (FAILED(hr
)) return hr
;
622 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
623 (void**)ppIDecoderInfo
);
625 IWICComponentInfo_Release(compinfo
);
630 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
631 IWICPalette
*pIPalette
)
633 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
637 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
638 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
640 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
644 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
645 IWICBitmapSource
**ppIBitmapSource
)
647 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
649 if (!ppIBitmapSource
) return E_INVALIDARG
;
651 *ppIBitmapSource
= NULL
;
652 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
655 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
656 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
658 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
659 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
662 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
663 IWICBitmapSource
**ppIThumbnail
)
665 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
667 if (!ppIThumbnail
) return E_INVALIDARG
;
669 *ppIThumbnail
= NULL
;
670 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
673 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
676 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
678 if (!pCount
) return E_INVALIDARG
;
680 EnterCriticalSection(&This
->lock
);
681 *pCount
= This
->tiff
? pTIFFNumberOfDirectories(This
->tiff
) : 0;
682 LeaveCriticalSection(&This
->lock
);
684 TRACE("(%p) <-- %i\n", iface
, *pCount
);
689 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
690 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
692 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
693 TiffFrameDecode
*result
;
695 tiff_decode_info decode_info
;
698 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
701 return WINCODEC_ERR_FRAMEMISSING
;
703 EnterCriticalSection(&This
->lock
);
704 res
= pTIFFSetDirectory(This
->tiff
, index
);
705 if (!res
) hr
= E_INVALIDARG
;
706 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
707 LeaveCriticalSection(&This
->lock
);
711 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
715 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
716 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
718 result
->parent
= This
;
719 result
->index
= index
;
720 result
->decode_info
= decode_info
;
721 result
->cached_tile_x
= -1;
722 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
724 if (result
->cached_tile
)
725 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
729 HeapFree(GetProcessHeap(), 0, result
);
732 else hr
= E_OUTOFMEMORY
;
735 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
740 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
741 TiffDecoder_QueryInterface
,
744 TiffDecoder_QueryCapability
,
745 TiffDecoder_Initialize
,
746 TiffDecoder_GetContainerFormat
,
747 TiffDecoder_GetDecoderInfo
,
748 TiffDecoder_CopyPalette
,
749 TiffDecoder_GetMetadataQueryReader
,
750 TiffDecoder_GetPreview
,
751 TiffDecoder_GetColorContexts
,
752 TiffDecoder_GetThumbnail
,
753 TiffDecoder_GetFrameCount
,
757 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
760 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
761 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
763 if (!ppv
) return E_INVALIDARG
;
765 if (IsEqualIID(&IID_IUnknown
, iid
) ||
766 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
767 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
769 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
771 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
773 *ppv
= &This
->IWICMetadataBlockReader_iface
;
778 return E_NOINTERFACE
;
781 IUnknown_AddRef((IUnknown
*)*ppv
);
785 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
787 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
788 ULONG ref
= InterlockedIncrement(&This
->ref
);
790 TRACE("(%p) refcount=%u\n", iface
, ref
);
795 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
797 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
798 ULONG ref
= InterlockedDecrement(&This
->ref
);
800 TRACE("(%p) refcount=%u\n", iface
, ref
);
804 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
805 HeapFree(GetProcessHeap(), 0, This
);
811 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
812 UINT
*puiWidth
, UINT
*puiHeight
)
814 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
816 *puiWidth
= This
->decode_info
.width
;
817 *puiHeight
= This
->decode_info
.height
;
819 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
824 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
825 WICPixelFormatGUID
*pPixelFormat
)
827 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
829 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
831 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
836 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
837 double *pDpiX
, double *pDpiY
)
839 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
841 switch (This
->decode_info
.resolution_unit
)
844 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
846 case 0: /* Not set */
847 *pDpiX
= *pDpiY
= 96.0;
849 case 1: /* Relative measurements */
851 *pDpiY
= 96.0 * This
->decode_info
.yres
/ This
->decode_info
.xres
;
854 *pDpiX
= This
->decode_info
.xres
;
855 *pDpiY
= This
->decode_info
.yres
;
857 case 3: /* Centimeter */
858 *pDpiX
= This
->decode_info
.xres
/ 2.54;
859 *pDpiY
= This
->decode_info
.yres
/ 2.54;
863 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
868 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
869 IWICPalette
*pIPalette
)
871 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
872 uint16
*red
, *green
, *blue
;
873 WICColor colors
[256];
874 int color_count
, ret
, i
;
876 TRACE("(%p,%p)\n", iface
, pIPalette
);
878 color_count
= 1<<This
->decode_info
.bps
;
880 EnterCriticalSection(&This
->parent
->lock
);
881 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
882 LeaveCriticalSection(&This
->parent
->lock
);
886 WARN("Couldn't read color map\n");
887 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
890 for (i
=0; i
<color_count
; i
++)
892 colors
[i
] = 0xff000000 |
893 ((red
[i
]<<8) & 0xff0000) |
894 (green
[i
] & 0xff00) |
895 ((blue
[i
]>>8) & 0xff);
898 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
901 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
907 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
909 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
916 if (This
->decode_info
.tiled
)
918 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
922 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
929 if (hr
== S_OK
&& This
->decode_info
.reverse_bgr
)
931 if (This
->decode_info
.bps
== 8)
933 UINT sample_count
= This
->decode_info
.samples
;
935 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
936 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
940 if (hr
== S_OK
&& swap_bytes
&& This
->decode_info
.bps
> 8)
942 UINT row
, i
, samples_per_row
;
945 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
947 switch(This
->decode_info
.bps
)
950 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
952 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
953 for (i
=0; i
<samples_per_row
; i
++)
956 sample
[1] = sample
[0];
963 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
968 if (hr
== S_OK
&& This
->decode_info
.invert_grayscale
)
972 if (This
->decode_info
.samples
!= 1)
974 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
978 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
980 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
986 This
->cached_tile_x
= tile_x
;
987 This
->cached_tile_y
= tile_y
;
993 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
994 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
996 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
997 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
1005 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1011 rect
.Width
= This
->decode_info
.width
;
1012 rect
.Height
= This
->decode_info
.height
;
1017 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
1018 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1019 return E_INVALIDARG
;
1022 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1024 if (cbStride
< bytesperrow
)
1025 return E_INVALIDARG
;
1027 if ((cbStride
* prc
->Height
) > cbBufferSize
)
1028 return E_INVALIDARG
;
1030 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1031 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1032 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1033 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1035 EnterCriticalSection(&This
->parent
->lock
);
1037 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1039 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1041 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1043 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1048 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1051 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1053 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1056 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1058 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1059 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1060 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1061 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1063 rc
.Width
= prc
->Width
;
1065 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1066 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1067 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1068 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1070 rc
.Height
= prc
->Height
;
1072 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1073 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1075 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1076 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1077 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1082 LeaveCriticalSection(&This
->parent
->lock
);
1083 TRACE("<-- 0x%x\n", hr
);
1089 LeaveCriticalSection(&This
->parent
->lock
);
1094 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1095 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1097 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
1101 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1102 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1104 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1105 const BYTE
*profile
;
1109 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1111 EnterCriticalSection(&This
->parent
->lock
);
1113 if (pTIFFGetField(This
->parent
->tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
1115 if (cCount
&& ppIColorContexts
)
1117 hr
= IWICColorContext_InitializeFromMemory(*ppIColorContexts
, profile
, len
);
1120 LeaveCriticalSection(&This
->parent
->lock
);
1129 LeaveCriticalSection(&This
->parent
->lock
);
1134 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1135 IWICBitmapSource
**ppIThumbnail
)
1137 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1139 if (!ppIThumbnail
) return E_INVALIDARG
;
1141 *ppIThumbnail
= NULL
;
1142 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1145 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1146 TiffFrameDecode_QueryInterface
,
1147 TiffFrameDecode_AddRef
,
1148 TiffFrameDecode_Release
,
1149 TiffFrameDecode_GetSize
,
1150 TiffFrameDecode_GetPixelFormat
,
1151 TiffFrameDecode_GetResolution
,
1152 TiffFrameDecode_CopyPalette
,
1153 TiffFrameDecode_CopyPixels
,
1154 TiffFrameDecode_GetMetadataQueryReader
,
1155 TiffFrameDecode_GetColorContexts
,
1156 TiffFrameDecode_GetThumbnail
1159 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1160 REFIID iid
, void **ppv
)
1162 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1163 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1166 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1168 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1169 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1172 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1174 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1175 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1178 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1181 TRACE("(%p,%p)\n", iface
, guid
);
1183 if (!guid
) return E_INVALIDARG
;
1185 *guid
= GUID_ContainerFormatTiff
;
1189 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1192 TRACE("%p,%p\n", iface
, count
);
1194 if (!count
) return E_INVALIDARG
;
1200 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1203 LARGE_INTEGER dir_offset
;
1204 IWICMetadataReader
*metadata_reader
;
1205 IWICPersistStream
*persist
;
1207 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1209 hr
= CoCreateInstance(&CLSID_WICIfdMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
1210 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
1211 if (FAILED(hr
)) return hr
;
1213 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1216 IWICMetadataReader_Release(metadata_reader
);
1220 EnterCriticalSection(&This
->parent
->lock
);
1222 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1223 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1226 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1227 #ifdef WORDS_BIGENDIAN
1228 DWORD persist_options
= byte_swapped
? WICPersistOptionsLittleEndian
: WICPersistOptionsBigEndian
;
1230 DWORD persist_options
= byte_swapped
? WICPersistOptionsBigEndian
: WICPersistOptionsLittleEndian
;
1232 persist_options
|= WICPersistOptionsNoCacheStream
;
1233 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1235 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1238 LeaveCriticalSection(&This
->parent
->lock
);
1240 IWICPersistStream_Release(persist
);
1244 IWICMetadataReader_Release(metadata_reader
);
1248 *reader
= metadata_reader
;
1252 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1253 UINT index
, IWICMetadataReader
**reader
)
1255 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1257 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1259 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1261 return create_metadata_reader(This
, reader
);
1264 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1265 IEnumUnknown
**enum_metadata
)
1267 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1271 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1273 TiffFrameDecode_Block_QueryInterface
,
1274 TiffFrameDecode_Block_AddRef
,
1275 TiffFrameDecode_Block_Release
,
1276 TiffFrameDecode_Block_GetContainerFormat
,
1277 TiffFrameDecode_Block_GetCount
,
1278 TiffFrameDecode_Block_GetReaderByIndex
,
1279 TiffFrameDecode_Block_GetEnumerator
1282 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
1287 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1291 if (!load_libtiff())
1293 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1297 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1298 if (!This
) return E_OUTOFMEMORY
;
1300 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1302 This
->stream
= NULL
;
1303 InitializeCriticalSection(&This
->lock
);
1304 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1306 This
->initialized
= FALSE
;
1308 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1309 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1314 struct tiff_encode_format
{
1315 const WICPixelFormatGUID
*guid
;
1321 int extra_sample_type
;
1325 static const struct tiff_encode_format formats
[] = {
1326 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1327 {&GUID_WICPixelFormat24bppRGB
, 2, 8, 3, 24, 0, 0, 0},
1328 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1329 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1330 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1331 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1332 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1333 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1334 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1335 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1339 typedef struct TiffEncoder
{
1340 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1343 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1348 ULONG num_frames_committed
;
1351 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1353 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1356 typedef struct TiffFrameEncode
{
1357 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1359 TiffEncoder
*parent
;
1360 /* fields below are protected by parent->lock */
1364 const struct tiff_encode_format
*format
;
1370 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1372 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1375 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1378 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1379 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1381 if (!ppv
) return E_INVALIDARG
;
1383 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1384 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1386 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1391 return E_NOINTERFACE
;
1394 IUnknown_AddRef((IUnknown
*)*ppv
);
1398 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1400 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1401 ULONG ref
= InterlockedIncrement(&This
->ref
);
1403 TRACE("(%p) refcount=%u\n", iface
, ref
);
1408 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1410 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1411 ULONG ref
= InterlockedDecrement(&This
->ref
);
1413 TRACE("(%p) refcount=%u\n", iface
, ref
);
1417 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1418 HeapFree(GetProcessHeap(), 0, This
);
1424 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1425 IPropertyBag2
*pIEncoderOptions
)
1427 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1428 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1430 EnterCriticalSection(&This
->parent
->lock
);
1432 if (This
->initialized
)
1434 LeaveCriticalSection(&This
->parent
->lock
);
1435 return WINCODEC_ERR_WRONGSTATE
;
1438 This
->initialized
= TRUE
;
1440 LeaveCriticalSection(&This
->parent
->lock
);
1445 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1446 UINT uiWidth
, UINT uiHeight
)
1448 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1449 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1451 EnterCriticalSection(&This
->parent
->lock
);
1453 if (!This
->initialized
|| This
->info_written
)
1455 LeaveCriticalSection(&This
->parent
->lock
);
1456 return WINCODEC_ERR_WRONGSTATE
;
1459 This
->width
= uiWidth
;
1460 This
->height
= uiHeight
;
1462 LeaveCriticalSection(&This
->parent
->lock
);
1467 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1468 double dpiX
, double dpiY
)
1470 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1471 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1473 EnterCriticalSection(&This
->parent
->lock
);
1475 if (!This
->initialized
|| This
->info_written
)
1477 LeaveCriticalSection(&This
->parent
->lock
);
1478 return WINCODEC_ERR_WRONGSTATE
;
1484 LeaveCriticalSection(&This
->parent
->lock
);
1489 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1490 WICPixelFormatGUID
*pPixelFormat
)
1492 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1495 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1497 EnterCriticalSection(&This
->parent
->lock
);
1499 if (!This
->initialized
|| This
->info_written
)
1501 LeaveCriticalSection(&This
->parent
->lock
);
1502 return WINCODEC_ERR_WRONGSTATE
;
1505 for (i
=0; formats
[i
].guid
; i
++)
1507 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1511 if (!formats
[i
].guid
) i
= 0;
1513 This
->format
= &formats
[i
];
1514 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1516 LeaveCriticalSection(&This
->parent
->lock
);
1521 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1522 UINT cCount
, IWICColorContext
**ppIColorContext
)
1524 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1528 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1529 IWICPalette
*pIPalette
)
1531 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
1532 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1535 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1536 IWICBitmapSource
*pIThumbnail
)
1538 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1539 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1542 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1543 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1545 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1546 BYTE
*row_data
, *swapped_data
= NULL
;
1547 UINT i
, j
, line_size
;
1549 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1551 EnterCriticalSection(&This
->parent
->lock
);
1553 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1555 LeaveCriticalSection(&This
->parent
->lock
);
1556 return WINCODEC_ERR_WRONGSTATE
;
1559 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1561 LeaveCriticalSection(&This
->parent
->lock
);
1562 return E_INVALIDARG
;
1565 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1567 if (This
->format
->reverse_bgr
)
1569 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1572 LeaveCriticalSection(&This
->parent
->lock
);
1573 return E_OUTOFMEMORY
;
1577 if (!This
->info_written
)
1579 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1580 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1581 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1582 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1584 if (This
->format
->extra_sample
)
1586 uint16 extra_samples
;
1587 extra_samples
= This
->format
->extra_sample_type
;
1589 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1592 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1593 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1595 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1597 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1598 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1599 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1602 This
->info_written
= TRUE
;
1605 for (i
=0; i
<lineCount
; i
++)
1607 row_data
= pbPixels
+ i
* cbStride
;
1609 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1611 memcpy(swapped_data
, row_data
, line_size
);
1612 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1615 temp
= swapped_data
[j
];
1616 swapped_data
[j
] = swapped_data
[j
+2];
1617 swapped_data
[j
+2] = temp
;
1619 row_data
= swapped_data
;
1622 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1625 This
->lines_written
+= lineCount
;
1627 LeaveCriticalSection(&This
->parent
->lock
);
1629 HeapFree(GetProcessHeap(), 0, swapped_data
);
1634 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1635 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1637 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1640 WICPixelFormatGUID guid
;
1644 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1646 if (!This
->initialized
|| !This
->width
|| !This
->height
)
1647 return WINCODEC_ERR_WRONGSTATE
;
1651 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1652 if (FAILED(hr
)) return hr
;
1653 hr
= IWICBitmapFrameEncode_SetPixelFormat(iface
, &guid
);
1654 if (FAILED(hr
)) return hr
;
1657 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1658 if (FAILED(hr
)) return hr
;
1659 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
1661 /* FIXME: should use WICConvertBitmapSource to convert */
1662 ERR("format %s unsupported\n", debugstr_guid(&guid
));
1666 if (This
->xres
== 0.0 || This
->yres
== 0.0)
1669 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
1670 if (FAILED(hr
)) return hr
;
1671 hr
= IWICBitmapFrameEncode_SetResolution(iface
, xres
, yres
);
1672 if (FAILED(hr
)) return hr
;
1678 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
1679 if (FAILED(hr
)) return hr
;
1687 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
1689 stride
= (This
->format
->bpp
* This
->width
+ 7)/8;
1691 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
1692 if (!pixeldata
) return E_OUTOFMEMORY
;
1694 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
1695 stride
*prc
->Height
, pixeldata
);
1699 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
1700 stride
*prc
->Height
, pixeldata
);
1703 HeapFree(GetProcessHeap(), 0, pixeldata
);
1708 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1710 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1712 TRACE("(%p)\n", iface
);
1714 EnterCriticalSection(&This
->parent
->lock
);
1716 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1718 LeaveCriticalSection(&This
->parent
->lock
);
1719 return WINCODEC_ERR_WRONGSTATE
;
1722 /* libtiff will commit the data when creating a new frame or closing the file */
1724 This
->committed
= TRUE
;
1725 This
->parent
->num_frames_committed
++;
1727 LeaveCriticalSection(&This
->parent
->lock
);
1732 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1733 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1735 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1739 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
1740 TiffFrameEncode_QueryInterface
,
1741 TiffFrameEncode_AddRef
,
1742 TiffFrameEncode_Release
,
1743 TiffFrameEncode_Initialize
,
1744 TiffFrameEncode_SetSize
,
1745 TiffFrameEncode_SetResolution
,
1746 TiffFrameEncode_SetPixelFormat
,
1747 TiffFrameEncode_SetColorContexts
,
1748 TiffFrameEncode_SetPalette
,
1749 TiffFrameEncode_SetThumbnail
,
1750 TiffFrameEncode_WritePixels
,
1751 TiffFrameEncode_WriteSource
,
1752 TiffFrameEncode_Commit
,
1753 TiffFrameEncode_GetMetadataQueryWriter
1756 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1759 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1760 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1762 if (!ppv
) return E_INVALIDARG
;
1764 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1765 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1767 *ppv
= &This
->IWICBitmapEncoder_iface
;
1772 return E_NOINTERFACE
;
1775 IUnknown_AddRef((IUnknown
*)*ppv
);
1779 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
1781 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1782 ULONG ref
= InterlockedIncrement(&This
->ref
);
1784 TRACE("(%p) refcount=%u\n", iface
, ref
);
1789 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
1791 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1792 ULONG ref
= InterlockedDecrement(&This
->ref
);
1794 TRACE("(%p) refcount=%u\n", iface
, ref
);
1798 if (This
->tiff
) pTIFFClose(This
->tiff
);
1799 if (This
->stream
) IStream_Release(This
->stream
);
1800 This
->lock
.DebugInfo
->Spare
[0] = 0;
1801 DeleteCriticalSection(&This
->lock
);
1802 HeapFree(GetProcessHeap(), 0, This
);
1808 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
1809 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1811 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1815 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1817 EnterCriticalSection(&This
->lock
);
1819 if (This
->initialized
|| This
->committed
)
1821 hr
= WINCODEC_ERR_WRONGSTATE
;
1825 tiff
= tiff_open_stream(pIStream
, "w");
1834 This
->stream
= pIStream
;
1835 IStream_AddRef(pIStream
);
1836 This
->initialized
= TRUE
;
1839 LeaveCriticalSection(&This
->lock
);
1843 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1844 GUID
*pguidContainerFormat
)
1846 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
1850 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1851 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1853 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1857 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1858 UINT cCount
, IWICColorContext
**ppIColorContext
)
1860 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1864 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1866 TRACE("(%p,%p)\n", iface
, pIPalette
);
1867 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1870 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1872 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1873 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1876 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1878 TRACE("(%p,%p)\n", iface
, pIPreview
);
1879 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1882 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1883 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1885 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1886 TiffFrameEncode
*result
;
1890 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1892 EnterCriticalSection(&This
->lock
);
1894 if (!This
->initialized
|| This
->committed
)
1896 hr
= WINCODEC_ERR_WRONGSTATE
;
1898 else if (This
->num_frames
!= This
->num_frames_committed
)
1900 FIXME("New frame created before previous frame was committed\n");
1906 PROPBAG2 opts
[2]= {{0}};
1907 opts
[0].pstrName
= (LPOLESTR
)wszTiffCompressionMethod
;
1908 opts
[0].vt
= VT_UI1
;
1909 opts
[0].dwType
= PROPBAG2_TYPE_DATA
;
1911 opts
[1].pstrName
= (LPOLESTR
)wszCompressionQuality
;
1913 opts
[1].dwType
= PROPBAG2_TYPE_DATA
;
1915 hr
= CreatePropertyBag2(opts
, 2, ppIEncoderOptions
);
1922 V_UNION(&v
, bVal
) = WICTiffCompressionDontCare
;
1923 hr
= IPropertyBag2_Write(*ppIEncoderOptions
, 1, opts
, &v
);
1927 IPropertyBag2_Release(*ppIEncoderOptions
);
1928 *ppIEncoderOptions
= NULL
;
1935 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
1939 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
1941 result
->parent
= This
;
1942 result
->initialized
= FALSE
;
1943 result
->info_written
= FALSE
;
1944 result
->committed
= FALSE
;
1945 result
->format
= NULL
;
1950 result
->lines_written
= 0;
1952 IWICBitmapEncoder_AddRef(iface
);
1953 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
1955 if (This
->num_frames
!= 0)
1956 pTIFFWriteDirectory(This
->tiff
);
1965 IPropertyBag2_Release(*ppIEncoderOptions
);
1966 *ppIEncoderOptions
= NULL
;
1970 LeaveCriticalSection(&This
->lock
);
1975 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
1977 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1979 TRACE("(%p)\n", iface
);
1981 EnterCriticalSection(&This
->lock
);
1983 if (!This
->initialized
|| This
->committed
)
1985 LeaveCriticalSection(&This
->lock
);
1986 return WINCODEC_ERR_WRONGSTATE
;
1989 pTIFFClose(This
->tiff
);
1990 IStream_Release(This
->stream
);
1991 This
->stream
= NULL
;
1994 This
->committed
= TRUE
;
1996 LeaveCriticalSection(&This
->lock
);
2001 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
2002 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
2004 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
2008 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
2009 TiffEncoder_QueryInterface
,
2011 TiffEncoder_Release
,
2012 TiffEncoder_Initialize
,
2013 TiffEncoder_GetContainerFormat
,
2014 TiffEncoder_GetEncoderInfo
,
2015 TiffEncoder_SetColorContexts
,
2016 TiffEncoder_SetPalette
,
2017 TiffEncoder_SetThumbnail
,
2018 TiffEncoder_SetPreview
,
2019 TiffEncoder_CreateNewFrame
,
2021 TiffEncoder_GetMetadataQueryWriter
2024 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2029 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
2033 if (!load_libtiff())
2035 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
2039 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
2040 if (!This
) return E_OUTOFMEMORY
;
2042 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
2044 This
->stream
= NULL
;
2045 InitializeCriticalSection(&This
->lock
);
2046 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
2048 This
->initialized
= FALSE
;
2049 This
->num_frames
= 0;
2050 This
->num_frames_committed
= 0;
2051 This
->committed
= FALSE
;
2053 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2054 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
2059 #else /* !SONAME_LIBTIFF */
2061 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
2063 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
2067 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2069 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");