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 "wincodecs_private.h"
38 #include "wine/debug.h"
39 #include "wine/library.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
45 /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which
46 * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they
47 * are supposed to be always 64-bit.
48 * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x.
52 # define toff_t UINT64
55 static CRITICAL_SECTION init_tiff_cs
;
56 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
59 { &init_tiff_cs_debug
.ProcessLocksList
,
60 &init_tiff_cs_debug
.ProcessLocksList
},
61 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
63 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
65 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};
66 static const WCHAR wszCompressionQuality
[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
68 static void *libtiff_handle
;
69 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
70 MAKE_FUNCPTR(TIFFClientOpen
);
71 MAKE_FUNCPTR(TIFFClose
);
72 MAKE_FUNCPTR(TIFFCurrentDirOffset
);
73 MAKE_FUNCPTR(TIFFGetField
);
74 MAKE_FUNCPTR(TIFFIsByteSwapped
);
75 MAKE_FUNCPTR(TIFFNumberOfDirectories
);
76 MAKE_FUNCPTR(TIFFReadDirectory
);
77 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
78 MAKE_FUNCPTR(TIFFReadEncodedTile
);
79 MAKE_FUNCPTR(TIFFSetDirectory
);
80 MAKE_FUNCPTR(TIFFSetField
);
81 MAKE_FUNCPTR(TIFFWriteDirectory
);
82 MAKE_FUNCPTR(TIFFWriteScanline
);
85 static void *load_libtiff(void)
89 EnterCriticalSection(&init_tiff_cs
);
91 if (!libtiff_handle
&&
92 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
94 void * (*pTIFFSetWarningHandler
)(void *);
95 void * (*pTIFFSetWarningHandlerExt
)(void *);
97 #define LOAD_FUNCPTR(f) \
98 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
99 ERR("failed to load symbol %s\n", #f); \
100 libtiff_handle = NULL; \
101 LeaveCriticalSection(&init_tiff_cs); \
104 LOAD_FUNCPTR(TIFFClientOpen
);
105 LOAD_FUNCPTR(TIFFClose
);
106 LOAD_FUNCPTR(TIFFCurrentDirOffset
);
107 LOAD_FUNCPTR(TIFFGetField
);
108 LOAD_FUNCPTR(TIFFIsByteSwapped
);
109 LOAD_FUNCPTR(TIFFNumberOfDirectories
);
110 LOAD_FUNCPTR(TIFFReadDirectory
);
111 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
112 LOAD_FUNCPTR(TIFFReadEncodedTile
);
113 LOAD_FUNCPTR(TIFFSetDirectory
);
114 LOAD_FUNCPTR(TIFFSetField
);
115 LOAD_FUNCPTR(TIFFWriteDirectory
);
116 LOAD_FUNCPTR(TIFFWriteScanline
);
119 if ((pTIFFSetWarningHandler
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandler", NULL
, 0)))
120 pTIFFSetWarningHandler(NULL
);
121 if ((pTIFFSetWarningHandlerExt
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandlerExt", NULL
, 0)))
122 pTIFFSetWarningHandlerExt(NULL
);
125 result
= libtiff_handle
;
127 LeaveCriticalSection(&init_tiff_cs
);
131 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
133 IStream
*stream
= (IStream
*)client_data
;
137 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
138 if (FAILED(hr
)) bytes_read
= 0;
142 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
144 IStream
*stream
= (IStream
*)client_data
;
148 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
149 if (FAILED(hr
)) bytes_written
= 0;
150 return bytes_written
;
153 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
155 IStream
*stream
= (IStream
*)client_data
;
158 ULARGE_INTEGER new_position
;
161 move
.QuadPart
= offset
;
165 origin
= STREAM_SEEK_SET
;
168 origin
= STREAM_SEEK_CUR
;
171 origin
= STREAM_SEEK_END
;
174 ERR("unknown whence value %i\n", whence
);
178 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
179 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
183 static int tiff_stream_close(thandle_t client_data
)
185 /* Caller is responsible for releasing the stream object. */
189 static toff_t
tiff_stream_size(thandle_t client_data
)
191 IStream
*stream
= (IStream
*)client_data
;
195 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
197 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
201 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
203 /* Cannot mmap streams */
207 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
209 /* No need to ever do this, since we can't map things. */
212 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
217 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
219 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
220 tiff_stream_write
, (void *)tiff_stream_seek
, tiff_stream_close
,
221 (void *)tiff_stream_size
, (void *)tiff_stream_map
, (void *)tiff_stream_unmap
);
225 IWICBitmapDecoder IWICBitmapDecoder_iface
;
228 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initialized is set */
234 const WICPixelFormatGUID
*format
;
241 int invert_grayscale
;
243 UINT tile_width
, tile_height
;
248 UINT resolution_unit
;
253 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
254 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
258 tiff_decode_info decode_info
;
259 INT cached_tile_x
, cached_tile_y
;
263 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
264 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
266 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
268 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
271 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
273 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
276 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
278 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
281 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
283 uint16 photometric
, bps
, samples
, planar
;
284 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
287 decode_info
->indexed
= 0;
288 decode_info
->reverse_bgr
= 0;
289 decode_info
->invert_grayscale
= 0;
290 decode_info
->tiled
= 0;
292 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
295 WARN("missing PhotometricInterpretation tag\n");
299 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
301 decode_info
->bps
= bps
;
303 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
304 if (!ret
) samples
= 1;
305 decode_info
->samples
= samples
;
311 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
312 if (!ret
) planar
= 1;
315 FIXME("unhandled planar configuration %u\n", planar
);
319 decode_info
->planar
= planar
;
323 case 0: /* WhiteIsZero */
324 decode_info
->invert_grayscale
= 1;
326 case 1: /* BlackIsZero */
329 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
332 extra_sample_count
= 1;
334 extra_samples
= &extra_sample
;
337 else if (samples
!= 1)
339 FIXME("unhandled %dbpp sample count %u\n", bps
, samples
);
343 decode_info
->bpp
= bps
* samples
;
344 decode_info
->source_bpp
= decode_info
->bpp
;
350 FIXME("unhandled 1bpp sample count %u\n", samples
);
353 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
358 FIXME("unhandled 4bpp grayscale sample count %u\n", samples
);
361 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
365 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
368 decode_info
->bpp
= 32;
370 switch(extra_samples
[0])
372 case 1: /* Associated (pre-multiplied) alpha data */
373 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
375 case 0: /* Unspecified data */
376 case 2: /* Unassociated alpha data */
377 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
380 FIXME("unhandled extra sample type %u\n", extra_samples
[0]);
386 FIXME("unhandled greyscale bit count %u\n", bps
);
391 decode_info
->bpp
= bps
* samples
;
395 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
398 extra_sample_count
= 1;
400 extra_samples
= &extra_sample
;
403 else if (samples
!= 3)
405 FIXME("unhandled RGB sample count %u\n", samples
);
412 decode_info
->reverse_bgr
= 1;
414 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
416 switch(extra_samples
[0])
418 case 1: /* Associated (pre-multiplied) alpha data */
419 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
421 case 0: /* Unspecified data */
422 case 2: /* Unassociated alpha data */
423 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
426 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
432 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
434 switch(extra_samples
[0])
436 case 1: /* Associated (pre-multiplied) alpha data */
437 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
439 case 0: /* Unspecified data */
440 case 2: /* Unassociated alpha data */
441 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
444 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
449 FIXME("unhandled RGB bit count %u\n", bps
);
453 case 3: /* RGB Palette */
456 FIXME("unhandled indexed sample count %u\n", samples
);
460 decode_info
->indexed
= 1;
461 decode_info
->bpp
= bps
;
465 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
468 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
471 FIXME("unhandled indexed bit count %u\n", bps
);
475 case 4: /* Transparency mask */
480 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
484 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
487 WARN("missing image width\n");
491 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
494 WARN("missing image length\n");
498 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
500 decode_info
->tiled
= 1;
502 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
505 WARN("missing tile height\n");
509 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
510 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
511 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
513 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
515 if (decode_info
->tile_height
> decode_info
->height
)
516 decode_info
->tile_height
= decode_info
->height
;
517 decode_info
->tile_width
= decode_info
->width
;
518 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
519 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
523 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
524 decode_info
->tile_height
= decode_info
->height
;
525 decode_info
->tile_width
= decode_info
->width
;
526 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
527 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
530 decode_info
->resolution_unit
= 0;
531 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
533 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
536 WARN("missing X resolution\n");
538 /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131)
539 * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */
540 if (!isfinite(decode_info
->xres
))
542 decode_info
->xres
= 0.0;
545 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
548 WARN("missing Y resolution\n");
550 if (!isfinite(decode_info
->yres
))
552 decode_info
->yres
= 0.0;
558 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
561 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
562 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
564 if (!ppv
) return E_INVALIDARG
;
566 if (IsEqualIID(&IID_IUnknown
, iid
) ||
567 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
569 *ppv
= &This
->IWICBitmapDecoder_iface
;
574 return E_NOINTERFACE
;
577 IUnknown_AddRef((IUnknown
*)*ppv
);
581 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
583 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
584 ULONG ref
= InterlockedIncrement(&This
->ref
);
586 TRACE("(%p) refcount=%u\n", iface
, ref
);
591 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
593 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
594 ULONG ref
= InterlockedDecrement(&This
->ref
);
596 TRACE("(%p) refcount=%u\n", iface
, ref
);
600 if (This
->tiff
) pTIFFClose(This
->tiff
);
601 if (This
->stream
) IStream_Release(This
->stream
);
602 This
->lock
.DebugInfo
->Spare
[0] = 0;
603 DeleteCriticalSection(&This
->lock
);
604 HeapFree(GetProcessHeap(), 0, This
);
610 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
615 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
617 if (!stream
|| !capability
) return E_INVALIDARG
;
619 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
620 if (hr
!= S_OK
) return hr
;
622 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
623 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
624 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
628 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
629 WICDecodeOptions cacheOptions
)
631 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
635 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
637 EnterCriticalSection(&This
->lock
);
639 if (This
->initialized
)
641 hr
= WINCODEC_ERR_WRONGSTATE
;
645 tiff
= tiff_open_stream(pIStream
, "r");
654 This
->stream
= pIStream
;
655 IStream_AddRef(pIStream
);
656 This
->initialized
= TRUE
;
659 LeaveCriticalSection(&This
->lock
);
663 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
664 GUID
*pguidContainerFormat
)
666 if (!pguidContainerFormat
) return E_INVALIDARG
;
668 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
672 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
673 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
676 IWICComponentInfo
*compinfo
;
678 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
680 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
681 if (FAILED(hr
)) return hr
;
683 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
684 (void**)ppIDecoderInfo
);
686 IWICComponentInfo_Release(compinfo
);
691 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
692 IWICPalette
*palette
)
694 TRACE("(%p,%p)\n", iface
, palette
);
695 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
698 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
699 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
701 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
705 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
706 IWICBitmapSource
**ppIBitmapSource
)
708 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
710 if (!ppIBitmapSource
) return E_INVALIDARG
;
712 *ppIBitmapSource
= NULL
;
713 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
716 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
717 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
719 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
720 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
723 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
724 IWICBitmapSource
**ppIThumbnail
)
726 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
728 if (!ppIThumbnail
) return E_INVALIDARG
;
730 *ppIThumbnail
= NULL
;
731 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
734 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
737 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
739 if (!pCount
) return E_INVALIDARG
;
741 EnterCriticalSection(&This
->lock
);
742 *pCount
= This
->tiff
? pTIFFNumberOfDirectories(This
->tiff
) : 0;
743 LeaveCriticalSection(&This
->lock
);
745 TRACE("(%p) <-- %i\n", iface
, *pCount
);
750 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
751 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
753 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
754 TiffFrameDecode
*result
;
756 tiff_decode_info decode_info
;
759 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
762 return WINCODEC_ERR_FRAMEMISSING
;
764 EnterCriticalSection(&This
->lock
);
765 res
= pTIFFSetDirectory(This
->tiff
, index
);
766 if (!res
) hr
= E_INVALIDARG
;
767 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
768 LeaveCriticalSection(&This
->lock
);
772 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
776 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
777 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
779 result
->parent
= This
;
780 result
->index
= index
;
781 result
->decode_info
= decode_info
;
782 result
->cached_tile_x
= -1;
783 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
785 if (result
->cached_tile
)
786 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
790 HeapFree(GetProcessHeap(), 0, result
);
793 else hr
= E_OUTOFMEMORY
;
796 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
801 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
802 TiffDecoder_QueryInterface
,
805 TiffDecoder_QueryCapability
,
806 TiffDecoder_Initialize
,
807 TiffDecoder_GetContainerFormat
,
808 TiffDecoder_GetDecoderInfo
,
809 TiffDecoder_CopyPalette
,
810 TiffDecoder_GetMetadataQueryReader
,
811 TiffDecoder_GetPreview
,
812 TiffDecoder_GetColorContexts
,
813 TiffDecoder_GetThumbnail
,
814 TiffDecoder_GetFrameCount
,
818 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
821 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
822 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
824 if (!ppv
) return E_INVALIDARG
;
826 if (IsEqualIID(&IID_IUnknown
, iid
) ||
827 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
828 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
830 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
832 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
834 *ppv
= &This
->IWICMetadataBlockReader_iface
;
839 return E_NOINTERFACE
;
842 IUnknown_AddRef((IUnknown
*)*ppv
);
846 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
848 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
849 ULONG ref
= InterlockedIncrement(&This
->ref
);
851 TRACE("(%p) refcount=%u\n", iface
, ref
);
856 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
858 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
859 ULONG ref
= InterlockedDecrement(&This
->ref
);
861 TRACE("(%p) refcount=%u\n", iface
, ref
);
865 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
866 HeapFree(GetProcessHeap(), 0, This
);
872 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
873 UINT
*puiWidth
, UINT
*puiHeight
)
875 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
877 *puiWidth
= This
->decode_info
.width
;
878 *puiHeight
= This
->decode_info
.height
;
880 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
885 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
886 WICPixelFormatGUID
*pPixelFormat
)
888 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
890 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
892 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
897 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
898 double *pDpiX
, double *pDpiY
)
900 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
902 if (This
->decode_info
.xres
== 0 || This
->decode_info
.yres
== 0)
904 *pDpiX
= *pDpiY
= 96.0;
908 switch (This
->decode_info
.resolution_unit
)
911 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
913 case 0: /* Not set */
914 case 1: /* Relative measurements */
916 *pDpiX
= This
->decode_info
.xres
;
917 *pDpiY
= This
->decode_info
.yres
;
919 case 3: /* Centimeter */
920 *pDpiX
= This
->decode_info
.xres
* 2.54;
921 *pDpiY
= This
->decode_info
.yres
* 2.54;
926 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
931 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
932 IWICPalette
*pIPalette
)
934 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
935 uint16
*red
, *green
, *blue
;
936 WICColor colors
[256];
937 int color_count
, ret
, i
;
939 TRACE("(%p,%p)\n", iface
, pIPalette
);
941 color_count
= 1<<This
->decode_info
.bps
;
943 EnterCriticalSection(&This
->parent
->lock
);
944 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
945 LeaveCriticalSection(&This
->parent
->lock
);
949 WARN("Couldn't read color map\n");
950 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
953 for (i
=0; i
<color_count
; i
++)
955 colors
[i
] = 0xff000000 |
956 ((red
[i
]<<8) & 0xff0000) |
957 (green
[i
] & 0xff00) |
958 ((blue
[i
]>>8) & 0xff);
961 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
964 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
970 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
972 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
979 if (This
->decode_info
.tiled
)
981 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
985 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
992 /* 8bpp grayscale with extra alpha */
993 if (hr
== S_OK
&& This
->decode_info
.source_bpp
== 16 && This
->decode_info
.samples
== 2 && This
->decode_info
.bpp
== 32)
996 DWORD
*dst
, count
= This
->decode_info
.tile_width
* This
->decode_info
.tile_height
;
998 src
= This
->cached_tile
+ This
->decode_info
.tile_width
* This
->decode_info
.tile_height
* 2 - 2;
999 dst
= (DWORD
*)(This
->cached_tile
+ This
->decode_info
.tile_size
- 4);
1003 *dst
-- = src
[0] | (src
[0] << 8) | (src
[0] << 16) | (src
[1] << 24);
1008 if (hr
== S_OK
&& This
->decode_info
.reverse_bgr
)
1010 if (This
->decode_info
.bps
== 8)
1012 UINT sample_count
= This
->decode_info
.samples
;
1014 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
1015 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
1019 if (hr
== S_OK
&& swap_bytes
&& This
->decode_info
.bps
> 8)
1021 UINT row
, i
, samples_per_row
;
1024 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
1026 switch(This
->decode_info
.bps
)
1029 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
1031 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
1032 for (i
=0; i
<samples_per_row
; i
++)
1035 sample
[1] = sample
[0];
1042 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
1047 if (hr
== S_OK
&& This
->decode_info
.invert_grayscale
)
1051 if (This
->decode_info
.samples
!= 1)
1053 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
1057 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
1059 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
1065 This
->cached_tile_x
= tile_x
;
1066 This
->cached_tile_y
= tile_y
;
1072 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
1073 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
1075 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1076 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
1077 UINT tile_x
, tile_y
;
1084 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1090 rect
.Width
= This
->decode_info
.width
;
1091 rect
.Height
= This
->decode_info
.height
;
1096 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
1097 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1098 return E_INVALIDARG
;
1101 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1103 if (cbStride
< bytesperrow
)
1104 return E_INVALIDARG
;
1106 if ((cbStride
* prc
->Height
) > cbBufferSize
)
1107 return E_INVALIDARG
;
1109 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1110 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1111 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1112 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1114 EnterCriticalSection(&This
->parent
->lock
);
1116 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1118 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1120 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1122 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1127 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1130 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1132 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1135 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1137 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1138 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1139 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1140 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1142 rc
.Width
= prc
->Width
;
1144 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1145 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1146 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1147 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1149 rc
.Height
= prc
->Height
;
1151 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1152 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1154 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1155 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1156 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1161 LeaveCriticalSection(&This
->parent
->lock
);
1162 TRACE("<-- 0x%x\n", hr
);
1168 LeaveCriticalSection(&This
->parent
->lock
);
1173 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1174 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1176 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1178 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1180 if (!ppIMetadataQueryReader
)
1181 return E_INVALIDARG
;
1183 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
1186 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1187 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1189 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1190 const BYTE
*profile
;
1194 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1196 EnterCriticalSection(&This
->parent
->lock
);
1198 if (pTIFFGetField(This
->parent
->tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
1200 if (cCount
&& ppIColorContexts
)
1202 hr
= IWICColorContext_InitializeFromMemory(*ppIColorContexts
, profile
, len
);
1205 LeaveCriticalSection(&This
->parent
->lock
);
1214 LeaveCriticalSection(&This
->parent
->lock
);
1219 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1220 IWICBitmapSource
**ppIThumbnail
)
1222 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1224 if (!ppIThumbnail
) return E_INVALIDARG
;
1226 *ppIThumbnail
= NULL
;
1227 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1230 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1231 TiffFrameDecode_QueryInterface
,
1232 TiffFrameDecode_AddRef
,
1233 TiffFrameDecode_Release
,
1234 TiffFrameDecode_GetSize
,
1235 TiffFrameDecode_GetPixelFormat
,
1236 TiffFrameDecode_GetResolution
,
1237 TiffFrameDecode_CopyPalette
,
1238 TiffFrameDecode_CopyPixels
,
1239 TiffFrameDecode_GetMetadataQueryReader
,
1240 TiffFrameDecode_GetColorContexts
,
1241 TiffFrameDecode_GetThumbnail
1244 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1245 REFIID iid
, void **ppv
)
1247 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1248 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1251 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1253 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1254 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1257 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1259 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1260 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1263 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1266 TRACE("(%p,%p)\n", iface
, guid
);
1268 if (!guid
) return E_INVALIDARG
;
1270 *guid
= GUID_ContainerFormatTiff
;
1274 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1277 TRACE("%p,%p\n", iface
, count
);
1279 if (!count
) return E_INVALIDARG
;
1285 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1288 LARGE_INTEGER dir_offset
;
1289 IWICMetadataReader
*metadata_reader
;
1290 IWICPersistStream
*persist
;
1292 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1294 hr
= IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
1295 if (FAILED(hr
)) return hr
;
1297 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1300 IWICMetadataReader_Release(metadata_reader
);
1304 EnterCriticalSection(&This
->parent
->lock
);
1306 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1307 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1310 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1311 #ifdef WORDS_BIGENDIAN
1312 DWORD persist_options
= byte_swapped
? WICPersistOptionLittleEndian
: WICPersistOptionBigEndian
;
1314 DWORD persist_options
= byte_swapped
? WICPersistOptionBigEndian
: WICPersistOptionLittleEndian
;
1316 persist_options
|= WICPersistOptionNoCacheStream
;
1317 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1319 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1322 LeaveCriticalSection(&This
->parent
->lock
);
1324 IWICPersistStream_Release(persist
);
1328 IWICMetadataReader_Release(metadata_reader
);
1332 *reader
= metadata_reader
;
1336 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1337 UINT index
, IWICMetadataReader
**reader
)
1339 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1341 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1343 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1345 return create_metadata_reader(This
, reader
);
1348 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1349 IEnumUnknown
**enum_metadata
)
1351 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1355 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1357 TiffFrameDecode_Block_QueryInterface
,
1358 TiffFrameDecode_Block_AddRef
,
1359 TiffFrameDecode_Block_Release
,
1360 TiffFrameDecode_Block_GetContainerFormat
,
1361 TiffFrameDecode_Block_GetCount
,
1362 TiffFrameDecode_Block_GetReaderByIndex
,
1363 TiffFrameDecode_Block_GetEnumerator
1366 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
1371 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1375 if (!load_libtiff())
1377 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1381 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1382 if (!This
) return E_OUTOFMEMORY
;
1384 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1386 This
->stream
= NULL
;
1387 InitializeCriticalSection(&This
->lock
);
1388 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1390 This
->initialized
= FALSE
;
1392 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1393 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1398 struct tiff_encode_format
{
1399 const WICPixelFormatGUID
*guid
;
1405 int extra_sample_type
;
1409 static const struct tiff_encode_format formats
[] = {
1410 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1411 {&GUID_WICPixelFormat24bppRGB
, 2, 8, 3, 24, 0, 0, 0},
1412 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1413 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1414 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1415 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1416 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1417 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1418 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1419 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1423 typedef struct TiffEncoder
{
1424 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1427 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1432 ULONG num_frames_committed
;
1435 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1437 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1440 typedef struct TiffFrameEncode
{
1441 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1443 TiffEncoder
*parent
;
1444 /* fields below are protected by parent->lock */
1448 const struct tiff_encode_format
*format
;
1452 WICColor palette
[256];
1456 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1458 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1461 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1464 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1465 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1467 if (!ppv
) return E_INVALIDARG
;
1469 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1470 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1472 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1477 return E_NOINTERFACE
;
1480 IUnknown_AddRef((IUnknown
*)*ppv
);
1484 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1486 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1487 ULONG ref
= InterlockedIncrement(&This
->ref
);
1489 TRACE("(%p) refcount=%u\n", iface
, ref
);
1494 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1496 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1497 ULONG ref
= InterlockedDecrement(&This
->ref
);
1499 TRACE("(%p) refcount=%u\n", iface
, ref
);
1503 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1504 HeapFree(GetProcessHeap(), 0, This
);
1510 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1511 IPropertyBag2
*pIEncoderOptions
)
1513 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1514 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1516 EnterCriticalSection(&This
->parent
->lock
);
1518 if (This
->initialized
)
1520 LeaveCriticalSection(&This
->parent
->lock
);
1521 return WINCODEC_ERR_WRONGSTATE
;
1524 This
->initialized
= TRUE
;
1526 LeaveCriticalSection(&This
->parent
->lock
);
1531 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1532 UINT uiWidth
, UINT uiHeight
)
1534 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1535 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1537 EnterCriticalSection(&This
->parent
->lock
);
1539 if (!This
->initialized
|| This
->info_written
)
1541 LeaveCriticalSection(&This
->parent
->lock
);
1542 return WINCODEC_ERR_WRONGSTATE
;
1545 This
->width
= uiWidth
;
1546 This
->height
= uiHeight
;
1548 LeaveCriticalSection(&This
->parent
->lock
);
1553 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1554 double dpiX
, double dpiY
)
1556 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1557 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1559 EnterCriticalSection(&This
->parent
->lock
);
1561 if (!This
->initialized
|| This
->info_written
)
1563 LeaveCriticalSection(&This
->parent
->lock
);
1564 return WINCODEC_ERR_WRONGSTATE
;
1570 LeaveCriticalSection(&This
->parent
->lock
);
1575 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1576 WICPixelFormatGUID
*pPixelFormat
)
1578 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1581 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1583 EnterCriticalSection(&This
->parent
->lock
);
1585 if (!This
->initialized
|| This
->info_written
)
1587 LeaveCriticalSection(&This
->parent
->lock
);
1588 return WINCODEC_ERR_WRONGSTATE
;
1591 for (i
=0; formats
[i
].guid
; i
++)
1593 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1597 if (!formats
[i
].guid
) i
= 0;
1599 This
->format
= &formats
[i
];
1600 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1602 LeaveCriticalSection(&This
->parent
->lock
);
1607 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1608 UINT cCount
, IWICColorContext
**ppIColorContext
)
1610 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1614 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1615 IWICPalette
*palette
)
1617 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1620 TRACE("(%p,%p)\n", iface
, palette
);
1622 if (!palette
) return E_INVALIDARG
;
1624 EnterCriticalSection(&This
->parent
->lock
);
1626 if (This
->initialized
)
1627 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
1629 hr
= WINCODEC_ERR_NOTINITIALIZED
;
1631 LeaveCriticalSection(&This
->parent
->lock
);
1635 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1636 IWICBitmapSource
*pIThumbnail
)
1638 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1639 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1642 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1643 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1645 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1646 BYTE
*row_data
, *swapped_data
= NULL
;
1647 UINT i
, j
, line_size
;
1649 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1651 EnterCriticalSection(&This
->parent
->lock
);
1653 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1655 LeaveCriticalSection(&This
->parent
->lock
);
1656 return WINCODEC_ERR_WRONGSTATE
;
1659 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1661 LeaveCriticalSection(&This
->parent
->lock
);
1662 return E_INVALIDARG
;
1665 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1667 if (This
->format
->reverse_bgr
)
1669 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1672 LeaveCriticalSection(&This
->parent
->lock
);
1673 return E_OUTOFMEMORY
;
1677 if (!This
->info_written
)
1679 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1680 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1681 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1682 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1684 if (This
->format
->extra_sample
)
1686 uint16 extra_samples
;
1687 extra_samples
= This
->format
->extra_sample_type
;
1689 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1692 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1693 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1695 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1697 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1698 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1699 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1702 This
->info_written
= TRUE
;
1705 for (i
=0; i
<lineCount
; i
++)
1707 row_data
= pbPixels
+ i
* cbStride
;
1709 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1711 memcpy(swapped_data
, row_data
, line_size
);
1712 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1715 temp
= swapped_data
[j
];
1716 swapped_data
[j
] = swapped_data
[j
+2];
1717 swapped_data
[j
+2] = temp
;
1719 row_data
= swapped_data
;
1722 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1725 This
->lines_written
+= lineCount
;
1727 LeaveCriticalSection(&This
->parent
->lock
);
1729 HeapFree(GetProcessHeap(), 0, swapped_data
);
1734 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1735 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1737 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1740 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1742 if (!This
->initialized
)
1743 return WINCODEC_ERR_WRONGSTATE
;
1745 hr
= configure_write_source(iface
, pIBitmapSource
, prc
,
1746 This
->format
? This
->format
->guid
: NULL
, This
->width
, This
->height
,
1747 This
->xres
, This
->yres
);
1751 hr
= write_source(iface
, pIBitmapSource
, prc
,
1752 This
->format
->guid
, This
->format
->bpp
, This
->width
, This
->height
);
1758 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1760 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1762 TRACE("(%p)\n", iface
);
1764 EnterCriticalSection(&This
->parent
->lock
);
1766 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1768 LeaveCriticalSection(&This
->parent
->lock
);
1769 return WINCODEC_ERR_WRONGSTATE
;
1772 /* libtiff will commit the data when creating a new frame or closing the file */
1774 This
->committed
= TRUE
;
1775 This
->parent
->num_frames_committed
++;
1777 LeaveCriticalSection(&This
->parent
->lock
);
1782 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1783 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1785 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1789 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
1790 TiffFrameEncode_QueryInterface
,
1791 TiffFrameEncode_AddRef
,
1792 TiffFrameEncode_Release
,
1793 TiffFrameEncode_Initialize
,
1794 TiffFrameEncode_SetSize
,
1795 TiffFrameEncode_SetResolution
,
1796 TiffFrameEncode_SetPixelFormat
,
1797 TiffFrameEncode_SetColorContexts
,
1798 TiffFrameEncode_SetPalette
,
1799 TiffFrameEncode_SetThumbnail
,
1800 TiffFrameEncode_WritePixels
,
1801 TiffFrameEncode_WriteSource
,
1802 TiffFrameEncode_Commit
,
1803 TiffFrameEncode_GetMetadataQueryWriter
1806 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1809 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1810 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1812 if (!ppv
) return E_INVALIDARG
;
1814 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1815 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1817 *ppv
= &This
->IWICBitmapEncoder_iface
;
1822 return E_NOINTERFACE
;
1825 IUnknown_AddRef((IUnknown
*)*ppv
);
1829 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
1831 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1832 ULONG ref
= InterlockedIncrement(&This
->ref
);
1834 TRACE("(%p) refcount=%u\n", iface
, ref
);
1839 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
1841 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1842 ULONG ref
= InterlockedDecrement(&This
->ref
);
1844 TRACE("(%p) refcount=%u\n", iface
, ref
);
1848 if (This
->tiff
) pTIFFClose(This
->tiff
);
1849 if (This
->stream
) IStream_Release(This
->stream
);
1850 This
->lock
.DebugInfo
->Spare
[0] = 0;
1851 DeleteCriticalSection(&This
->lock
);
1852 HeapFree(GetProcessHeap(), 0, This
);
1858 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
1859 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1861 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1865 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1867 EnterCriticalSection(&This
->lock
);
1869 if (This
->initialized
|| This
->committed
)
1871 hr
= WINCODEC_ERR_WRONGSTATE
;
1875 tiff
= tiff_open_stream(pIStream
, "w");
1884 This
->stream
= pIStream
;
1885 IStream_AddRef(pIStream
);
1886 This
->initialized
= TRUE
;
1889 LeaveCriticalSection(&This
->lock
);
1893 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1894 GUID
*pguidContainerFormat
)
1896 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
1900 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1901 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1903 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1907 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1908 UINT cCount
, IWICColorContext
**ppIColorContext
)
1910 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1914 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
1916 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1919 TRACE("(%p,%p)\n", iface
, palette
);
1921 EnterCriticalSection(&This
->lock
);
1923 hr
= This
->stream
? WINCODEC_ERR_UNSUPPORTEDOPERATION
: WINCODEC_ERR_NOTINITIALIZED
;
1925 LeaveCriticalSection(&This
->lock
);
1930 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1932 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1933 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1936 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1938 TRACE("(%p,%p)\n", iface
, pIPreview
);
1939 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1942 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1943 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1945 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1946 TiffFrameEncode
*result
;
1947 static const PROPBAG2 opts
[2] =
1949 { PROPBAG2_TYPE_DATA
, VT_UI1
, 0, 0, (LPOLESTR
)wszTiffCompressionMethod
},
1950 { PROPBAG2_TYPE_DATA
, VT_R4
, 0, 0, (LPOLESTR
)wszCompressionQuality
},
1954 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1956 EnterCriticalSection(&This
->lock
);
1958 if (!This
->initialized
|| This
->committed
)
1960 hr
= WINCODEC_ERR_WRONGSTATE
;
1962 else if (This
->num_frames
!= This
->num_frames_committed
)
1964 FIXME("New frame created before previous frame was committed\n");
1968 if (ppIEncoderOptions
&& SUCCEEDED(hr
))
1970 hr
= CreatePropertyBag2(opts
, sizeof(opts
)/sizeof(opts
[0]), ppIEncoderOptions
);
1976 V_UNION(&v
, bVal
) = WICTiffCompressionDontCare
;
1977 hr
= IPropertyBag2_Write(*ppIEncoderOptions
, 1, (PROPBAG2
*)opts
, &v
);
1981 IPropertyBag2_Release(*ppIEncoderOptions
);
1982 *ppIEncoderOptions
= NULL
;
1989 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
1993 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
1995 result
->parent
= This
;
1996 result
->initialized
= FALSE
;
1997 result
->info_written
= FALSE
;
1998 result
->committed
= FALSE
;
1999 result
->format
= NULL
;
2004 result
->lines_written
= 0;
2007 IWICBitmapEncoder_AddRef(iface
);
2008 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
2010 if (This
->num_frames
!= 0)
2011 pTIFFWriteDirectory(This
->tiff
);
2020 IPropertyBag2_Release(*ppIEncoderOptions
);
2021 *ppIEncoderOptions
= NULL
;
2025 LeaveCriticalSection(&This
->lock
);
2030 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
2032 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2034 TRACE("(%p)\n", iface
);
2036 EnterCriticalSection(&This
->lock
);
2038 if (!This
->initialized
|| This
->committed
)
2040 LeaveCriticalSection(&This
->lock
);
2041 return WINCODEC_ERR_WRONGSTATE
;
2044 pTIFFClose(This
->tiff
);
2045 IStream_Release(This
->stream
);
2046 This
->stream
= NULL
;
2049 This
->committed
= TRUE
;
2051 LeaveCriticalSection(&This
->lock
);
2056 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
2057 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
2059 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
2063 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
2064 TiffEncoder_QueryInterface
,
2066 TiffEncoder_Release
,
2067 TiffEncoder_Initialize
,
2068 TiffEncoder_GetContainerFormat
,
2069 TiffEncoder_GetEncoderInfo
,
2070 TiffEncoder_SetColorContexts
,
2071 TiffEncoder_SetPalette
,
2072 TiffEncoder_SetThumbnail
,
2073 TiffEncoder_SetPreview
,
2074 TiffEncoder_CreateNewFrame
,
2076 TiffEncoder_GetMetadataQueryWriter
2079 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2084 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
2088 if (!load_libtiff())
2090 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
2094 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
2095 if (!This
) return E_OUTOFMEMORY
;
2097 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
2099 This
->stream
= NULL
;
2100 InitializeCriticalSection(&This
->lock
);
2101 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
2103 This
->initialized
= FALSE
;
2104 This
->num_frames
= 0;
2105 This
->num_frames_committed
= 0;
2106 This
->committed
= FALSE
;
2108 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2109 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
2114 #else /* !SONAME_LIBTIFF */
2116 HRESULT
TiffDecoder_CreateInstance(REFIID iid
, void** ppv
)
2118 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
2122 HRESULT
TiffEncoder_CreateInstance(REFIID iid
, void** ppv
)
2124 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");