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"
37 #include "wincodecs_private.h"
39 #include "wine/debug.h"
40 #include "wine/library.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
46 static CRITICAL_SECTION init_tiff_cs
;
47 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
50 { &init_tiff_cs_debug
.ProcessLocksList
,
51 &init_tiff_cs_debug
.ProcessLocksList
},
52 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
54 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
56 static void *libtiff_handle
;
57 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
58 MAKE_FUNCPTR(TIFFClientOpen
);
59 MAKE_FUNCPTR(TIFFClose
);
60 MAKE_FUNCPTR(TIFFCurrentDirectory
);
61 MAKE_FUNCPTR(TIFFGetField
);
62 MAKE_FUNCPTR(TIFFIsByteSwapped
);
63 MAKE_FUNCPTR(TIFFReadDirectory
);
64 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
65 MAKE_FUNCPTR(TIFFReadEncodedTile
);
66 MAKE_FUNCPTR(TIFFSetDirectory
);
67 MAKE_FUNCPTR(TIFFSetField
);
68 MAKE_FUNCPTR(TIFFWriteDirectory
);
69 MAKE_FUNCPTR(TIFFWriteScanline
);
72 static void *load_libtiff(void)
76 EnterCriticalSection(&init_tiff_cs
);
78 if (!libtiff_handle
&&
79 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
82 #define LOAD_FUNCPTR(f) \
83 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
84 ERR("failed to load symbol %s\n", #f); \
85 libtiff_handle = NULL; \
86 LeaveCriticalSection(&init_tiff_cs); \
89 LOAD_FUNCPTR(TIFFClientOpen
);
90 LOAD_FUNCPTR(TIFFClose
);
91 LOAD_FUNCPTR(TIFFCurrentDirectory
);
92 LOAD_FUNCPTR(TIFFGetField
);
93 LOAD_FUNCPTR(TIFFIsByteSwapped
);
94 LOAD_FUNCPTR(TIFFReadDirectory
);
95 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
96 LOAD_FUNCPTR(TIFFReadEncodedTile
);
97 LOAD_FUNCPTR(TIFFSetDirectory
);
98 LOAD_FUNCPTR(TIFFSetField
);
99 LOAD_FUNCPTR(TIFFWriteDirectory
);
100 LOAD_FUNCPTR(TIFFWriteScanline
);
105 result
= libtiff_handle
;
107 LeaveCriticalSection(&init_tiff_cs
);
111 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
113 IStream
*stream
= (IStream
*)client_data
;
117 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
118 if (FAILED(hr
)) bytes_read
= 0;
122 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
124 IStream
*stream
= (IStream
*)client_data
;
128 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
129 if (FAILED(hr
)) bytes_written
= 0;
130 return bytes_written
;
133 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
135 IStream
*stream
= (IStream
*)client_data
;
138 ULARGE_INTEGER new_position
;
141 move
.QuadPart
= offset
;
145 origin
= STREAM_SEEK_SET
;
148 origin
= STREAM_SEEK_CUR
;
151 origin
= STREAM_SEEK_END
;
154 ERR("unknown whence value %i\n", whence
);
158 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
159 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
163 static int tiff_stream_close(thandle_t client_data
)
165 /* Caller is responsible for releasing the stream object. */
169 static toff_t
tiff_stream_size(thandle_t client_data
)
171 IStream
*stream
= (IStream
*)client_data
;
175 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
177 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
181 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
183 /* Cannot mmap streams */
187 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
189 /* No need to ever do this, since we can't map things. */
192 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
197 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
199 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
200 tiff_stream_write
, tiff_stream_seek
, tiff_stream_close
,
201 tiff_stream_size
, tiff_stream_map
, tiff_stream_unmap
);
205 IWICBitmapDecoder IWICBitmapDecoder_iface
;
208 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initiailzed is set */
214 const WICPixelFormatGUID
*format
;
221 int invert_grayscale
;
223 UINT tile_width
, tile_height
;
228 UINT resolution_unit
;
233 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
237 tiff_decode_info decode_info
;
238 INT cached_tile_x
, cached_tile_y
;
242 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
244 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
246 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
249 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
251 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
254 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
256 uint16 photometric
, bps
, samples
, planar
;
257 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
260 decode_info
->indexed
= 0;
261 decode_info
->reverse_bgr
= 0;
262 decode_info
->invert_grayscale
= 0;
263 decode_info
->tiled
= 0;
265 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
268 WARN("missing PhotometricInterpretation tag\n");
272 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
274 decode_info
->bps
= bps
;
276 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
277 if (!ret
) samples
= 1;
278 decode_info
->samples
= samples
;
284 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
285 if (!ret
) planar
= 1;
288 FIXME("unhandled planar configuration %u\n", planar
);
292 decode_info
->planar
= planar
;
296 case 0: /* WhiteIsZero */
297 decode_info
->invert_grayscale
= 1;
299 case 1: /* BlackIsZero */
302 FIXME("unhandled grayscale sample count %u\n", samples
);
306 decode_info
->bpp
= bps
;
310 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
313 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
316 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
319 FIXME("unhandled greyscale bit count %u\n", bps
);
324 decode_info
->bpp
= bps
* samples
;
328 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
331 extra_sample_count
= 1;
333 extra_samples
= &extra_sample
;
336 else if (samples
!= 3)
338 FIXME("unhandled RGB sample count %u\n", samples
);
345 decode_info
->reverse_bgr
= 1;
347 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
349 switch(extra_samples
[0])
351 case 1: /* Associated (pre-multiplied) alpha data */
352 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
354 case 0: /* Unspecified data */
355 case 2: /* Unassociated alpha data */
356 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
359 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
365 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
367 switch(extra_samples
[0])
369 case 1: /* Associated (pre-multiplied) alpha data */
370 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
372 case 0: /* Unspecified data */
373 case 2: /* Unassociated alpha data */
374 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
377 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
382 FIXME("unhandled RGB bit count %u\n", bps
);
386 case 3: /* RGB Palette */
389 FIXME("unhandled indexed sample count %u\n", samples
);
393 decode_info
->indexed
= 1;
394 decode_info
->bpp
= bps
;
398 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
401 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
404 FIXME("unhandled indexed bit count %u\n", bps
);
408 case 4: /* Transparency mask */
413 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
417 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
420 WARN("missing image width\n");
424 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
427 WARN("missing image length\n");
431 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
433 decode_info
->tiled
= 1;
437 WARN("missing tile width\n");
441 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
444 WARN("missing tile height\n");
448 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
449 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
450 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
452 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
454 if (decode_info
->tile_height
> decode_info
->height
)
455 decode_info
->tile_height
= decode_info
->height
;
456 decode_info
->tile_width
= decode_info
->width
;
457 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
458 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
462 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
463 decode_info
->tile_height
= decode_info
->height
;
464 decode_info
->tile_width
= decode_info
->width
;
465 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
466 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
469 decode_info
->resolution_unit
= 0;
470 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
471 if (decode_info
->resolution_unit
!= 0)
473 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
476 WARN("missing X resolution\n");
477 decode_info
->resolution_unit
= 0;
480 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
483 WARN("missing Y resolution\n");
484 decode_info
->resolution_unit
= 0;
491 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
494 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
495 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
497 if (!ppv
) return E_INVALIDARG
;
499 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
506 return E_NOINTERFACE
;
509 IUnknown_AddRef((IUnknown
*)*ppv
);
513 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
515 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
516 ULONG ref
= InterlockedIncrement(&This
->ref
);
518 TRACE("(%p) refcount=%u\n", iface
, ref
);
523 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
525 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
526 ULONG ref
= InterlockedDecrement(&This
->ref
);
528 TRACE("(%p) refcount=%u\n", iface
, ref
);
532 if (This
->tiff
) pTIFFClose(This
->tiff
);
533 if (This
->stream
) IStream_Release(This
->stream
);
534 This
->lock
.DebugInfo
->Spare
[0] = 0;
535 DeleteCriticalSection(&This
->lock
);
536 HeapFree(GetProcessHeap(), 0, This
);
542 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
543 DWORD
*pdwCapability
)
545 FIXME("(%p,%p,%p): stub\n", iface
, pIStream
, pdwCapability
);
549 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
550 WICDecodeOptions cacheOptions
)
552 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
556 TRACE("(%p,%p,%x): stub\n", iface
, pIStream
, cacheOptions
);
558 EnterCriticalSection(&This
->lock
);
560 if (This
->initialized
)
562 hr
= WINCODEC_ERR_WRONGSTATE
;
566 tiff
= tiff_open_stream(pIStream
, "r");
575 This
->stream
= pIStream
;
576 IStream_AddRef(pIStream
);
577 This
->initialized
= TRUE
;
580 LeaveCriticalSection(&This
->lock
);
584 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
585 GUID
*pguidContainerFormat
)
587 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
591 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
592 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
595 IWICComponentInfo
*compinfo
;
597 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
599 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
600 if (FAILED(hr
)) return hr
;
602 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
603 (void**)ppIDecoderInfo
);
605 IWICComponentInfo_Release(compinfo
);
610 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
611 IWICPalette
*pIPalette
)
613 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
617 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
618 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
620 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
624 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
625 IWICBitmapSource
**ppIBitmapSource
)
627 FIXME("(%p,%p): stub\n", iface
, ppIBitmapSource
);
631 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
632 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
634 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
638 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
639 IWICBitmapSource
**ppIThumbnail
)
641 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
642 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
645 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
648 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
652 WARN("(%p) <-- WINCODEC_ERR_WRONGSTATE\n", iface
);
653 return WINCODEC_ERR_WRONGSTATE
;
656 EnterCriticalSection(&This
->lock
);
657 while (pTIFFReadDirectory(This
->tiff
)) { }
658 *pCount
= pTIFFCurrentDirectory(This
->tiff
)+1;
659 LeaveCriticalSection(&This
->lock
);
661 TRACE("(%p) <-- %i\n", iface
, *pCount
);
666 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
667 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
669 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
670 TiffFrameDecode
*result
;
672 tiff_decode_info decode_info
;
675 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
678 return WINCODEC_ERR_WRONGSTATE
;
680 EnterCriticalSection(&This
->lock
);
681 res
= pTIFFSetDirectory(This
->tiff
, index
);
682 if (!res
) hr
= E_INVALIDARG
;
683 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
684 LeaveCriticalSection(&This
->lock
);
688 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
692 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
694 result
->parent
= This
;
695 result
->index
= index
;
696 result
->decode_info
= decode_info
;
697 result
->cached_tile_x
= -1;
698 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
700 if (result
->cached_tile
)
701 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)result
;
705 HeapFree(GetProcessHeap(), 0, result
);
708 else hr
= E_OUTOFMEMORY
;
711 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
716 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
717 TiffDecoder_QueryInterface
,
720 TiffDecoder_QueryCapability
,
721 TiffDecoder_Initialize
,
722 TiffDecoder_GetContainerFormat
,
723 TiffDecoder_GetDecoderInfo
,
724 TiffDecoder_CopyPalette
,
725 TiffDecoder_GetMetadataQueryReader
,
726 TiffDecoder_GetPreview
,
727 TiffDecoder_GetColorContexts
,
728 TiffDecoder_GetThumbnail
,
729 TiffDecoder_GetFrameCount
,
733 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
736 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
737 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
739 if (!ppv
) return E_INVALIDARG
;
741 if (IsEqualIID(&IID_IUnknown
, iid
) ||
742 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
743 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
750 return E_NOINTERFACE
;
753 IUnknown_AddRef((IUnknown
*)*ppv
);
757 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
759 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
760 ULONG ref
= InterlockedIncrement(&This
->ref
);
762 TRACE("(%p) refcount=%u\n", iface
, ref
);
767 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
769 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
770 ULONG ref
= InterlockedDecrement(&This
->ref
);
772 TRACE("(%p) refcount=%u\n", iface
, ref
);
776 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
777 HeapFree(GetProcessHeap(), 0, This
);
783 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
784 UINT
*puiWidth
, UINT
*puiHeight
)
786 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
788 *puiWidth
= This
->decode_info
.width
;
789 *puiHeight
= This
->decode_info
.height
;
791 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
796 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
797 WICPixelFormatGUID
*pPixelFormat
)
799 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
801 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
803 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
808 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
809 double *pDpiX
, double *pDpiY
)
811 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
813 switch (This
->decode_info
.resolution_unit
)
816 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
818 case 0: /* Not set */
819 *pDpiX
= *pDpiY
= 96.0;
821 case 1: /* Relative measurements */
823 *pDpiY
= 96.0 * This
->decode_info
.yres
/ This
->decode_info
.xres
;
826 *pDpiX
= This
->decode_info
.xres
;
827 *pDpiY
= This
->decode_info
.yres
;
829 case 3: /* Centimeter */
830 *pDpiX
= This
->decode_info
.xres
/ 2.54;
831 *pDpiY
= This
->decode_info
.yres
/ 2.54;
835 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
840 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
841 IWICPalette
*pIPalette
)
843 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
844 uint16
*red
, *green
, *blue
;
845 WICColor colors
[256];
846 int color_count
, ret
, i
;
848 TRACE("(%p,%p)\n", iface
, pIPalette
);
850 color_count
= 1<<This
->decode_info
.bps
;
852 EnterCriticalSection(&This
->parent
->lock
);
853 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
854 LeaveCriticalSection(&This
->parent
->lock
);
858 WARN("Couldn't read color map\n");
862 for (i
=0; i
<color_count
; i
++)
864 colors
[i
] = 0xff000000 |
865 ((red
[i
]<<8) & 0xff0000) |
866 (green
[i
] & 0xff00) |
867 ((blue
[i
]>>8) & 0xff);
870 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
873 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
879 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
881 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
888 if (This
->decode_info
.tiled
)
890 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
894 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
901 if (hr
== S_OK
&& This
->decode_info
.reverse_bgr
)
903 if (This
->decode_info
.bps
== 8)
905 UINT sample_count
= This
->decode_info
.samples
;
907 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
908 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
912 if (hr
== S_OK
&& swap_bytes
&& This
->decode_info
.bps
> 8)
914 UINT row
, i
, samples_per_row
;
917 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
919 switch(This
->decode_info
.bps
)
922 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
924 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
925 for (i
=0; i
<samples_per_row
; i
++)
928 sample
[1] = sample
[0];
935 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
940 if (hr
== S_OK
&& This
->decode_info
.invert_grayscale
)
944 if (This
->decode_info
.samples
!= 1)
946 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
950 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
952 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
958 This
->cached_tile_x
= tile_x
;
959 This
->cached_tile_y
= tile_y
;
965 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
966 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
968 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
969 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
977 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
983 rect
.Width
= This
->decode_info
.width
;
984 rect
.Height
= This
->decode_info
.height
;
989 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
990 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
994 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
996 if (cbStride
< bytesperrow
)
999 if ((cbStride
* prc
->Height
) > cbBufferSize
)
1000 return E_INVALIDARG
;
1002 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1003 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1004 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1005 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1007 EnterCriticalSection(&This
->parent
->lock
);
1009 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1011 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1013 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1015 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1020 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1023 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1025 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1028 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1030 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1031 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1032 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1033 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1035 rc
.Width
= prc
->Width
;
1037 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1038 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1039 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1040 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1042 rc
.Height
= prc
->Height
;
1044 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1045 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1047 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1048 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1049 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1054 LeaveCriticalSection(&This
->parent
->lock
);
1055 TRACE("<-- 0x%x\n", hr
);
1061 LeaveCriticalSection(&This
->parent
->lock
);
1066 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1067 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1069 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
1073 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1074 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1076 FIXME("(%p,%u,%p,%p): stub\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1080 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1081 IWICBitmapSource
**ppIThumbnail
)
1083 FIXME("(%p,%p): stub\n", iface
, ppIThumbnail
);
1087 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1088 TiffFrameDecode_QueryInterface
,
1089 TiffFrameDecode_AddRef
,
1090 TiffFrameDecode_Release
,
1091 TiffFrameDecode_GetSize
,
1092 TiffFrameDecode_GetPixelFormat
,
1093 TiffFrameDecode_GetResolution
,
1094 TiffFrameDecode_CopyPalette
,
1095 TiffFrameDecode_CopyPixels
,
1096 TiffFrameDecode_GetMetadataQueryReader
,
1097 TiffFrameDecode_GetColorContexts
,
1098 TiffFrameDecode_GetThumbnail
1101 HRESULT
TiffDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1106 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1110 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1112 if (!load_libtiff())
1114 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1118 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1119 if (!This
) return E_OUTOFMEMORY
;
1121 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1123 This
->stream
= NULL
;
1124 InitializeCriticalSection(&This
->lock
);
1125 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1127 This
->initialized
= FALSE
;
1129 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1130 IUnknown_Release((IUnknown
*)This
);
1135 struct tiff_encode_format
{
1136 const WICPixelFormatGUID
*guid
;
1142 int extra_sample_type
;
1146 static const struct tiff_encode_format formats
[] = {
1147 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1148 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1149 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1150 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1151 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1152 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1153 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1154 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1155 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1159 typedef struct TiffEncoder
{
1160 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1163 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1168 ULONG num_frames_committed
;
1171 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1173 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1176 typedef struct TiffFrameEncode
{
1177 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1179 TiffEncoder
*parent
;
1180 /* fields below are protected by parent->lock */
1184 const struct tiff_encode_format
*format
;
1190 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1192 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1195 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1198 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1199 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1201 if (!ppv
) return E_INVALIDARG
;
1203 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1204 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1206 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1211 return E_NOINTERFACE
;
1214 IUnknown_AddRef((IUnknown
*)*ppv
);
1218 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1220 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1221 ULONG ref
= InterlockedIncrement(&This
->ref
);
1223 TRACE("(%p) refcount=%u\n", iface
, ref
);
1228 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1230 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1231 ULONG ref
= InterlockedDecrement(&This
->ref
);
1233 TRACE("(%p) refcount=%u\n", iface
, ref
);
1237 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1238 HeapFree(GetProcessHeap(), 0, This
);
1244 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1245 IPropertyBag2
*pIEncoderOptions
)
1247 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1248 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1250 EnterCriticalSection(&This
->parent
->lock
);
1252 if (This
->initialized
)
1254 LeaveCriticalSection(&This
->parent
->lock
);
1255 return WINCODEC_ERR_WRONGSTATE
;
1258 This
->initialized
= TRUE
;
1260 LeaveCriticalSection(&This
->parent
->lock
);
1265 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1266 UINT uiWidth
, UINT uiHeight
)
1268 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1269 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1271 EnterCriticalSection(&This
->parent
->lock
);
1273 if (!This
->initialized
|| This
->info_written
)
1275 LeaveCriticalSection(&This
->parent
->lock
);
1276 return WINCODEC_ERR_WRONGSTATE
;
1279 This
->width
= uiWidth
;
1280 This
->height
= uiHeight
;
1282 LeaveCriticalSection(&This
->parent
->lock
);
1287 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1288 double dpiX
, double dpiY
)
1290 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1291 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1293 EnterCriticalSection(&This
->parent
->lock
);
1295 if (!This
->initialized
|| This
->info_written
)
1297 LeaveCriticalSection(&This
->parent
->lock
);
1298 return WINCODEC_ERR_WRONGSTATE
;
1304 LeaveCriticalSection(&This
->parent
->lock
);
1309 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1310 WICPixelFormatGUID
*pPixelFormat
)
1312 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1315 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1317 EnterCriticalSection(&This
->parent
->lock
);
1319 if (!This
->initialized
|| This
->info_written
)
1321 LeaveCriticalSection(&This
->parent
->lock
);
1322 return WINCODEC_ERR_WRONGSTATE
;
1325 for (i
=0; formats
[i
].guid
; i
++)
1327 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1331 if (!formats
[i
].guid
) i
= 0;
1333 This
->format
= &formats
[i
];
1334 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1336 LeaveCriticalSection(&This
->parent
->lock
);
1341 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1342 UINT cCount
, IWICColorContext
**ppIColorContext
)
1344 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1348 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1349 IWICPalette
*pIPalette
)
1351 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
1352 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1355 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1356 IWICBitmapSource
*pIThumbnail
)
1358 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1359 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1362 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1363 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1365 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1366 BYTE
*row_data
, *swapped_data
= NULL
;
1367 UINT i
, j
, line_size
;
1369 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1371 EnterCriticalSection(&This
->parent
->lock
);
1373 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1375 LeaveCriticalSection(&This
->parent
->lock
);
1376 return WINCODEC_ERR_WRONGSTATE
;
1379 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1381 LeaveCriticalSection(&This
->parent
->lock
);
1382 return E_INVALIDARG
;
1385 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1387 if (This
->format
->reverse_bgr
)
1389 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1392 LeaveCriticalSection(&This
->parent
->lock
);
1393 return E_OUTOFMEMORY
;
1397 if (!This
->info_written
)
1399 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1400 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1401 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1402 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1404 if (This
->format
->extra_sample
)
1406 uint16 extra_samples
;
1407 extra_samples
= This
->format
->extra_sample_type
;
1409 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1412 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1413 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1415 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1417 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1418 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1419 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1422 This
->info_written
= TRUE
;
1425 for (i
=0; i
<lineCount
; i
++)
1427 row_data
= pbPixels
+ i
* cbStride
;
1429 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1431 memcpy(swapped_data
, row_data
, line_size
);
1432 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1435 temp
= swapped_data
[j
];
1436 swapped_data
[j
] = swapped_data
[j
+2];
1437 swapped_data
[j
+2] = temp
;
1439 row_data
= swapped_data
;
1442 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1445 This
->lines_written
+= lineCount
;
1447 LeaveCriticalSection(&This
->parent
->lock
);
1449 HeapFree(GetProcessHeap(), 0, swapped_data
);
1454 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1455 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1457 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1460 WICPixelFormatGUID guid
;
1464 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1466 if (!This
->initialized
|| !This
->width
|| !This
->height
)
1467 return WINCODEC_ERR_WRONGSTATE
;
1471 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1472 if (FAILED(hr
)) return hr
;
1473 hr
= IWICBitmapFrameEncode_SetPixelFormat(iface
, &guid
);
1474 if (FAILED(hr
)) return hr
;
1477 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1478 if (FAILED(hr
)) return hr
;
1479 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
1481 /* FIXME: should use WICConvertBitmapSource to convert */
1482 ERR("format %s unsupported\n", debugstr_guid(&guid
));
1486 if (This
->xres
== 0.0 || This
->yres
== 0.0)
1489 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
1490 if (FAILED(hr
)) return hr
;
1491 hr
= IWICBitmapFrameEncode_SetResolution(iface
, xres
, yres
);
1492 if (FAILED(hr
)) return hr
;
1498 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
1499 if (FAILED(hr
)) return hr
;
1507 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
1509 stride
= (This
->format
->bpp
* This
->width
+ 7)/8;
1511 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
1512 if (!pixeldata
) return E_OUTOFMEMORY
;
1514 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
1515 stride
*prc
->Height
, pixeldata
);
1519 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
1520 stride
*prc
->Height
, pixeldata
);
1523 HeapFree(GetProcessHeap(), 0, pixeldata
);
1528 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1530 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1532 TRACE("(%p)\n", iface
);
1534 EnterCriticalSection(&This
->parent
->lock
);
1536 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1538 LeaveCriticalSection(&This
->parent
->lock
);
1539 return WINCODEC_ERR_WRONGSTATE
;
1542 /* libtiff will commit the data when creating a new frame or closing the file */
1544 This
->committed
= TRUE
;
1545 This
->parent
->num_frames_committed
++;
1547 LeaveCriticalSection(&This
->parent
->lock
);
1552 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1553 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1555 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1559 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
1560 TiffFrameEncode_QueryInterface
,
1561 TiffFrameEncode_AddRef
,
1562 TiffFrameEncode_Release
,
1563 TiffFrameEncode_Initialize
,
1564 TiffFrameEncode_SetSize
,
1565 TiffFrameEncode_SetResolution
,
1566 TiffFrameEncode_SetPixelFormat
,
1567 TiffFrameEncode_SetColorContexts
,
1568 TiffFrameEncode_SetPalette
,
1569 TiffFrameEncode_SetThumbnail
,
1570 TiffFrameEncode_WritePixels
,
1571 TiffFrameEncode_WriteSource
,
1572 TiffFrameEncode_Commit
,
1573 TiffFrameEncode_GetMetadataQueryWriter
1576 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1579 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1580 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1582 if (!ppv
) return E_INVALIDARG
;
1584 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1585 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1592 return E_NOINTERFACE
;
1595 IUnknown_AddRef((IUnknown
*)*ppv
);
1599 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
1601 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1602 ULONG ref
= InterlockedIncrement(&This
->ref
);
1604 TRACE("(%p) refcount=%u\n", iface
, ref
);
1609 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
1611 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1612 ULONG ref
= InterlockedDecrement(&This
->ref
);
1614 TRACE("(%p) refcount=%u\n", iface
, ref
);
1618 if (This
->tiff
) pTIFFClose(This
->tiff
);
1619 if (This
->stream
) IStream_Release(This
->stream
);
1620 This
->lock
.DebugInfo
->Spare
[0] = 0;
1621 DeleteCriticalSection(&This
->lock
);
1622 HeapFree(GetProcessHeap(), 0, This
);
1628 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
1629 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1631 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1635 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1637 EnterCriticalSection(&This
->lock
);
1639 if (This
->initialized
|| This
->committed
)
1641 hr
= WINCODEC_ERR_WRONGSTATE
;
1645 tiff
= tiff_open_stream(pIStream
, "w");
1654 This
->stream
= pIStream
;
1655 IStream_AddRef(pIStream
);
1656 This
->initialized
= TRUE
;
1659 LeaveCriticalSection(&This
->lock
);
1663 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1664 GUID
*pguidContainerFormat
)
1666 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
1670 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1671 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1673 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1677 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1678 UINT cCount
, IWICColorContext
**ppIColorContext
)
1680 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1684 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1686 TRACE("(%p,%p)\n", iface
, pIPalette
);
1687 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1690 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1692 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1693 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1696 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1698 TRACE("(%p,%p)\n", iface
, pIPreview
);
1699 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1702 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1703 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1705 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1706 TiffFrameEncode
*result
;
1710 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1712 EnterCriticalSection(&This
->lock
);
1714 if (!This
->initialized
|| This
->committed
)
1716 hr
= WINCODEC_ERR_WRONGSTATE
;
1718 else if (This
->num_frames
!= This
->num_frames_committed
)
1720 FIXME("New frame created before previous frame was committed\n");
1726 hr
= CreatePropertyBag2(ppIEncoderOptions
);
1731 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
1735 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
1737 result
->parent
= This
;
1738 result
->initialized
= FALSE
;
1739 result
->info_written
= FALSE
;
1740 result
->committed
= FALSE
;
1741 result
->format
= NULL
;
1746 result
->lines_written
= 0;
1748 IWICBitmapEncoder_AddRef(iface
);
1749 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
1751 if (This
->num_frames
!= 0)
1752 pTIFFWriteDirectory(This
->tiff
);
1761 IPropertyBag2_Release(*ppIEncoderOptions
);
1762 *ppIEncoderOptions
= NULL
;
1766 LeaveCriticalSection(&This
->lock
);
1771 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
1773 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1775 TRACE("(%p)\n", iface
);
1777 EnterCriticalSection(&This
->lock
);
1779 if (!This
->initialized
|| This
->committed
)
1781 LeaveCriticalSection(&This
->lock
);
1782 return WINCODEC_ERR_WRONGSTATE
;
1785 pTIFFClose(This
->tiff
);
1786 IStream_Release(This
->stream
);
1787 This
->stream
= NULL
;
1790 This
->committed
= TRUE
;
1792 LeaveCriticalSection(&This
->lock
);
1797 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
1798 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1800 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
1804 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
1805 TiffEncoder_QueryInterface
,
1807 TiffEncoder_Release
,
1808 TiffEncoder_Initialize
,
1809 TiffEncoder_GetContainerFormat
,
1810 TiffEncoder_GetEncoderInfo
,
1811 TiffEncoder_SetColorContexts
,
1812 TiffEncoder_SetPalette
,
1813 TiffEncoder_SetThumbnail
,
1814 TiffEncoder_SetPreview
,
1815 TiffEncoder_CreateNewFrame
,
1817 TiffEncoder_GetMetadataQueryWriter
1820 HRESULT
TiffEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1825 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1829 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1831 if (!load_libtiff())
1833 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1837 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
1838 if (!This
) return E_OUTOFMEMORY
;
1840 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
1842 This
->stream
= NULL
;
1843 InitializeCriticalSection(&This
->lock
);
1844 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
1846 This
->initialized
= FALSE
;
1847 This
->num_frames
= 0;
1848 This
->num_frames_committed
= 0;
1849 This
->committed
= FALSE
;
1851 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1852 IUnknown_Release((IUnknown
*)This
);
1857 #else /* !SONAME_LIBTIFF */
1859 HRESULT
TiffDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1861 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
1865 HRESULT
TiffEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1867 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");