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 #define WIN32_NO_STATUS
21 #define COM_NO_WINDOWS_H
24 #include <wine/port.h>
39 //#include "wincodec.h"
40 #include <wincodecsdk.h>
42 #include "wincodecs_private.h"
44 #include <wine/debug.h>
45 #include <wine/library.h>
47 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
51 static CRITICAL_SECTION init_tiff_cs
;
52 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
55 { &init_tiff_cs_debug
.ProcessLocksList
,
56 &init_tiff_cs_debug
.ProcessLocksList
},
57 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
59 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
61 static void *libtiff_handle
;
62 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
63 MAKE_FUNCPTR(TIFFClientOpen
);
64 MAKE_FUNCPTR(TIFFClose
);
65 MAKE_FUNCPTR(TIFFCurrentDirOffset
);
66 MAKE_FUNCPTR(TIFFGetField
);
67 MAKE_FUNCPTR(TIFFIsByteSwapped
);
68 MAKE_FUNCPTR(TIFFNumberOfDirectories
);
69 MAKE_FUNCPTR(TIFFReadDirectory
);
70 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
71 MAKE_FUNCPTR(TIFFReadEncodedTile
);
72 MAKE_FUNCPTR(TIFFSetDirectory
);
73 MAKE_FUNCPTR(TIFFSetField
);
74 MAKE_FUNCPTR(TIFFWriteDirectory
);
75 MAKE_FUNCPTR(TIFFWriteScanline
);
78 static void *load_libtiff(void)
82 EnterCriticalSection(&init_tiff_cs
);
84 if (!libtiff_handle
&&
85 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
87 void * (*pTIFFSetWarningHandler
)(void *);
88 void * (*pTIFFSetWarningHandlerExt
)(void *);
90 #define LOAD_FUNCPTR(f) \
91 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
92 ERR("failed to load symbol %s\n", #f); \
93 libtiff_handle = NULL; \
94 LeaveCriticalSection(&init_tiff_cs); \
97 LOAD_FUNCPTR(TIFFClientOpen
);
98 LOAD_FUNCPTR(TIFFClose
);
99 LOAD_FUNCPTR(TIFFCurrentDirOffset
);
100 LOAD_FUNCPTR(TIFFGetField
);
101 LOAD_FUNCPTR(TIFFIsByteSwapped
);
102 LOAD_FUNCPTR(TIFFNumberOfDirectories
);
103 LOAD_FUNCPTR(TIFFReadDirectory
);
104 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
105 LOAD_FUNCPTR(TIFFReadEncodedTile
);
106 LOAD_FUNCPTR(TIFFSetDirectory
);
107 LOAD_FUNCPTR(TIFFSetField
);
108 LOAD_FUNCPTR(TIFFWriteDirectory
);
109 LOAD_FUNCPTR(TIFFWriteScanline
);
112 if ((pTIFFSetWarningHandler
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandler", NULL
, 0)))
113 pTIFFSetWarningHandler(NULL
);
114 if ((pTIFFSetWarningHandlerExt
= wine_dlsym(libtiff_handle
, "TIFFSetWarningHandlerExt", NULL
, 0)))
115 pTIFFSetWarningHandlerExt(NULL
);
118 result
= libtiff_handle
;
120 LeaveCriticalSection(&init_tiff_cs
);
124 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
126 IStream
*stream
= (IStream
*)client_data
;
130 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
131 if (FAILED(hr
)) bytes_read
= 0;
135 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
137 IStream
*stream
= (IStream
*)client_data
;
141 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
142 if (FAILED(hr
)) bytes_written
= 0;
143 return bytes_written
;
146 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
148 IStream
*stream
= (IStream
*)client_data
;
151 ULARGE_INTEGER new_position
;
154 move
.QuadPart
= offset
;
158 origin
= STREAM_SEEK_SET
;
161 origin
= STREAM_SEEK_CUR
;
164 origin
= STREAM_SEEK_END
;
167 ERR("unknown whence value %i\n", whence
);
171 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
172 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
176 static int tiff_stream_close(thandle_t client_data
)
178 /* Caller is responsible for releasing the stream object. */
182 static toff_t
tiff_stream_size(thandle_t client_data
)
184 IStream
*stream
= (IStream
*)client_data
;
188 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
190 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
194 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
196 /* Cannot mmap streams */
200 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
202 /* No need to ever do this, since we can't map things. */
205 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
210 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
212 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
213 tiff_stream_write
, tiff_stream_seek
, tiff_stream_close
,
214 tiff_stream_size
, tiff_stream_map
, tiff_stream_unmap
);
218 IWICBitmapDecoder IWICBitmapDecoder_iface
;
221 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initiailzed is set */
227 const WICPixelFormatGUID
*format
;
234 int invert_grayscale
;
236 UINT tile_width
, tile_height
;
241 UINT resolution_unit
;
246 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
247 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
251 tiff_decode_info decode_info
;
252 INT cached_tile_x
, cached_tile_y
;
256 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
257 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
259 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
261 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
264 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
266 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
269 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
271 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
274 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
276 uint16 photometric
, bps
, samples
, planar
;
277 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
280 decode_info
->indexed
= 0;
281 decode_info
->reverse_bgr
= 0;
282 decode_info
->invert_grayscale
= 0;
283 decode_info
->tiled
= 0;
285 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
288 WARN("missing PhotometricInterpretation tag\n");
292 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
294 decode_info
->bps
= bps
;
296 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
297 if (!ret
) samples
= 1;
298 decode_info
->samples
= samples
;
304 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
305 if (!ret
) planar
= 1;
308 FIXME("unhandled planar configuration %u\n", planar
);
312 decode_info
->planar
= planar
;
316 case 0: /* WhiteIsZero */
317 decode_info
->invert_grayscale
= 1;
319 case 1: /* BlackIsZero */
322 FIXME("unhandled grayscale sample count %u\n", samples
);
326 decode_info
->bpp
= bps
;
330 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
333 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
336 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
339 FIXME("unhandled greyscale bit count %u\n", bps
);
344 decode_info
->bpp
= bps
* samples
;
348 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
351 extra_sample_count
= 1;
353 extra_samples
= &extra_sample
;
356 else if (samples
!= 3)
358 FIXME("unhandled RGB sample count %u\n", samples
);
365 decode_info
->reverse_bgr
= 1;
367 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
369 switch(extra_samples
[0])
371 case 1: /* Associated (pre-multiplied) alpha data */
372 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
374 case 0: /* Unspecified data */
375 case 2: /* Unassociated alpha data */
376 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
379 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
385 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
387 switch(extra_samples
[0])
389 case 1: /* Associated (pre-multiplied) alpha data */
390 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
392 case 0: /* Unspecified data */
393 case 2: /* Unassociated alpha data */
394 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
397 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
402 FIXME("unhandled RGB bit count %u\n", bps
);
406 case 3: /* RGB Palette */
409 FIXME("unhandled indexed sample count %u\n", samples
);
413 decode_info
->indexed
= 1;
414 decode_info
->bpp
= bps
;
418 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
421 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
424 FIXME("unhandled indexed bit count %u\n", bps
);
428 case 4: /* Transparency mask */
433 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
437 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
440 WARN("missing image width\n");
444 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
447 WARN("missing image length\n");
451 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
453 decode_info
->tiled
= 1;
455 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
458 WARN("missing tile height\n");
462 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
463 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
464 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
466 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
468 if (decode_info
->tile_height
> decode_info
->height
)
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
;
476 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
477 decode_info
->tile_height
= decode_info
->height
;
478 decode_info
->tile_width
= decode_info
->width
;
479 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
480 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
483 decode_info
->resolution_unit
= 0;
484 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
485 if (decode_info
->resolution_unit
!= 0)
487 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
490 WARN("missing X resolution\n");
491 decode_info
->resolution_unit
= 0;
494 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
497 WARN("missing Y resolution\n");
498 decode_info
->resolution_unit
= 0;
505 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
508 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
509 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
511 if (!ppv
) return E_INVALIDARG
;
513 if (IsEqualIID(&IID_IUnknown
, iid
) ||
514 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
516 *ppv
= &This
->IWICBitmapDecoder_iface
;
521 return E_NOINTERFACE
;
524 IUnknown_AddRef((IUnknown
*)*ppv
);
528 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
530 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
531 ULONG ref
= InterlockedIncrement(&This
->ref
);
533 TRACE("(%p) refcount=%u\n", iface
, ref
);
538 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
540 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
541 ULONG ref
= InterlockedDecrement(&This
->ref
);
543 TRACE("(%p) refcount=%u\n", iface
, ref
);
547 if (This
->tiff
) pTIFFClose(This
->tiff
);
548 if (This
->stream
) IStream_Release(This
->stream
);
549 This
->lock
.DebugInfo
->Spare
[0] = 0;
550 DeleteCriticalSection(&This
->lock
);
551 HeapFree(GetProcessHeap(), 0, This
);
557 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
562 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
564 if (!stream
|| !capability
) return E_INVALIDARG
;
566 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
567 if (hr
!= S_OK
) return hr
;
569 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
570 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
571 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
575 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
576 WICDecodeOptions cacheOptions
)
578 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
582 TRACE("(%p,%p,%x): stub\n", iface
, pIStream
, cacheOptions
);
584 EnterCriticalSection(&This
->lock
);
586 if (This
->initialized
)
588 hr
= WINCODEC_ERR_WRONGSTATE
;
592 tiff
= tiff_open_stream(pIStream
, "r");
601 This
->stream
= pIStream
;
602 IStream_AddRef(pIStream
);
603 This
->initialized
= TRUE
;
606 LeaveCriticalSection(&This
->lock
);
610 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
611 GUID
*pguidContainerFormat
)
613 if (!pguidContainerFormat
) return E_INVALIDARG
;
615 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
619 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
620 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
623 IWICComponentInfo
*compinfo
;
625 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
627 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
628 if (FAILED(hr
)) return hr
;
630 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
631 (void**)ppIDecoderInfo
);
633 IWICComponentInfo_Release(compinfo
);
638 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
639 IWICPalette
*pIPalette
)
641 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
645 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
646 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
648 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
652 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
653 IWICBitmapSource
**ppIBitmapSource
)
655 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
657 if (!ppIBitmapSource
) return E_INVALIDARG
;
659 *ppIBitmapSource
= NULL
;
660 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
663 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
664 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
666 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
667 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
670 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
671 IWICBitmapSource
**ppIThumbnail
)
673 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
675 if (!ppIThumbnail
) return E_INVALIDARG
;
677 *ppIThumbnail
= NULL
;
678 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
681 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
684 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
686 if (!pCount
) return E_INVALIDARG
;
688 EnterCriticalSection(&This
->lock
);
689 *pCount
= This
->tiff
? pTIFFNumberOfDirectories(This
->tiff
) : 0;
690 LeaveCriticalSection(&This
->lock
);
692 TRACE("(%p) <-- %i\n", iface
, *pCount
);
697 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
698 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
700 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
701 TiffFrameDecode
*result
;
703 tiff_decode_info decode_info
;
706 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
709 return WINCODEC_ERR_FRAMEMISSING
;
711 EnterCriticalSection(&This
->lock
);
712 res
= pTIFFSetDirectory(This
->tiff
, index
);
713 if (!res
) hr
= E_INVALIDARG
;
714 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
715 LeaveCriticalSection(&This
->lock
);
719 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
723 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
724 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
726 result
->parent
= This
;
727 result
->index
= index
;
728 result
->decode_info
= decode_info
;
729 result
->cached_tile_x
= -1;
730 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
732 if (result
->cached_tile
)
733 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
737 HeapFree(GetProcessHeap(), 0, result
);
740 else hr
= E_OUTOFMEMORY
;
743 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
748 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
749 TiffDecoder_QueryInterface
,
752 TiffDecoder_QueryCapability
,
753 TiffDecoder_Initialize
,
754 TiffDecoder_GetContainerFormat
,
755 TiffDecoder_GetDecoderInfo
,
756 TiffDecoder_CopyPalette
,
757 TiffDecoder_GetMetadataQueryReader
,
758 TiffDecoder_GetPreview
,
759 TiffDecoder_GetColorContexts
,
760 TiffDecoder_GetThumbnail
,
761 TiffDecoder_GetFrameCount
,
765 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
768 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
769 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
771 if (!ppv
) return E_INVALIDARG
;
773 if (IsEqualIID(&IID_IUnknown
, iid
) ||
774 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
775 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
777 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
779 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
781 *ppv
= &This
->IWICMetadataBlockReader_iface
;
786 return E_NOINTERFACE
;
789 IUnknown_AddRef((IUnknown
*)*ppv
);
793 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
795 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
796 ULONG ref
= InterlockedIncrement(&This
->ref
);
798 TRACE("(%p) refcount=%u\n", iface
, ref
);
803 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
805 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
806 ULONG ref
= InterlockedDecrement(&This
->ref
);
808 TRACE("(%p) refcount=%u\n", iface
, ref
);
812 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
813 HeapFree(GetProcessHeap(), 0, This
);
819 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
820 UINT
*puiWidth
, UINT
*puiHeight
)
822 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
824 *puiWidth
= This
->decode_info
.width
;
825 *puiHeight
= This
->decode_info
.height
;
827 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
832 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
833 WICPixelFormatGUID
*pPixelFormat
)
835 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
837 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
839 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
844 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
845 double *pDpiX
, double *pDpiY
)
847 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
849 switch (This
->decode_info
.resolution_unit
)
852 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
854 case 0: /* Not set */
855 *pDpiX
= *pDpiY
= 96.0;
857 case 1: /* Relative measurements */
859 *pDpiY
= 96.0 * This
->decode_info
.yres
/ This
->decode_info
.xres
;
862 *pDpiX
= This
->decode_info
.xres
;
863 *pDpiY
= This
->decode_info
.yres
;
865 case 3: /* Centimeter */
866 *pDpiX
= This
->decode_info
.xres
/ 2.54;
867 *pDpiY
= This
->decode_info
.yres
/ 2.54;
871 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
876 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
877 IWICPalette
*pIPalette
)
879 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
880 uint16
*red
, *green
, *blue
;
881 WICColor colors
[256];
882 int color_count
, ret
, i
;
884 TRACE("(%p,%p)\n", iface
, pIPalette
);
886 color_count
= 1<<This
->decode_info
.bps
;
888 EnterCriticalSection(&This
->parent
->lock
);
889 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
890 LeaveCriticalSection(&This
->parent
->lock
);
894 WARN("Couldn't read color map\n");
895 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
898 for (i
=0; i
<color_count
; i
++)
900 colors
[i
] = 0xff000000 |
901 ((red
[i
]<<8) & 0xff0000) |
902 (green
[i
] & 0xff00) |
903 ((blue
[i
]>>8) & 0xff);
906 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
909 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
915 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
917 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
924 if (This
->decode_info
.tiled
)
926 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
930 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
937 if (hr
== S_OK
&& This
->decode_info
.reverse_bgr
)
939 if (This
->decode_info
.bps
== 8)
941 UINT sample_count
= This
->decode_info
.samples
;
943 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
944 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
948 if (hr
== S_OK
&& swap_bytes
&& This
->decode_info
.bps
> 8)
950 UINT row
, i
, samples_per_row
;
953 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
955 switch(This
->decode_info
.bps
)
958 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
960 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
961 for (i
=0; i
<samples_per_row
; i
++)
964 sample
[1] = sample
[0];
971 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
976 if (hr
== S_OK
&& This
->decode_info
.invert_grayscale
)
980 if (This
->decode_info
.samples
!= 1)
982 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
986 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
988 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
994 This
->cached_tile_x
= tile_x
;
995 This
->cached_tile_y
= tile_y
;
1001 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
1002 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
1004 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
1005 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
1006 UINT tile_x
, tile_y
;
1013 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1019 rect
.Width
= This
->decode_info
.width
;
1020 rect
.Height
= This
->decode_info
.height
;
1025 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
1026 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1027 return E_INVALIDARG
;
1030 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1032 if (cbStride
< bytesperrow
)
1033 return E_INVALIDARG
;
1035 if ((cbStride
* prc
->Height
) > cbBufferSize
)
1036 return E_INVALIDARG
;
1038 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1039 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1040 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1041 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1043 EnterCriticalSection(&This
->parent
->lock
);
1045 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1047 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1049 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1051 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1056 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1059 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1061 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1064 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1066 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1067 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1068 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1069 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1071 rc
.Width
= prc
->Width
;
1073 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1074 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1075 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1076 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1078 rc
.Height
= prc
->Height
;
1080 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1081 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1083 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1084 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1085 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1090 LeaveCriticalSection(&This
->parent
->lock
);
1091 TRACE("<-- 0x%x\n", hr
);
1097 LeaveCriticalSection(&This
->parent
->lock
);
1102 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1103 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1105 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
1109 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1110 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1112 FIXME("(%p,%u,%p,%p): stub\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1113 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1116 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1117 IWICBitmapSource
**ppIThumbnail
)
1119 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1121 if (!ppIThumbnail
) return E_INVALIDARG
;
1123 *ppIThumbnail
= NULL
;
1124 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1127 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1128 TiffFrameDecode_QueryInterface
,
1129 TiffFrameDecode_AddRef
,
1130 TiffFrameDecode_Release
,
1131 TiffFrameDecode_GetSize
,
1132 TiffFrameDecode_GetPixelFormat
,
1133 TiffFrameDecode_GetResolution
,
1134 TiffFrameDecode_CopyPalette
,
1135 TiffFrameDecode_CopyPixels
,
1136 TiffFrameDecode_GetMetadataQueryReader
,
1137 TiffFrameDecode_GetColorContexts
,
1138 TiffFrameDecode_GetThumbnail
1141 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1142 REFIID iid
, void **ppv
)
1144 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1145 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1148 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1150 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1151 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1154 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1156 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1157 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1160 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1163 TRACE("(%p,%p)\n", iface
, guid
);
1165 if (!guid
) return E_INVALIDARG
;
1167 *guid
= GUID_ContainerFormatTiff
;
1171 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1174 TRACE("%p,%p\n", iface
, count
);
1176 if (!count
) return E_INVALIDARG
;
1182 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1185 LARGE_INTEGER dir_offset
;
1186 IWICMetadataReader
*metadata_reader
;
1187 IWICPersistStream
*persist
;
1189 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1191 hr
= CoCreateInstance(&CLSID_WICIfdMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
1192 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
1193 if (FAILED(hr
)) return hr
;
1195 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1198 IWICMetadataReader_Release(metadata_reader
);
1202 EnterCriticalSection(&This
->parent
->lock
);
1204 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1205 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1208 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1209 #ifdef WORDS_BIGENDIAN
1210 DWORD persist_options
= byte_swapped
? WICPersistOptionsLittleEndian
: WICPersistOptionsBigEndian
;
1212 DWORD persist_options
= byte_swapped
? WICPersistOptionsBigEndian
: WICPersistOptionsLittleEndian
;
1214 persist_options
|= WICPersistOptionsNoCacheStream
;
1215 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1217 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1220 LeaveCriticalSection(&This
->parent
->lock
);
1222 IWICPersistStream_Release(persist
);
1226 IWICMetadataReader_Release(metadata_reader
);
1230 *reader
= metadata_reader
;
1234 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1235 UINT index
, IWICMetadataReader
**reader
)
1237 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1239 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1241 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1243 return create_metadata_reader(This
, reader
);
1246 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1247 IEnumUnknown
**enum_metadata
)
1249 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1253 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1255 TiffFrameDecode_Block_QueryInterface
,
1256 TiffFrameDecode_Block_AddRef
,
1257 TiffFrameDecode_Block_Release
,
1258 TiffFrameDecode_Block_GetContainerFormat
,
1259 TiffFrameDecode_Block_GetCount
,
1260 TiffFrameDecode_Block_GetReaderByIndex
,
1261 TiffFrameDecode_Block_GetEnumerator
1264 HRESULT
TiffDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1269 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1273 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1275 if (!load_libtiff())
1277 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1281 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1282 if (!This
) return E_OUTOFMEMORY
;
1284 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1286 This
->stream
= NULL
;
1287 InitializeCriticalSection(&This
->lock
);
1288 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1290 This
->initialized
= FALSE
;
1292 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1293 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1298 struct tiff_encode_format
{
1299 const WICPixelFormatGUID
*guid
;
1305 int extra_sample_type
;
1309 static const struct tiff_encode_format formats
[] = {
1310 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1311 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1312 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1313 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1314 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1315 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1316 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1317 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1318 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1322 typedef struct TiffEncoder
{
1323 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1326 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1331 ULONG num_frames_committed
;
1334 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1336 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1339 typedef struct TiffFrameEncode
{
1340 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1342 TiffEncoder
*parent
;
1343 /* fields below are protected by parent->lock */
1347 const struct tiff_encode_format
*format
;
1353 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1355 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1358 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1361 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1362 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1364 if (!ppv
) return E_INVALIDARG
;
1366 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1367 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1369 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1374 return E_NOINTERFACE
;
1377 IUnknown_AddRef((IUnknown
*)*ppv
);
1381 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1383 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1384 ULONG ref
= InterlockedIncrement(&This
->ref
);
1386 TRACE("(%p) refcount=%u\n", iface
, ref
);
1391 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1393 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1394 ULONG ref
= InterlockedDecrement(&This
->ref
);
1396 TRACE("(%p) refcount=%u\n", iface
, ref
);
1400 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1401 HeapFree(GetProcessHeap(), 0, This
);
1407 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1408 IPropertyBag2
*pIEncoderOptions
)
1410 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1411 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1413 EnterCriticalSection(&This
->parent
->lock
);
1415 if (This
->initialized
)
1417 LeaveCriticalSection(&This
->parent
->lock
);
1418 return WINCODEC_ERR_WRONGSTATE
;
1421 This
->initialized
= TRUE
;
1423 LeaveCriticalSection(&This
->parent
->lock
);
1428 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1429 UINT uiWidth
, UINT uiHeight
)
1431 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1432 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1434 EnterCriticalSection(&This
->parent
->lock
);
1436 if (!This
->initialized
|| This
->info_written
)
1438 LeaveCriticalSection(&This
->parent
->lock
);
1439 return WINCODEC_ERR_WRONGSTATE
;
1442 This
->width
= uiWidth
;
1443 This
->height
= uiHeight
;
1445 LeaveCriticalSection(&This
->parent
->lock
);
1450 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1451 double dpiX
, double dpiY
)
1453 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1454 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1456 EnterCriticalSection(&This
->parent
->lock
);
1458 if (!This
->initialized
|| This
->info_written
)
1460 LeaveCriticalSection(&This
->parent
->lock
);
1461 return WINCODEC_ERR_WRONGSTATE
;
1467 LeaveCriticalSection(&This
->parent
->lock
);
1472 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1473 WICPixelFormatGUID
*pPixelFormat
)
1475 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1478 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1480 EnterCriticalSection(&This
->parent
->lock
);
1482 if (!This
->initialized
|| This
->info_written
)
1484 LeaveCriticalSection(&This
->parent
->lock
);
1485 return WINCODEC_ERR_WRONGSTATE
;
1488 for (i
=0; formats
[i
].guid
; i
++)
1490 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1494 if (!formats
[i
].guid
) i
= 0;
1496 This
->format
= &formats
[i
];
1497 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1499 LeaveCriticalSection(&This
->parent
->lock
);
1504 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1505 UINT cCount
, IWICColorContext
**ppIColorContext
)
1507 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1511 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1512 IWICPalette
*pIPalette
)
1514 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
1515 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1518 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1519 IWICBitmapSource
*pIThumbnail
)
1521 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1522 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1525 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1526 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1528 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1529 BYTE
*row_data
, *swapped_data
= NULL
;
1530 UINT i
, j
, line_size
;
1532 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1534 EnterCriticalSection(&This
->parent
->lock
);
1536 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1538 LeaveCriticalSection(&This
->parent
->lock
);
1539 return WINCODEC_ERR_WRONGSTATE
;
1542 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1544 LeaveCriticalSection(&This
->parent
->lock
);
1545 return E_INVALIDARG
;
1548 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1550 if (This
->format
->reverse_bgr
)
1552 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1555 LeaveCriticalSection(&This
->parent
->lock
);
1556 return E_OUTOFMEMORY
;
1560 if (!This
->info_written
)
1562 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1563 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1564 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1565 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1567 if (This
->format
->extra_sample
)
1569 uint16 extra_samples
;
1570 extra_samples
= This
->format
->extra_sample_type
;
1572 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1575 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1576 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1578 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1580 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1581 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1582 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1585 This
->info_written
= TRUE
;
1588 for (i
=0; i
<lineCount
; i
++)
1590 row_data
= pbPixels
+ i
* cbStride
;
1592 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1594 memcpy(swapped_data
, row_data
, line_size
);
1595 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1598 temp
= swapped_data
[j
];
1599 swapped_data
[j
] = swapped_data
[j
+2];
1600 swapped_data
[j
+2] = temp
;
1602 row_data
= swapped_data
;
1605 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1608 This
->lines_written
+= lineCount
;
1610 LeaveCriticalSection(&This
->parent
->lock
);
1612 HeapFree(GetProcessHeap(), 0, swapped_data
);
1617 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1618 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1620 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1623 WICPixelFormatGUID guid
;
1627 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1629 if (!This
->initialized
|| !This
->width
|| !This
->height
)
1630 return WINCODEC_ERR_WRONGSTATE
;
1634 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1635 if (FAILED(hr
)) return hr
;
1636 hr
= IWICBitmapFrameEncode_SetPixelFormat(iface
, &guid
);
1637 if (FAILED(hr
)) return hr
;
1640 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1641 if (FAILED(hr
)) return hr
;
1642 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
1644 /* FIXME: should use WICConvertBitmapSource to convert */
1645 ERR("format %s unsupported\n", debugstr_guid(&guid
));
1649 if (This
->xres
== 0.0 || This
->yres
== 0.0)
1652 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
1653 if (FAILED(hr
)) return hr
;
1654 hr
= IWICBitmapFrameEncode_SetResolution(iface
, xres
, yres
);
1655 if (FAILED(hr
)) return hr
;
1661 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
1662 if (FAILED(hr
)) return hr
;
1670 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
1672 stride
= (This
->format
->bpp
* This
->width
+ 7)/8;
1674 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
1675 if (!pixeldata
) return E_OUTOFMEMORY
;
1677 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
1678 stride
*prc
->Height
, pixeldata
);
1682 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
1683 stride
*prc
->Height
, pixeldata
);
1686 HeapFree(GetProcessHeap(), 0, pixeldata
);
1691 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1693 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1695 TRACE("(%p)\n", iface
);
1697 EnterCriticalSection(&This
->parent
->lock
);
1699 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1701 LeaveCriticalSection(&This
->parent
->lock
);
1702 return WINCODEC_ERR_WRONGSTATE
;
1705 /* libtiff will commit the data when creating a new frame or closing the file */
1707 This
->committed
= TRUE
;
1708 This
->parent
->num_frames_committed
++;
1710 LeaveCriticalSection(&This
->parent
->lock
);
1715 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1716 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1718 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1722 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
1723 TiffFrameEncode_QueryInterface
,
1724 TiffFrameEncode_AddRef
,
1725 TiffFrameEncode_Release
,
1726 TiffFrameEncode_Initialize
,
1727 TiffFrameEncode_SetSize
,
1728 TiffFrameEncode_SetResolution
,
1729 TiffFrameEncode_SetPixelFormat
,
1730 TiffFrameEncode_SetColorContexts
,
1731 TiffFrameEncode_SetPalette
,
1732 TiffFrameEncode_SetThumbnail
,
1733 TiffFrameEncode_WritePixels
,
1734 TiffFrameEncode_WriteSource
,
1735 TiffFrameEncode_Commit
,
1736 TiffFrameEncode_GetMetadataQueryWriter
1739 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1742 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1743 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1745 if (!ppv
) return E_INVALIDARG
;
1747 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1748 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1750 *ppv
= &This
->IWICBitmapEncoder_iface
;
1755 return E_NOINTERFACE
;
1758 IUnknown_AddRef((IUnknown
*)*ppv
);
1762 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
1764 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1765 ULONG ref
= InterlockedIncrement(&This
->ref
);
1767 TRACE("(%p) refcount=%u\n", iface
, ref
);
1772 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
1774 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1775 ULONG ref
= InterlockedDecrement(&This
->ref
);
1777 TRACE("(%p) refcount=%u\n", iface
, ref
);
1781 if (This
->tiff
) pTIFFClose(This
->tiff
);
1782 if (This
->stream
) IStream_Release(This
->stream
);
1783 This
->lock
.DebugInfo
->Spare
[0] = 0;
1784 DeleteCriticalSection(&This
->lock
);
1785 HeapFree(GetProcessHeap(), 0, This
);
1791 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
1792 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1794 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1798 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1800 EnterCriticalSection(&This
->lock
);
1802 if (This
->initialized
|| This
->committed
)
1804 hr
= WINCODEC_ERR_WRONGSTATE
;
1808 tiff
= tiff_open_stream(pIStream
, "w");
1817 This
->stream
= pIStream
;
1818 IStream_AddRef(pIStream
);
1819 This
->initialized
= TRUE
;
1822 LeaveCriticalSection(&This
->lock
);
1826 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1827 GUID
*pguidContainerFormat
)
1829 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
1833 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1834 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1836 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1840 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1841 UINT cCount
, IWICColorContext
**ppIColorContext
)
1843 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1847 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1849 TRACE("(%p,%p)\n", iface
, pIPalette
);
1850 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1853 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1855 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1856 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1859 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1861 TRACE("(%p,%p)\n", iface
, pIPreview
);
1862 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1865 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1866 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1868 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1869 TiffFrameEncode
*result
;
1873 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1875 EnterCriticalSection(&This
->lock
);
1877 if (!This
->initialized
|| This
->committed
)
1879 hr
= WINCODEC_ERR_WRONGSTATE
;
1881 else if (This
->num_frames
!= This
->num_frames_committed
)
1883 FIXME("New frame created before previous frame was committed\n");
1889 hr
= CreatePropertyBag2(ppIEncoderOptions
);
1894 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
1898 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
1900 result
->parent
= This
;
1901 result
->initialized
= FALSE
;
1902 result
->info_written
= FALSE
;
1903 result
->committed
= FALSE
;
1904 result
->format
= NULL
;
1909 result
->lines_written
= 0;
1911 IWICBitmapEncoder_AddRef(iface
);
1912 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
1914 if (This
->num_frames
!= 0)
1915 pTIFFWriteDirectory(This
->tiff
);
1924 IPropertyBag2_Release(*ppIEncoderOptions
);
1925 *ppIEncoderOptions
= NULL
;
1929 LeaveCriticalSection(&This
->lock
);
1934 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
1936 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1938 TRACE("(%p)\n", iface
);
1940 EnterCriticalSection(&This
->lock
);
1942 if (!This
->initialized
|| This
->committed
)
1944 LeaveCriticalSection(&This
->lock
);
1945 return WINCODEC_ERR_WRONGSTATE
;
1948 pTIFFClose(This
->tiff
);
1949 IStream_Release(This
->stream
);
1950 This
->stream
= NULL
;
1953 This
->committed
= TRUE
;
1955 LeaveCriticalSection(&This
->lock
);
1960 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
1961 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1963 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
1967 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
1968 TiffEncoder_QueryInterface
,
1970 TiffEncoder_Release
,
1971 TiffEncoder_Initialize
,
1972 TiffEncoder_GetContainerFormat
,
1973 TiffEncoder_GetEncoderInfo
,
1974 TiffEncoder_SetColorContexts
,
1975 TiffEncoder_SetPalette
,
1976 TiffEncoder_SetThumbnail
,
1977 TiffEncoder_SetPreview
,
1978 TiffEncoder_CreateNewFrame
,
1980 TiffEncoder_GetMetadataQueryWriter
1983 HRESULT
TiffEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1988 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1992 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1994 if (!load_libtiff())
1996 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
2000 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
2001 if (!This
) return E_OUTOFMEMORY
;
2003 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
2005 This
->stream
= NULL
;
2006 InitializeCriticalSection(&This
->lock
);
2007 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
2009 This
->initialized
= FALSE
;
2010 This
->num_frames
= 0;
2011 This
->num_frames_committed
= 0;
2012 This
->committed
= FALSE
;
2014 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2015 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);
2020 #else /* !SONAME_LIBTIFF */
2022 HRESULT
TiffDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
2024 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
2028 HRESULT
TiffEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
2030 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");