2 * Copyright 2010 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "wine/port.h"
36 #include "wincodecsdk.h"
38 #include "wincodecs_private.h"
40 #include "wine/debug.h"
41 #include "wine/library.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
47 static CRITICAL_SECTION init_tiff_cs
;
48 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug
=
51 { &init_tiff_cs_debug
.ProcessLocksList
,
52 &init_tiff_cs_debug
.ProcessLocksList
},
53 0, 0, { (DWORD_PTR
)(__FILE__
": init_tiff_cs") }
55 static CRITICAL_SECTION init_tiff_cs
= { &init_tiff_cs_debug
, -1, 0, 0, 0, 0 };
57 static void *libtiff_handle
;
58 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
59 MAKE_FUNCPTR(TIFFClientOpen
);
60 MAKE_FUNCPTR(TIFFClose
);
61 MAKE_FUNCPTR(TIFFCurrentDirOffset
);
62 MAKE_FUNCPTR(TIFFGetField
);
63 MAKE_FUNCPTR(TIFFIsByteSwapped
);
64 MAKE_FUNCPTR(TIFFNumberOfDirectories
);
65 MAKE_FUNCPTR(TIFFReadDirectory
);
66 MAKE_FUNCPTR(TIFFReadEncodedStrip
);
67 MAKE_FUNCPTR(TIFFReadEncodedTile
);
68 MAKE_FUNCPTR(TIFFSetDirectory
);
69 MAKE_FUNCPTR(TIFFSetField
);
70 MAKE_FUNCPTR(TIFFWriteDirectory
);
71 MAKE_FUNCPTR(TIFFWriteScanline
);
74 static void *load_libtiff(void)
78 EnterCriticalSection(&init_tiff_cs
);
80 if (!libtiff_handle
&&
81 (libtiff_handle
= wine_dlopen(SONAME_LIBTIFF
, RTLD_NOW
, NULL
, 0)) != NULL
)
84 #define LOAD_FUNCPTR(f) \
85 if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
86 ERR("failed to load symbol %s\n", #f); \
87 libtiff_handle = NULL; \
88 LeaveCriticalSection(&init_tiff_cs); \
91 LOAD_FUNCPTR(TIFFClientOpen
);
92 LOAD_FUNCPTR(TIFFClose
);
93 LOAD_FUNCPTR(TIFFCurrentDirOffset
);
94 LOAD_FUNCPTR(TIFFGetField
);
95 LOAD_FUNCPTR(TIFFIsByteSwapped
);
96 LOAD_FUNCPTR(TIFFNumberOfDirectories
);
97 LOAD_FUNCPTR(TIFFReadDirectory
);
98 LOAD_FUNCPTR(TIFFReadEncodedStrip
);
99 LOAD_FUNCPTR(TIFFReadEncodedTile
);
100 LOAD_FUNCPTR(TIFFSetDirectory
);
101 LOAD_FUNCPTR(TIFFSetField
);
102 LOAD_FUNCPTR(TIFFWriteDirectory
);
103 LOAD_FUNCPTR(TIFFWriteScanline
);
108 result
= libtiff_handle
;
110 LeaveCriticalSection(&init_tiff_cs
);
114 static tsize_t
tiff_stream_read(thandle_t client_data
, tdata_t data
, tsize_t size
)
116 IStream
*stream
= (IStream
*)client_data
;
120 hr
= IStream_Read(stream
, data
, size
, &bytes_read
);
121 if (FAILED(hr
)) bytes_read
= 0;
125 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
127 IStream
*stream
= (IStream
*)client_data
;
131 hr
= IStream_Write(stream
, data
, size
, &bytes_written
);
132 if (FAILED(hr
)) bytes_written
= 0;
133 return bytes_written
;
136 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
138 IStream
*stream
= (IStream
*)client_data
;
141 ULARGE_INTEGER new_position
;
144 move
.QuadPart
= offset
;
148 origin
= STREAM_SEEK_SET
;
151 origin
= STREAM_SEEK_CUR
;
154 origin
= STREAM_SEEK_END
;
157 ERR("unknown whence value %i\n", whence
);
161 hr
= IStream_Seek(stream
, move
, origin
, &new_position
);
162 if (SUCCEEDED(hr
)) return new_position
.QuadPart
;
166 static int tiff_stream_close(thandle_t client_data
)
168 /* Caller is responsible for releasing the stream object. */
172 static toff_t
tiff_stream_size(thandle_t client_data
)
174 IStream
*stream
= (IStream
*)client_data
;
178 hr
= IStream_Stat(stream
, &statstg
, STATFLAG_NONAME
);
180 if (SUCCEEDED(hr
)) return statstg
.cbSize
.QuadPart
;
184 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
186 /* Cannot mmap streams */
190 static void tiff_stream_unmap(thandle_t client_data
, tdata_t addr
, toff_t size
)
192 /* No need to ever do this, since we can't map things. */
195 static TIFF
* tiff_open_stream(IStream
*stream
, const char *mode
)
200 IStream_Seek(stream
, zero
, STREAM_SEEK_SET
, NULL
);
202 return pTIFFClientOpen("<IStream object>", mode
, stream
, tiff_stream_read
,
203 tiff_stream_write
, tiff_stream_seek
, tiff_stream_close
,
204 tiff_stream_size
, tiff_stream_map
, tiff_stream_unmap
);
208 IWICBitmapDecoder IWICBitmapDecoder_iface
;
211 CRITICAL_SECTION lock
; /* Must be held when tiff is used or initiailzed is set */
217 const WICPixelFormatGUID
*format
;
224 int invert_grayscale
;
226 UINT tile_width
, tile_height
;
231 UINT resolution_unit
;
236 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
237 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
241 tiff_decode_info decode_info
;
242 INT cached_tile_x
, cached_tile_y
;
246 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
;
247 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
;
249 static inline TiffDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
251 return CONTAINING_RECORD(iface
, TiffDecoder
, IWICBitmapDecoder_iface
);
254 static inline TiffFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
256 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICBitmapFrameDecode_iface
);
259 static inline TiffFrameDecode
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
261 return CONTAINING_RECORD(iface
, TiffFrameDecode
, IWICMetadataBlockReader_iface
);
264 static HRESULT
tiff_get_decode_info(TIFF
*tiff
, tiff_decode_info
*decode_info
)
266 uint16 photometric
, bps
, samples
, planar
;
267 uint16 extra_sample_count
, extra_sample
, *extra_samples
;
270 decode_info
->indexed
= 0;
271 decode_info
->reverse_bgr
= 0;
272 decode_info
->invert_grayscale
= 0;
273 decode_info
->tiled
= 0;
275 ret
= pTIFFGetField(tiff
, TIFFTAG_PHOTOMETRIC
, &photometric
);
278 WARN("missing PhotometricInterpretation tag\n");
282 ret
= pTIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
284 decode_info
->bps
= bps
;
286 ret
= pTIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
287 if (!ret
) samples
= 1;
288 decode_info
->samples
= samples
;
294 ret
= pTIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
295 if (!ret
) planar
= 1;
298 FIXME("unhandled planar configuration %u\n", planar
);
302 decode_info
->planar
= planar
;
306 case 0: /* WhiteIsZero */
307 decode_info
->invert_grayscale
= 1;
309 case 1: /* BlackIsZero */
312 FIXME("unhandled grayscale sample count %u\n", samples
);
316 decode_info
->bpp
= bps
;
320 decode_info
->format
= &GUID_WICPixelFormatBlackWhite
;
323 decode_info
->format
= &GUID_WICPixelFormat4bppGray
;
326 decode_info
->format
= &GUID_WICPixelFormat8bppGray
;
329 FIXME("unhandled greyscale bit count %u\n", bps
);
334 decode_info
->bpp
= bps
* samples
;
338 ret
= pTIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
341 extra_sample_count
= 1;
343 extra_samples
= &extra_sample
;
346 else if (samples
!= 3)
348 FIXME("unhandled RGB sample count %u\n", samples
);
355 decode_info
->reverse_bgr
= 1;
357 decode_info
->format
= &GUID_WICPixelFormat24bppBGR
;
359 switch(extra_samples
[0])
361 case 1: /* Associated (pre-multiplied) alpha data */
362 decode_info
->format
= &GUID_WICPixelFormat32bppPBGRA
;
364 case 0: /* Unspecified data */
365 case 2: /* Unassociated alpha data */
366 decode_info
->format
= &GUID_WICPixelFormat32bppBGRA
;
369 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
375 decode_info
->format
= &GUID_WICPixelFormat48bppRGB
;
377 switch(extra_samples
[0])
379 case 1: /* Associated (pre-multiplied) alpha data */
380 decode_info
->format
= &GUID_WICPixelFormat64bppPRGBA
;
382 case 0: /* Unspecified data */
383 case 2: /* Unassociated alpha data */
384 decode_info
->format
= &GUID_WICPixelFormat64bppRGBA
;
387 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
392 FIXME("unhandled RGB bit count %u\n", bps
);
396 case 3: /* RGB Palette */
399 FIXME("unhandled indexed sample count %u\n", samples
);
403 decode_info
->indexed
= 1;
404 decode_info
->bpp
= bps
;
408 decode_info
->format
= &GUID_WICPixelFormat4bppIndexed
;
411 decode_info
->format
= &GUID_WICPixelFormat8bppIndexed
;
414 FIXME("unhandled indexed bit count %u\n", bps
);
418 case 4: /* Transparency mask */
423 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
427 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->width
);
430 WARN("missing image width\n");
434 ret
= pTIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->height
);
437 WARN("missing image length\n");
441 if ((ret
= pTIFFGetField(tiff
, TIFFTAG_TILEWIDTH
, &decode_info
->tile_width
)))
443 decode_info
->tiled
= 1;
445 ret
= pTIFFGetField(tiff
, TIFFTAG_TILELENGTH
, &decode_info
->tile_height
);
448 WARN("missing tile height\n");
452 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
453 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
454 decode_info
->tiles_across
= (decode_info
->width
+ decode_info
->tile_width
- 1) / decode_info
->tile_width
;
456 else if ((ret
= pTIFFGetField(tiff
, TIFFTAG_ROWSPERSTRIP
, &decode_info
->tile_height
)))
458 if (decode_info
->tile_height
> decode_info
->height
)
459 decode_info
->tile_height
= decode_info
->height
;
460 decode_info
->tile_width
= decode_info
->width
;
461 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
462 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
466 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
467 decode_info
->tile_height
= decode_info
->height
;
468 decode_info
->tile_width
= decode_info
->width
;
469 decode_info
->tile_stride
= ((decode_info
->bpp
* decode_info
->tile_width
+ 7)/8);
470 decode_info
->tile_size
= decode_info
->tile_height
* decode_info
->tile_stride
;
473 decode_info
->resolution_unit
= 0;
474 pTIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &decode_info
->resolution_unit
);
475 if (decode_info
->resolution_unit
!= 0)
477 ret
= pTIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &decode_info
->xres
);
480 WARN("missing X resolution\n");
481 decode_info
->resolution_unit
= 0;
484 ret
= pTIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &decode_info
->yres
);
487 WARN("missing Y resolution\n");
488 decode_info
->resolution_unit
= 0;
495 static HRESULT WINAPI
TiffDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
498 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
499 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
501 if (!ppv
) return E_INVALIDARG
;
503 if (IsEqualIID(&IID_IUnknown
, iid
) || IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
510 return E_NOINTERFACE
;
513 IUnknown_AddRef((IUnknown
*)*ppv
);
517 static ULONG WINAPI
TiffDecoder_AddRef(IWICBitmapDecoder
*iface
)
519 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
520 ULONG ref
= InterlockedIncrement(&This
->ref
);
522 TRACE("(%p) refcount=%u\n", iface
, ref
);
527 static ULONG WINAPI
TiffDecoder_Release(IWICBitmapDecoder
*iface
)
529 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
530 ULONG ref
= InterlockedDecrement(&This
->ref
);
532 TRACE("(%p) refcount=%u\n", iface
, ref
);
536 if (This
->tiff
) pTIFFClose(This
->tiff
);
537 if (This
->stream
) IStream_Release(This
->stream
);
538 This
->lock
.DebugInfo
->Spare
[0] = 0;
539 DeleteCriticalSection(&This
->lock
);
540 HeapFree(GetProcessHeap(), 0, This
);
546 static HRESULT WINAPI
TiffDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
547 DWORD
*pdwCapability
)
549 FIXME("(%p,%p,%p): stub\n", iface
, pIStream
, pdwCapability
);
553 static HRESULT WINAPI
TiffDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
554 WICDecodeOptions cacheOptions
)
556 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
560 TRACE("(%p,%p,%x): stub\n", iface
, pIStream
, cacheOptions
);
562 EnterCriticalSection(&This
->lock
);
564 if (This
->initialized
)
566 hr
= WINCODEC_ERR_WRONGSTATE
;
570 tiff
= tiff_open_stream(pIStream
, "r");
579 This
->stream
= pIStream
;
580 IStream_AddRef(pIStream
);
581 This
->initialized
= TRUE
;
584 LeaveCriticalSection(&This
->lock
);
588 static HRESULT WINAPI
TiffDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
589 GUID
*pguidContainerFormat
)
591 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
595 static HRESULT WINAPI
TiffDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
596 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
599 IWICComponentInfo
*compinfo
;
601 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
603 hr
= CreateComponentInfo(&CLSID_WICTiffDecoder
, &compinfo
);
604 if (FAILED(hr
)) return hr
;
606 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
607 (void**)ppIDecoderInfo
);
609 IWICComponentInfo_Release(compinfo
);
614 static HRESULT WINAPI
TiffDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
615 IWICPalette
*pIPalette
)
617 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
621 static HRESULT WINAPI
TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
622 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
624 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
628 static HRESULT WINAPI
TiffDecoder_GetPreview(IWICBitmapDecoder
*iface
,
629 IWICBitmapSource
**ppIBitmapSource
)
631 FIXME("(%p,%p): stub\n", iface
, ppIBitmapSource
);
635 static HRESULT WINAPI
TiffDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
636 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
638 FIXME("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
642 static HRESULT WINAPI
TiffDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
643 IWICBitmapSource
**ppIThumbnail
)
645 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
646 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
649 static HRESULT WINAPI
TiffDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
652 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
656 WARN("(%p) <-- WINCODEC_ERR_WRONGSTATE\n", iface
);
657 return WINCODEC_ERR_WRONGSTATE
;
660 EnterCriticalSection(&This
->lock
);
661 *pCount
= pTIFFNumberOfDirectories(This
->tiff
);
662 LeaveCriticalSection(&This
->lock
);
664 TRACE("(%p) <-- %i\n", iface
, *pCount
);
669 static HRESULT WINAPI
TiffDecoder_GetFrame(IWICBitmapDecoder
*iface
,
670 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
672 TiffDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
673 TiffFrameDecode
*result
;
675 tiff_decode_info decode_info
;
678 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
681 return WINCODEC_ERR_WRONGSTATE
;
683 EnterCriticalSection(&This
->lock
);
684 res
= pTIFFSetDirectory(This
->tiff
, index
);
685 if (!res
) hr
= E_INVALIDARG
;
686 else hr
= tiff_get_decode_info(This
->tiff
, &decode_info
);
687 LeaveCriticalSection(&This
->lock
);
691 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode
));
695 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &TiffFrameDecode_Vtbl
;
696 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &TiffFrameDecode_BlockVtbl
;
698 result
->parent
= This
;
699 result
->index
= index
;
700 result
->decode_info
= decode_info
;
701 result
->cached_tile_x
= -1;
702 result
->cached_tile
= HeapAlloc(GetProcessHeap(), 0, decode_info
.tile_size
);
704 if (result
->cached_tile
)
705 *ppIBitmapFrame
= (IWICBitmapFrameDecode
*)result
;
709 HeapFree(GetProcessHeap(), 0, result
);
712 else hr
= E_OUTOFMEMORY
;
715 if (FAILED(hr
)) *ppIBitmapFrame
= NULL
;
720 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl
= {
721 TiffDecoder_QueryInterface
,
724 TiffDecoder_QueryCapability
,
725 TiffDecoder_Initialize
,
726 TiffDecoder_GetContainerFormat
,
727 TiffDecoder_GetDecoderInfo
,
728 TiffDecoder_CopyPalette
,
729 TiffDecoder_GetMetadataQueryReader
,
730 TiffDecoder_GetPreview
,
731 TiffDecoder_GetColorContexts
,
732 TiffDecoder_GetThumbnail
,
733 TiffDecoder_GetFrameCount
,
737 static HRESULT WINAPI
TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
740 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
741 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
743 if (!ppv
) return E_INVALIDARG
;
745 if (IsEqualIID(&IID_IUnknown
, iid
) ||
746 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
747 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
751 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
753 *ppv
= &This
->IWICMetadataBlockReader_iface
;
758 return E_NOINTERFACE
;
761 IUnknown_AddRef((IUnknown
*)*ppv
);
765 static ULONG WINAPI
TiffFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
767 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
768 ULONG ref
= InterlockedIncrement(&This
->ref
);
770 TRACE("(%p) refcount=%u\n", iface
, ref
);
775 static ULONG WINAPI
TiffFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
777 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
778 ULONG ref
= InterlockedDecrement(&This
->ref
);
780 TRACE("(%p) refcount=%u\n", iface
, ref
);
784 HeapFree(GetProcessHeap(), 0, This
->cached_tile
);
785 HeapFree(GetProcessHeap(), 0, This
);
791 static HRESULT WINAPI
TiffFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
792 UINT
*puiWidth
, UINT
*puiHeight
)
794 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
796 *puiWidth
= This
->decode_info
.width
;
797 *puiHeight
= This
->decode_info
.height
;
799 TRACE("(%p) <-- %ux%u\n", iface
, *puiWidth
, *puiHeight
);
804 static HRESULT WINAPI
TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
805 WICPixelFormatGUID
*pPixelFormat
)
807 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
809 memcpy(pPixelFormat
, This
->decode_info
.format
, sizeof(GUID
));
811 TRACE("(%p) <-- %s\n", This
, debugstr_guid(This
->decode_info
.format
));
816 static HRESULT WINAPI
TiffFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
817 double *pDpiX
, double *pDpiY
)
819 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
821 switch (This
->decode_info
.resolution_unit
)
824 FIXME("unknown resolution unit %i\n", This
->decode_info
.resolution_unit
);
826 case 0: /* Not set */
827 *pDpiX
= *pDpiY
= 96.0;
829 case 1: /* Relative measurements */
831 *pDpiY
= 96.0 * This
->decode_info
.yres
/ This
->decode_info
.xres
;
834 *pDpiX
= This
->decode_info
.xres
;
835 *pDpiY
= This
->decode_info
.yres
;
837 case 3: /* Centimeter */
838 *pDpiX
= This
->decode_info
.xres
/ 2.54;
839 *pDpiY
= This
->decode_info
.yres
/ 2.54;
843 TRACE("(%p) <-- %f,%f unit=%i\n", iface
, *pDpiX
, *pDpiY
, This
->decode_info
.resolution_unit
);
848 static HRESULT WINAPI
TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
849 IWICPalette
*pIPalette
)
851 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
852 uint16
*red
, *green
, *blue
;
853 WICColor colors
[256];
854 int color_count
, ret
, i
;
856 TRACE("(%p,%p)\n", iface
, pIPalette
);
858 color_count
= 1<<This
->decode_info
.bps
;
860 EnterCriticalSection(&This
->parent
->lock
);
861 ret
= pTIFFGetField(This
->parent
->tiff
, TIFFTAG_COLORMAP
, &red
, &green
, &blue
);
862 LeaveCriticalSection(&This
->parent
->lock
);
866 WARN("Couldn't read color map\n");
870 for (i
=0; i
<color_count
; i
++)
872 colors
[i
] = 0xff000000 |
873 ((red
[i
]<<8) & 0xff0000) |
874 (green
[i
] & 0xff00) |
875 ((blue
[i
]>>8) & 0xff);
878 return IWICPalette_InitializeCustom(pIPalette
, colors
, color_count
);
881 static HRESULT
TiffFrameDecode_ReadTile(TiffFrameDecode
*This
, UINT tile_x
, UINT tile_y
)
887 swap_bytes
= pTIFFIsByteSwapped(This
->parent
->tiff
);
889 ret
= pTIFFSetDirectory(This
->parent
->tiff
, This
->index
);
896 if (This
->decode_info
.tiled
)
898 ret
= pTIFFReadEncodedTile(This
->parent
->tiff
, tile_x
+ tile_y
* This
->decode_info
.tiles_across
, This
->cached_tile
, This
->decode_info
.tile_size
);
902 ret
= pTIFFReadEncodedStrip(This
->parent
->tiff
, tile_y
, This
->cached_tile
, This
->decode_info
.tile_size
);
909 if (hr
== S_OK
&& This
->decode_info
.reverse_bgr
)
911 if (This
->decode_info
.bps
== 8)
913 UINT sample_count
= This
->decode_info
.samples
;
915 reverse_bgr8(sample_count
, This
->cached_tile
, This
->decode_info
.tile_width
,
916 This
->decode_info
.tile_height
, This
->decode_info
.tile_width
* sample_count
);
920 if (hr
== S_OK
&& swap_bytes
&& This
->decode_info
.bps
> 8)
922 UINT row
, i
, samples_per_row
;
925 samples_per_row
= This
->decode_info
.tile_width
* This
->decode_info
.samples
;
927 switch(This
->decode_info
.bps
)
930 for (row
=0; row
<This
->decode_info
.tile_height
; row
++)
932 sample
= This
->cached_tile
+ row
* This
->decode_info
.tile_stride
;
933 for (i
=0; i
<samples_per_row
; i
++)
936 sample
[1] = sample
[0];
943 ERR("unhandled bps for byte swap %u\n", This
->decode_info
.bps
);
948 if (hr
== S_OK
&& This
->decode_info
.invert_grayscale
)
952 if (This
->decode_info
.samples
!= 1)
954 ERR("cannot invert grayscale image with %u samples\n", This
->decode_info
.samples
);
958 end
= This
->cached_tile
+This
->decode_info
.tile_size
;
960 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
966 This
->cached_tile_x
= tile_x
;
967 This
->cached_tile_y
= tile_y
;
973 static HRESULT WINAPI
TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
974 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
976 TiffFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
977 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
985 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
991 rect
.Width
= This
->decode_info
.width
;
992 rect
.Height
= This
->decode_info
.height
;
997 if (prc
->X
< 0 || prc
->Y
< 0 || prc
->X
+prc
->Width
> This
->decode_info
.width
||
998 prc
->Y
+prc
->Height
> This
->decode_info
.height
)
1002 bytesperrow
= ((This
->decode_info
.bpp
* prc
->Width
)+7)/8;
1004 if (cbStride
< bytesperrow
)
1005 return E_INVALIDARG
;
1007 if ((cbStride
* prc
->Height
) > cbBufferSize
)
1008 return E_INVALIDARG
;
1010 min_tile_x
= prc
->X
/ This
->decode_info
.tile_width
;
1011 min_tile_y
= prc
->Y
/ This
->decode_info
.tile_height
;
1012 max_tile_x
= (prc
->X
+prc
->Width
-1) / This
->decode_info
.tile_width
;
1013 max_tile_y
= (prc
->Y
+prc
->Height
-1) / This
->decode_info
.tile_height
;
1015 EnterCriticalSection(&This
->parent
->lock
);
1017 for (tile_x
=min_tile_x
; tile_x
<= max_tile_x
; tile_x
++)
1019 for (tile_y
=min_tile_y
; tile_y
<= max_tile_y
; tile_y
++)
1021 if (tile_x
!= This
->cached_tile_x
|| tile_y
!= This
->cached_tile_y
)
1023 hr
= TiffFrameDecode_ReadTile(This
, tile_x
, tile_y
);
1028 if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1031 rc
.X
= prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1033 if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1036 rc
.Y
= prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1038 if (prc
->X
+prc
->Width
> (tile_x
+1) * This
->decode_info
.tile_width
)
1039 rc
.Width
= This
->decode_info
.tile_width
- rc
.X
;
1040 else if (prc
->X
< tile_x
* This
->decode_info
.tile_width
)
1041 rc
.Width
= prc
->Width
+ prc
->X
- tile_x
* This
->decode_info
.tile_width
;
1043 rc
.Width
= prc
->Width
;
1045 if (prc
->Y
+prc
->Height
> (tile_y
+1) * This
->decode_info
.tile_height
)
1046 rc
.Height
= This
->decode_info
.tile_height
- rc
.Y
;
1047 else if (prc
->Y
< tile_y
* This
->decode_info
.tile_height
)
1048 rc
.Height
= prc
->Height
+ prc
->Y
- tile_y
* This
->decode_info
.tile_height
;
1050 rc
.Height
= prc
->Height
;
1052 dst_tilepos
= pbBuffer
+ (cbStride
* ((rc
.Y
+ tile_y
* This
->decode_info
.tile_height
) - prc
->Y
)) +
1053 ((This
->decode_info
.bpp
* ((rc
.X
+ tile_x
* This
->decode_info
.tile_width
) - prc
->X
) + 7) / 8);
1055 hr
= copy_pixels(This
->decode_info
.bpp
, This
->cached_tile
,
1056 This
->decode_info
.tile_width
, This
->decode_info
.tile_height
, This
->decode_info
.tile_stride
,
1057 &rc
, cbStride
, cbBufferSize
, dst_tilepos
);
1062 LeaveCriticalSection(&This
->parent
->lock
);
1063 TRACE("<-- 0x%x\n", hr
);
1069 LeaveCriticalSection(&This
->parent
->lock
);
1074 static HRESULT WINAPI
TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
1075 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1077 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryReader
);
1081 static HRESULT WINAPI
TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
1082 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1084 FIXME("(%p,%u,%p,%p): stub\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1088 static HRESULT WINAPI
TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
1089 IWICBitmapSource
**ppIThumbnail
)
1091 FIXME("(%p,%p): stub\n", iface
, ppIThumbnail
);
1095 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl
= {
1096 TiffFrameDecode_QueryInterface
,
1097 TiffFrameDecode_AddRef
,
1098 TiffFrameDecode_Release
,
1099 TiffFrameDecode_GetSize
,
1100 TiffFrameDecode_GetPixelFormat
,
1101 TiffFrameDecode_GetResolution
,
1102 TiffFrameDecode_CopyPalette
,
1103 TiffFrameDecode_CopyPixels
,
1104 TiffFrameDecode_GetMetadataQueryReader
,
1105 TiffFrameDecode_GetColorContexts
,
1106 TiffFrameDecode_GetThumbnail
1109 static HRESULT WINAPI
TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1110 REFIID iid
, void **ppv
)
1112 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1113 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
1116 static ULONG WINAPI
TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
1118 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1119 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
1122 static ULONG WINAPI
TiffFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
1124 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1125 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
1128 static HRESULT WINAPI
TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1131 FIXME("(%p,%p): stub\n", iface
, guid
);
1135 static HRESULT WINAPI
TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
1138 TRACE("%p,%p\n", iface
, count
);
1140 if (!count
) return E_INVALIDARG
;
1146 static HRESULT
create_metadata_reader(TiffFrameDecode
*This
, IWICMetadataReader
**reader
)
1149 LARGE_INTEGER dir_offset
;
1150 IWICMetadataReader
*metadata_reader
;
1151 IWICPersistStream
*persist
;
1153 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1155 hr
= CoCreateInstance(&CLSID_WICIfdMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
1156 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
1157 if (FAILED(hr
)) return hr
;
1159 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1162 IWICMetadataReader_Release(metadata_reader
);
1166 EnterCriticalSection(&This
->parent
->lock
);
1168 dir_offset
.QuadPart
= pTIFFCurrentDirOffset(This
->parent
->tiff
);
1169 hr
= IStream_Seek(This
->parent
->stream
, dir_offset
, STREAM_SEEK_SET
, NULL
);
1172 BOOL byte_swapped
= pTIFFIsByteSwapped(This
->parent
->tiff
);
1173 #ifdef WORDS_BIGENDIAN
1174 DWORD persist_options
= byte_swapped
? WICPersistOptionsLittleEndian
: WICPersistOptionsBigEndian
;
1176 DWORD persist_options
= byte_swapped
? WICPersistOptionsBigEndian
: WICPersistOptionsLittleEndian
;
1178 persist_options
|= WICPersistOptionsNoCacheStream
;
1179 hr
= IWICPersistStream_LoadEx(persist
, This
->parent
->stream
, NULL
, persist_options
);
1181 ERR("IWICPersistStream_LoadEx error %#x\n", hr
);
1184 LeaveCriticalSection(&This
->parent
->lock
);
1186 IWICPersistStream_Release(persist
);
1190 IWICMetadataReader_Release(metadata_reader
);
1194 *reader
= metadata_reader
;
1198 static HRESULT WINAPI
TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1199 UINT index
, IWICMetadataReader
**reader
)
1201 TiffFrameDecode
*This
= impl_from_IWICMetadataBlockReader(iface
);
1203 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1205 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1207 return create_metadata_reader(This
, reader
);
1210 static HRESULT WINAPI
TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1211 IEnumUnknown
**enum_metadata
)
1213 FIXME("(%p,%p): stub\n", iface
, enum_metadata
);
1217 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl
=
1219 TiffFrameDecode_Block_QueryInterface
,
1220 TiffFrameDecode_Block_AddRef
,
1221 TiffFrameDecode_Block_Release
,
1222 TiffFrameDecode_Block_GetContainerFormat
,
1223 TiffFrameDecode_Block_GetCount
,
1224 TiffFrameDecode_Block_GetReaderByIndex
,
1225 TiffFrameDecode_Block_GetEnumerator
1228 HRESULT
TiffDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1233 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1237 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1239 if (!load_libtiff())
1241 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1245 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder
));
1246 if (!This
) return E_OUTOFMEMORY
;
1248 This
->IWICBitmapDecoder_iface
.lpVtbl
= &TiffDecoder_Vtbl
;
1250 This
->stream
= NULL
;
1251 InitializeCriticalSection(&This
->lock
);
1252 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffDecoder.lock");
1254 This
->initialized
= FALSE
;
1256 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1257 IUnknown_Release((IUnknown
*)This
);
1262 struct tiff_encode_format
{
1263 const WICPixelFormatGUID
*guid
;
1269 int extra_sample_type
;
1273 static const struct tiff_encode_format formats
[] = {
1274 {&GUID_WICPixelFormat24bppBGR
, 2, 8, 3, 24, 0, 0, 1},
1275 {&GUID_WICPixelFormatBlackWhite
, 1, 1, 1, 1, 0, 0, 0},
1276 {&GUID_WICPixelFormat4bppGray
, 1, 4, 1, 4, 0, 0, 0},
1277 {&GUID_WICPixelFormat8bppGray
, 1, 8, 1, 8, 0, 0, 0},
1278 {&GUID_WICPixelFormat32bppBGRA
, 2, 8, 4, 32, 1, 2, 1},
1279 {&GUID_WICPixelFormat32bppPBGRA
, 2, 8, 4, 32, 1, 1, 1},
1280 {&GUID_WICPixelFormat48bppRGB
, 2, 16, 3, 48, 0, 0, 0},
1281 {&GUID_WICPixelFormat64bppRGBA
, 2, 16, 4, 64, 1, 2, 0},
1282 {&GUID_WICPixelFormat64bppPRGBA
, 2, 16, 4, 64, 1, 1, 0},
1286 typedef struct TiffEncoder
{
1287 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1290 CRITICAL_SECTION lock
; /* Must be held when tiff is used or fields below are set */
1295 ULONG num_frames_committed
;
1298 static inline TiffEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1300 return CONTAINING_RECORD(iface
, TiffEncoder
, IWICBitmapEncoder_iface
);
1303 typedef struct TiffFrameEncode
{
1304 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1306 TiffEncoder
*parent
;
1307 /* fields below are protected by parent->lock */
1311 const struct tiff_encode_format
*format
;
1317 static inline TiffFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1319 return CONTAINING_RECORD(iface
, TiffFrameEncode
, IWICBitmapFrameEncode_iface
);
1322 static HRESULT WINAPI
TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
1325 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1326 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1328 if (!ppv
) return E_INVALIDARG
;
1330 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1331 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1333 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
1338 return E_NOINTERFACE
;
1341 IUnknown_AddRef((IUnknown
*)*ppv
);
1345 static ULONG WINAPI
TiffFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1347 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1348 ULONG ref
= InterlockedIncrement(&This
->ref
);
1350 TRACE("(%p) refcount=%u\n", iface
, ref
);
1355 static ULONG WINAPI
TiffFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1357 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1358 ULONG ref
= InterlockedDecrement(&This
->ref
);
1360 TRACE("(%p) refcount=%u\n", iface
, ref
);
1364 IWICBitmapEncoder_Release(&This
->parent
->IWICBitmapEncoder_iface
);
1365 HeapFree(GetProcessHeap(), 0, This
);
1371 static HRESULT WINAPI
TiffFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
1372 IPropertyBag2
*pIEncoderOptions
)
1374 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1375 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
1377 EnterCriticalSection(&This
->parent
->lock
);
1379 if (This
->initialized
)
1381 LeaveCriticalSection(&This
->parent
->lock
);
1382 return WINCODEC_ERR_WRONGSTATE
;
1385 This
->initialized
= TRUE
;
1387 LeaveCriticalSection(&This
->parent
->lock
);
1392 static HRESULT WINAPI
TiffFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
1393 UINT uiWidth
, UINT uiHeight
)
1395 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1396 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
1398 EnterCriticalSection(&This
->parent
->lock
);
1400 if (!This
->initialized
|| This
->info_written
)
1402 LeaveCriticalSection(&This
->parent
->lock
);
1403 return WINCODEC_ERR_WRONGSTATE
;
1406 This
->width
= uiWidth
;
1407 This
->height
= uiHeight
;
1409 LeaveCriticalSection(&This
->parent
->lock
);
1414 static HRESULT WINAPI
TiffFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
1415 double dpiX
, double dpiY
)
1417 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1418 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
1420 EnterCriticalSection(&This
->parent
->lock
);
1422 if (!This
->initialized
|| This
->info_written
)
1424 LeaveCriticalSection(&This
->parent
->lock
);
1425 return WINCODEC_ERR_WRONGSTATE
;
1431 LeaveCriticalSection(&This
->parent
->lock
);
1436 static HRESULT WINAPI
TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
1437 WICPixelFormatGUID
*pPixelFormat
)
1439 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1442 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
1444 EnterCriticalSection(&This
->parent
->lock
);
1446 if (!This
->initialized
|| This
->info_written
)
1448 LeaveCriticalSection(&This
->parent
->lock
);
1449 return WINCODEC_ERR_WRONGSTATE
;
1452 for (i
=0; formats
[i
].guid
; i
++)
1454 if (memcmp(formats
[i
].guid
, pPixelFormat
, sizeof(GUID
)) == 0)
1458 if (!formats
[i
].guid
) i
= 0;
1460 This
->format
= &formats
[i
];
1461 memcpy(pPixelFormat
, This
->format
->guid
, sizeof(GUID
));
1463 LeaveCriticalSection(&This
->parent
->lock
);
1468 static HRESULT WINAPI
TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
1469 UINT cCount
, IWICColorContext
**ppIColorContext
)
1471 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1475 static HRESULT WINAPI
TiffFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
1476 IWICPalette
*pIPalette
)
1478 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
1479 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1482 static HRESULT WINAPI
TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
1483 IWICBitmapSource
*pIThumbnail
)
1485 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
1486 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1489 static HRESULT WINAPI
TiffFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
1490 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
1492 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1493 BYTE
*row_data
, *swapped_data
= NULL
;
1494 UINT i
, j
, line_size
;
1496 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
1498 EnterCriticalSection(&This
->parent
->lock
);
1500 if (!This
->initialized
|| !This
->width
|| !This
->height
|| !This
->format
)
1502 LeaveCriticalSection(&This
->parent
->lock
);
1503 return WINCODEC_ERR_WRONGSTATE
;
1506 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->height
)
1508 LeaveCriticalSection(&This
->parent
->lock
);
1509 return E_INVALIDARG
;
1512 line_size
= ((This
->width
* This
->format
->bpp
)+7)/8;
1514 if (This
->format
->reverse_bgr
)
1516 swapped_data
= HeapAlloc(GetProcessHeap(), 0, line_size
);
1519 LeaveCriticalSection(&This
->parent
->lock
);
1520 return E_OUTOFMEMORY
;
1524 if (!This
->info_written
)
1526 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PHOTOMETRIC
, (uint16
)This
->format
->photometric
);
1527 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_PLANARCONFIG
, (uint16
)1);
1528 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_BITSPERSAMPLE
, (uint16
)This
->format
->bps
);
1529 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_SAMPLESPERPIXEL
, (uint16
)This
->format
->samples
);
1531 if (This
->format
->extra_sample
)
1533 uint16 extra_samples
;
1534 extra_samples
= This
->format
->extra_sample_type
;
1536 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_EXTRASAMPLES
, (uint16
)1, &extra_samples
);
1539 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGEWIDTH
, (uint32
)This
->width
);
1540 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_IMAGELENGTH
, (uint32
)This
->height
);
1542 if (This
->xres
!= 0.0 && This
->yres
!= 0.0)
1544 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_RESOLUTIONUNIT
, (uint16
)2); /* Inch */
1545 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_XRESOLUTION
, (float)This
->xres
);
1546 pTIFFSetField(This
->parent
->tiff
, TIFFTAG_YRESOLUTION
, (float)This
->yres
);
1549 This
->info_written
= TRUE
;
1552 for (i
=0; i
<lineCount
; i
++)
1554 row_data
= pbPixels
+ i
* cbStride
;
1556 if (This
->format
->reverse_bgr
&& This
->format
->bps
== 8)
1558 memcpy(swapped_data
, row_data
, line_size
);
1559 for (j
=0; j
<line_size
; j
+= This
->format
->samples
)
1562 temp
= swapped_data
[j
];
1563 swapped_data
[j
] = swapped_data
[j
+2];
1564 swapped_data
[j
+2] = temp
;
1566 row_data
= swapped_data
;
1569 pTIFFWriteScanline(This
->parent
->tiff
, (tdata_t
)row_data
, i
+This
->lines_written
, 0);
1572 This
->lines_written
+= lineCount
;
1574 LeaveCriticalSection(&This
->parent
->lock
);
1576 HeapFree(GetProcessHeap(), 0, swapped_data
);
1581 static HRESULT WINAPI
TiffFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
1582 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
1584 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1587 WICPixelFormatGUID guid
;
1591 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
1593 if (!This
->initialized
|| !This
->width
|| !This
->height
)
1594 return WINCODEC_ERR_WRONGSTATE
;
1598 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1599 if (FAILED(hr
)) return hr
;
1600 hr
= IWICBitmapFrameEncode_SetPixelFormat(iface
, &guid
);
1601 if (FAILED(hr
)) return hr
;
1604 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
1605 if (FAILED(hr
)) return hr
;
1606 if (memcmp(&guid
, This
->format
->guid
, sizeof(GUID
)) != 0)
1608 /* FIXME: should use WICConvertBitmapSource to convert */
1609 ERR("format %s unsupported\n", debugstr_guid(&guid
));
1613 if (This
->xres
== 0.0 || This
->yres
== 0.0)
1616 hr
= IWICBitmapSource_GetResolution(pIBitmapSource
, &xres
, &yres
);
1617 if (FAILED(hr
)) return hr
;
1618 hr
= IWICBitmapFrameEncode_SetResolution(iface
, xres
, yres
);
1619 if (FAILED(hr
)) return hr
;
1625 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
1626 if (FAILED(hr
)) return hr
;
1634 if (prc
->Width
!= This
->width
) return E_INVALIDARG
;
1636 stride
= (This
->format
->bpp
* This
->width
+ 7)/8;
1638 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
1639 if (!pixeldata
) return E_OUTOFMEMORY
;
1641 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
1642 stride
*prc
->Height
, pixeldata
);
1646 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
1647 stride
*prc
->Height
, pixeldata
);
1650 HeapFree(GetProcessHeap(), 0, pixeldata
);
1655 static HRESULT WINAPI
TiffFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1657 TiffFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1659 TRACE("(%p)\n", iface
);
1661 EnterCriticalSection(&This
->parent
->lock
);
1663 if (!This
->info_written
|| This
->lines_written
!= This
->height
|| This
->committed
)
1665 LeaveCriticalSection(&This
->parent
->lock
);
1666 return WINCODEC_ERR_WRONGSTATE
;
1669 /* libtiff will commit the data when creating a new frame or closing the file */
1671 This
->committed
= TRUE
;
1672 This
->parent
->num_frames_committed
++;
1674 LeaveCriticalSection(&This
->parent
->lock
);
1679 static HRESULT WINAPI
TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
1680 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1682 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
1686 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl
= {
1687 TiffFrameEncode_QueryInterface
,
1688 TiffFrameEncode_AddRef
,
1689 TiffFrameEncode_Release
,
1690 TiffFrameEncode_Initialize
,
1691 TiffFrameEncode_SetSize
,
1692 TiffFrameEncode_SetResolution
,
1693 TiffFrameEncode_SetPixelFormat
,
1694 TiffFrameEncode_SetColorContexts
,
1695 TiffFrameEncode_SetPalette
,
1696 TiffFrameEncode_SetThumbnail
,
1697 TiffFrameEncode_WritePixels
,
1698 TiffFrameEncode_WriteSource
,
1699 TiffFrameEncode_Commit
,
1700 TiffFrameEncode_GetMetadataQueryWriter
1703 static HRESULT WINAPI
TiffEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
1706 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1707 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1709 if (!ppv
) return E_INVALIDARG
;
1711 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1712 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
1719 return E_NOINTERFACE
;
1722 IUnknown_AddRef((IUnknown
*)*ppv
);
1726 static ULONG WINAPI
TiffEncoder_AddRef(IWICBitmapEncoder
*iface
)
1728 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1729 ULONG ref
= InterlockedIncrement(&This
->ref
);
1731 TRACE("(%p) refcount=%u\n", iface
, ref
);
1736 static ULONG WINAPI
TiffEncoder_Release(IWICBitmapEncoder
*iface
)
1738 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1739 ULONG ref
= InterlockedDecrement(&This
->ref
);
1741 TRACE("(%p) refcount=%u\n", iface
, ref
);
1745 if (This
->tiff
) pTIFFClose(This
->tiff
);
1746 if (This
->stream
) IStream_Release(This
->stream
);
1747 This
->lock
.DebugInfo
->Spare
[0] = 0;
1748 DeleteCriticalSection(&This
->lock
);
1749 HeapFree(GetProcessHeap(), 0, This
);
1755 static HRESULT WINAPI
TiffEncoder_Initialize(IWICBitmapEncoder
*iface
,
1756 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
1758 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1762 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
1764 EnterCriticalSection(&This
->lock
);
1766 if (This
->initialized
|| This
->committed
)
1768 hr
= WINCODEC_ERR_WRONGSTATE
;
1772 tiff
= tiff_open_stream(pIStream
, "w");
1781 This
->stream
= pIStream
;
1782 IStream_AddRef(pIStream
);
1783 This
->initialized
= TRUE
;
1786 LeaveCriticalSection(&This
->lock
);
1790 static HRESULT WINAPI
TiffEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
1791 GUID
*pguidContainerFormat
)
1793 memcpy(pguidContainerFormat
, &GUID_ContainerFormatTiff
, sizeof(GUID
));
1797 static HRESULT WINAPI
TiffEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
1798 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
1800 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
1804 static HRESULT WINAPI
TiffEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
1805 UINT cCount
, IWICColorContext
**ppIColorContext
)
1807 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
1811 static HRESULT WINAPI
TiffEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
1813 TRACE("(%p,%p)\n", iface
, pIPalette
);
1814 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1817 static HRESULT WINAPI
TiffEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
1819 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
1820 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1823 static HRESULT WINAPI
TiffEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
1825 TRACE("(%p,%p)\n", iface
, pIPreview
);
1826 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1829 static HRESULT WINAPI
TiffEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
1830 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
1832 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1833 TiffFrameEncode
*result
;
1837 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
1839 EnterCriticalSection(&This
->lock
);
1841 if (!This
->initialized
|| This
->committed
)
1843 hr
= WINCODEC_ERR_WRONGSTATE
;
1845 else if (This
->num_frames
!= This
->num_frames_committed
)
1847 FIXME("New frame created before previous frame was committed\n");
1853 hr
= CreatePropertyBag2(ppIEncoderOptions
);
1858 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(*result
));
1862 result
->IWICBitmapFrameEncode_iface
.lpVtbl
= &TiffFrameEncode_Vtbl
;
1864 result
->parent
= This
;
1865 result
->initialized
= FALSE
;
1866 result
->info_written
= FALSE
;
1867 result
->committed
= FALSE
;
1868 result
->format
= NULL
;
1873 result
->lines_written
= 0;
1875 IWICBitmapEncoder_AddRef(iface
);
1876 *ppIFrameEncode
= &result
->IWICBitmapFrameEncode_iface
;
1878 if (This
->num_frames
!= 0)
1879 pTIFFWriteDirectory(This
->tiff
);
1888 IPropertyBag2_Release(*ppIEncoderOptions
);
1889 *ppIEncoderOptions
= NULL
;
1893 LeaveCriticalSection(&This
->lock
);
1898 static HRESULT WINAPI
TiffEncoder_Commit(IWICBitmapEncoder
*iface
)
1900 TiffEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
1902 TRACE("(%p)\n", iface
);
1904 EnterCriticalSection(&This
->lock
);
1906 if (!This
->initialized
|| This
->committed
)
1908 LeaveCriticalSection(&This
->lock
);
1909 return WINCODEC_ERR_WRONGSTATE
;
1912 pTIFFClose(This
->tiff
);
1913 IStream_Release(This
->stream
);
1914 This
->stream
= NULL
;
1917 This
->committed
= TRUE
;
1919 LeaveCriticalSection(&This
->lock
);
1924 static HRESULT WINAPI
TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
1925 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
1927 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
1931 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl
= {
1932 TiffEncoder_QueryInterface
,
1934 TiffEncoder_Release
,
1935 TiffEncoder_Initialize
,
1936 TiffEncoder_GetContainerFormat
,
1937 TiffEncoder_GetEncoderInfo
,
1938 TiffEncoder_SetColorContexts
,
1939 TiffEncoder_SetPalette
,
1940 TiffEncoder_SetThumbnail
,
1941 TiffEncoder_SetPreview
,
1942 TiffEncoder_CreateNewFrame
,
1944 TiffEncoder_GetMetadataQueryWriter
1947 HRESULT
TiffEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1952 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1956 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1958 if (!load_libtiff())
1960 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF
);
1964 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder
));
1965 if (!This
) return E_OUTOFMEMORY
;
1967 This
->IWICBitmapEncoder_iface
.lpVtbl
= &TiffEncoder_Vtbl
;
1969 This
->stream
= NULL
;
1970 InitializeCriticalSection(&This
->lock
);
1971 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TiffEncoder.lock");
1973 This
->initialized
= FALSE
;
1974 This
->num_frames
= 0;
1975 This
->num_frames_committed
= 0;
1976 This
->committed
= FALSE
;
1978 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
1979 IUnknown_Release((IUnknown
*)This
);
1984 #else /* !SONAME_LIBTIFF */
1986 HRESULT
TiffDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1988 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
1992 HRESULT
TiffEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1994 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");