msvcp90: Added basic_iostream<char> implementation.
[wine] / dlls / windowscodecs / tiffformat.c
1 /*
2  * Copyright 2010 Vincent Povirk for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include "config.h"
20 #include "wine/port.h"
21
22 #include <stdarg.h>
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_TIFFIO_H
27 #include <tiffio.h>
28 #endif
29
30 #define COBJMACROS
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "objbase.h"
35 #include "wincodec.h"
36 #include "wincodecsdk.h"
37
38 #include "wincodecs_private.h"
39
40 #include "wine/debug.h"
41 #include "wine/library.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
44
45 #ifdef SONAME_LIBTIFF
46
47 static CRITICAL_SECTION init_tiff_cs;
48 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug =
49 {
50     0, 0, &init_tiff_cs,
51     { &init_tiff_cs_debug.ProcessLocksList,
52       &init_tiff_cs_debug.ProcessLocksList },
53     0, 0, { (DWORD_PTR)(__FILE__ ": init_tiff_cs") }
54 };
55 static CRITICAL_SECTION init_tiff_cs = { &init_tiff_cs_debug, -1, 0, 0, 0, 0 };
56
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(TIFFCurrentDirectory);
62 MAKE_FUNCPTR(TIFFGetField);
63 MAKE_FUNCPTR(TIFFIsByteSwapped);
64 MAKE_FUNCPTR(TIFFReadDirectory);
65 MAKE_FUNCPTR(TIFFReadEncodedStrip);
66 MAKE_FUNCPTR(TIFFReadEncodedTile);
67 MAKE_FUNCPTR(TIFFSetDirectory);
68 MAKE_FUNCPTR(TIFFSetField);
69 MAKE_FUNCPTR(TIFFWriteDirectory);
70 MAKE_FUNCPTR(TIFFWriteScanline);
71 #undef MAKE_FUNCPTR
72
73 static void *load_libtiff(void)
74 {
75     void *result;
76
77     EnterCriticalSection(&init_tiff_cs);
78
79     if (!libtiff_handle &&
80         (libtiff_handle = wine_dlopen(SONAME_LIBTIFF, RTLD_NOW, NULL, 0)) != NULL)
81     {
82
83 #define LOAD_FUNCPTR(f) \
84     if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
85         ERR("failed to load symbol %s\n", #f); \
86         libtiff_handle = NULL; \
87         LeaveCriticalSection(&init_tiff_cs); \
88         return NULL; \
89     }
90         LOAD_FUNCPTR(TIFFClientOpen);
91         LOAD_FUNCPTR(TIFFClose);
92         LOAD_FUNCPTR(TIFFCurrentDirectory);
93         LOAD_FUNCPTR(TIFFGetField);
94         LOAD_FUNCPTR(TIFFIsByteSwapped);
95         LOAD_FUNCPTR(TIFFReadDirectory);
96         LOAD_FUNCPTR(TIFFReadEncodedStrip);
97         LOAD_FUNCPTR(TIFFReadEncodedTile);
98         LOAD_FUNCPTR(TIFFSetDirectory);
99         LOAD_FUNCPTR(TIFFSetField);
100         LOAD_FUNCPTR(TIFFWriteDirectory);
101         LOAD_FUNCPTR(TIFFWriteScanline);
102 #undef LOAD_FUNCPTR
103
104     }
105
106     result = libtiff_handle;
107
108     LeaveCriticalSection(&init_tiff_cs);
109     return result;
110 }
111
112 static tsize_t tiff_stream_read(thandle_t client_data, tdata_t data, tsize_t size)
113 {
114     IStream *stream = (IStream*)client_data;
115     ULONG bytes_read;
116     HRESULT hr;
117
118     hr = IStream_Read(stream, data, size, &bytes_read);
119     if (FAILED(hr)) bytes_read = 0;
120     return bytes_read;
121 }
122
123 static tsize_t tiff_stream_write(thandle_t client_data, tdata_t data, tsize_t size)
124 {
125     IStream *stream = (IStream*)client_data;
126     ULONG bytes_written;
127     HRESULT hr;
128
129     hr = IStream_Write(stream, data, size, &bytes_written);
130     if (FAILED(hr)) bytes_written = 0;
131     return bytes_written;
132 }
133
134 static toff_t tiff_stream_seek(thandle_t client_data, toff_t offset, int whence)
135 {
136     IStream *stream = (IStream*)client_data;
137     LARGE_INTEGER move;
138     DWORD origin;
139     ULARGE_INTEGER new_position;
140     HRESULT hr;
141
142     move.QuadPart = offset;
143     switch (whence)
144     {
145         case SEEK_SET:
146             origin = STREAM_SEEK_SET;
147             break;
148         case SEEK_CUR:
149             origin = STREAM_SEEK_CUR;
150             break;
151         case SEEK_END:
152             origin = STREAM_SEEK_END;
153             break;
154         default:
155             ERR("unknown whence value %i\n", whence);
156             return -1;
157     }
158
159     hr = IStream_Seek(stream, move, origin, &new_position);
160     if (SUCCEEDED(hr)) return new_position.QuadPart;
161     else return -1;
162 }
163
164 static int tiff_stream_close(thandle_t client_data)
165 {
166     /* Caller is responsible for releasing the stream object. */
167     return 0;
168 }
169
170 static toff_t tiff_stream_size(thandle_t client_data)
171 {
172     IStream *stream = (IStream*)client_data;
173     STATSTG statstg;
174     HRESULT hr;
175
176     hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
177
178     if (SUCCEEDED(hr)) return statstg.cbSize.QuadPart;
179     else return -1;
180 }
181
182 static int tiff_stream_map(thandle_t client_data, tdata_t *addr, toff_t *size)
183 {
184     /* Cannot mmap streams */
185     return 0;
186 }
187
188 static void tiff_stream_unmap(thandle_t client_data, tdata_t addr, toff_t size)
189 {
190     /* No need to ever do this, since we can't map things. */
191 }
192
193 static TIFF* tiff_open_stream(IStream *stream, const char *mode)
194 {
195     LARGE_INTEGER zero;
196
197     zero.QuadPart = 0;
198     IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
199
200     return pTIFFClientOpen("<IStream object>", mode, stream, tiff_stream_read,
201         tiff_stream_write, tiff_stream_seek, tiff_stream_close,
202         tiff_stream_size, tiff_stream_map, tiff_stream_unmap);
203 }
204
205 typedef struct {
206     IWICBitmapDecoder IWICBitmapDecoder_iface;
207     LONG ref;
208     IStream *stream;
209     CRITICAL_SECTION lock; /* Must be held when tiff is used or initiailzed is set */
210     TIFF *tiff;
211     BOOL initialized;
212 } TiffDecoder;
213
214 typedef struct {
215     const WICPixelFormatGUID *format;
216     int bps;
217     int samples;
218     int bpp;
219     int planar;
220     int indexed;
221     int reverse_bgr;
222     int invert_grayscale;
223     UINT width, height;
224     UINT tile_width, tile_height;
225     UINT tile_stride;
226     UINT tile_size;
227     int tiled;
228     UINT tiles_across;
229     UINT resolution_unit;
230     float xres, yres;
231 } tiff_decode_info;
232
233 typedef struct {
234     IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
235     IWICMetadataBlockReader IWICMetadataBlockReader_iface;
236     LONG ref;
237     TiffDecoder *parent;
238     UINT index;
239     tiff_decode_info decode_info;
240     INT cached_tile_x, cached_tile_y;
241     BYTE *cached_tile;
242 } TiffFrameDecode;
243
244 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl;
245 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl;
246
247 static inline TiffDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
248 {
249     return CONTAINING_RECORD(iface, TiffDecoder, IWICBitmapDecoder_iface);
250 }
251
252 static inline TiffFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
253 {
254     return CONTAINING_RECORD(iface, TiffFrameDecode, IWICBitmapFrameDecode_iface);
255 }
256
257 static inline TiffFrameDecode *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
258 {
259     return CONTAINING_RECORD(iface, TiffFrameDecode, IWICMetadataBlockReader_iface);
260 }
261
262 static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
263 {
264     uint16 photometric, bps, samples, planar;
265     uint16 extra_sample_count, extra_sample, *extra_samples;
266     int ret;
267
268     decode_info->indexed = 0;
269     decode_info->reverse_bgr = 0;
270     decode_info->invert_grayscale = 0;
271     decode_info->tiled = 0;
272
273     ret = pTIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
274     if (!ret)
275     {
276         WARN("missing PhotometricInterpretation tag\n");
277         return E_FAIL;
278     }
279
280     ret = pTIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps);
281     if (!ret) bps = 1;
282     decode_info->bps = bps;
283
284     ret = pTIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
285     if (!ret) samples = 1;
286     decode_info->samples = samples;
287
288     if (samples == 1)
289         planar = 1;
290     else
291     {
292         ret = pTIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar);
293         if (!ret) planar = 1;
294         if (planar != 1)
295         {
296             FIXME("unhandled planar configuration %u\n", planar);
297             return E_FAIL;
298         }
299     }
300     decode_info->planar = planar;
301
302     switch(photometric)
303     {
304     case 0: /* WhiteIsZero */
305         decode_info->invert_grayscale = 1;
306         /* fall through */
307     case 1: /* BlackIsZero */
308         if (samples != 1)
309         {
310             FIXME("unhandled grayscale sample count %u\n", samples);
311             return E_FAIL;
312         }
313
314         decode_info->bpp = bps;
315         switch (bps)
316         {
317         case 1:
318             decode_info->format = &GUID_WICPixelFormatBlackWhite;
319             break;
320         case 4:
321             decode_info->format = &GUID_WICPixelFormat4bppGray;
322             break;
323         case 8:
324             decode_info->format = &GUID_WICPixelFormat8bppGray;
325             break;
326         default:
327             FIXME("unhandled greyscale bit count %u\n", bps);
328             return E_FAIL;
329         }
330         break;
331     case 2: /* RGB */
332         decode_info->bpp = bps * samples;
333
334         if (samples == 4)
335         {
336             ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
337             if (!ret)
338             {
339                 extra_sample_count = 1;
340                 extra_sample = 0;
341                 extra_samples = &extra_sample;
342             }
343         }
344         else if (samples != 3)
345         {
346             FIXME("unhandled RGB sample count %u\n", samples);
347             return E_FAIL;
348         }
349
350         switch(bps)
351         {
352         case 8:
353             decode_info->reverse_bgr = 1;
354             if (samples == 3)
355                 decode_info->format = &GUID_WICPixelFormat24bppBGR;
356             else
357                 switch(extra_samples[0])
358                 {
359                 case 1: /* Associated (pre-multiplied) alpha data */
360                     decode_info->format = &GUID_WICPixelFormat32bppPBGRA;
361                     break;
362                 case 0: /* Unspecified data */
363                 case 2: /* Unassociated alpha data */
364                     decode_info->format = &GUID_WICPixelFormat32bppBGRA;
365                     break;
366                 default:
367                     FIXME("unhandled extra sample type %i\n", extra_samples[0]);
368                     return E_FAIL;
369                 }
370             break;
371         case 16:
372             if (samples == 3)
373                 decode_info->format = &GUID_WICPixelFormat48bppRGB;
374             else
375                 switch(extra_samples[0])
376                 {
377                 case 1: /* Associated (pre-multiplied) alpha data */
378                     decode_info->format = &GUID_WICPixelFormat64bppPRGBA;
379                     break;
380                 case 0: /* Unspecified data */
381                 case 2: /* Unassociated alpha data */
382                     decode_info->format = &GUID_WICPixelFormat64bppRGBA;
383                     break;
384                 default:
385                     FIXME("unhandled extra sample type %i\n", extra_samples[0]);
386                     return E_FAIL;
387                 }
388             break;
389         default:
390             FIXME("unhandled RGB bit count %u\n", bps);
391             return E_FAIL;
392         }
393         break;
394     case 3: /* RGB Palette */
395         if (samples != 1)
396         {
397             FIXME("unhandled indexed sample count %u\n", samples);
398             return E_FAIL;
399         }
400
401         decode_info->indexed = 1;
402         decode_info->bpp = bps;
403         switch (bps)
404         {
405         case 4:
406             decode_info->format = &GUID_WICPixelFormat4bppIndexed;
407             break;
408         case 8:
409             decode_info->format = &GUID_WICPixelFormat8bppIndexed;
410             break;
411         default:
412             FIXME("unhandled indexed bit count %u\n", bps);
413             return E_FAIL;
414         }
415         break;
416     case 4: /* Transparency mask */
417     case 5: /* CMYK */
418     case 6: /* YCbCr */
419     case 8: /* CIELab */
420     default:
421         FIXME("unhandled PhotometricInterpretation %u\n", photometric);
422         return E_FAIL;
423     }
424
425     ret = pTIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->width);
426     if (!ret)
427     {
428         WARN("missing image width\n");
429         return E_FAIL;
430     }
431
432     ret = pTIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->height);
433     if (!ret)
434     {
435         WARN("missing image length\n");
436         return E_FAIL;
437     }
438
439     if ((ret = pTIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width)))
440     {
441         decode_info->tiled = 1;
442
443         if (!ret)
444         {
445             WARN("missing tile width\n");
446             return E_FAIL;
447         }
448
449         ret = pTIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height);
450         if (!ret)
451         {
452             WARN("missing tile height\n");
453             return E_FAIL;
454         }
455
456         decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8);
457         decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
458         decode_info->tiles_across = (decode_info->width + decode_info->tile_width - 1) / decode_info->tile_width;
459     }
460     else if ((ret = pTIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height)))
461     {
462         if (decode_info->tile_height > decode_info->height)
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;
467     }
468     else
469     {
470         /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
471         decode_info->tile_height = decode_info->height;
472         decode_info->tile_width = decode_info->width;
473         decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8);
474         decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
475     }
476
477     decode_info->resolution_unit = 0;
478     pTIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &decode_info->resolution_unit);
479     if (decode_info->resolution_unit != 0)
480     {
481         ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &decode_info->xres);
482         if (!ret)
483         {
484             WARN("missing X resolution\n");
485             decode_info->resolution_unit = 0;
486         }
487
488         ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &decode_info->yres);
489         if (!ret)
490         {
491             WARN("missing Y resolution\n");
492             decode_info->resolution_unit = 0;
493         }
494     }
495
496     return S_OK;
497 }
498
499 static HRESULT WINAPI TiffDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
500     void **ppv)
501 {
502     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
503     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
504
505     if (!ppv) return E_INVALIDARG;
506
507     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
508     {
509         *ppv = This;
510     }
511     else
512     {
513         *ppv = NULL;
514         return E_NOINTERFACE;
515     }
516
517     IUnknown_AddRef((IUnknown*)*ppv);
518     return S_OK;
519 }
520
521 static ULONG WINAPI TiffDecoder_AddRef(IWICBitmapDecoder *iface)
522 {
523     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
524     ULONG ref = InterlockedIncrement(&This->ref);
525
526     TRACE("(%p) refcount=%u\n", iface, ref);
527
528     return ref;
529 }
530
531 static ULONG WINAPI TiffDecoder_Release(IWICBitmapDecoder *iface)
532 {
533     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
534     ULONG ref = InterlockedDecrement(&This->ref);
535
536     TRACE("(%p) refcount=%u\n", iface, ref);
537
538     if (ref == 0)
539     {
540         if (This->tiff) pTIFFClose(This->tiff);
541         if (This->stream) IStream_Release(This->stream);
542         This->lock.DebugInfo->Spare[0] = 0;
543         DeleteCriticalSection(&This->lock);
544         HeapFree(GetProcessHeap(), 0, This);
545     }
546
547     return ref;
548 }
549
550 static HRESULT WINAPI TiffDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
551     DWORD *pdwCapability)
552 {
553     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
554     return E_NOTIMPL;
555 }
556
557 static HRESULT WINAPI TiffDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
558     WICDecodeOptions cacheOptions)
559 {
560     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
561     TIFF *tiff;
562     HRESULT hr=S_OK;
563
564     TRACE("(%p,%p,%x): stub\n", iface, pIStream, cacheOptions);
565
566     EnterCriticalSection(&This->lock);
567
568     if (This->initialized)
569     {
570         hr = WINCODEC_ERR_WRONGSTATE;
571         goto exit;
572     }
573
574     tiff = tiff_open_stream(pIStream, "r");
575
576     if (!tiff)
577     {
578         hr = E_FAIL;
579         goto exit;
580     }
581
582     This->tiff = tiff;
583     This->stream = pIStream;
584     IStream_AddRef(pIStream);
585     This->initialized = TRUE;
586
587 exit:
588     LeaveCriticalSection(&This->lock);
589     return hr;
590 }
591
592 static HRESULT WINAPI TiffDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
593     GUID *pguidContainerFormat)
594 {
595     memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID));
596     return S_OK;
597 }
598
599 static HRESULT WINAPI TiffDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
600     IWICBitmapDecoderInfo **ppIDecoderInfo)
601 {
602     HRESULT hr;
603     IWICComponentInfo *compinfo;
604
605     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
606
607     hr = CreateComponentInfo(&CLSID_WICTiffDecoder, &compinfo);
608     if (FAILED(hr)) return hr;
609
610     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
611         (void**)ppIDecoderInfo);
612
613     IWICComponentInfo_Release(compinfo);
614
615     return hr;
616 }
617
618 static HRESULT WINAPI TiffDecoder_CopyPalette(IWICBitmapDecoder *iface,
619     IWICPalette *pIPalette)
620 {
621     FIXME("(%p,%p): stub\n", iface, pIPalette);
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
626     IWICMetadataQueryReader **ppIMetadataQueryReader)
627 {
628     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
629     return E_NOTIMPL;
630 }
631
632 static HRESULT WINAPI TiffDecoder_GetPreview(IWICBitmapDecoder *iface,
633     IWICBitmapSource **ppIBitmapSource)
634 {
635     FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
636     return E_NOTIMPL;
637 }
638
639 static HRESULT WINAPI TiffDecoder_GetColorContexts(IWICBitmapDecoder *iface,
640     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
641 {
642     FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
643     return E_NOTIMPL;
644 }
645
646 static HRESULT WINAPI TiffDecoder_GetThumbnail(IWICBitmapDecoder *iface,
647     IWICBitmapSource **ppIThumbnail)
648 {
649     TRACE("(%p,%p)\n", iface, ppIThumbnail);
650     return WINCODEC_ERR_CODECNOTHUMBNAIL;
651 }
652
653 static HRESULT WINAPI TiffDecoder_GetFrameCount(IWICBitmapDecoder *iface,
654     UINT *pCount)
655 {
656     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
657
658     if (!This->tiff)
659     {
660         WARN("(%p) <-- WINCODEC_ERR_WRONGSTATE\n", iface);
661         return WINCODEC_ERR_WRONGSTATE;
662     }
663
664     EnterCriticalSection(&This->lock);
665     while (pTIFFReadDirectory(This->tiff)) { }
666     *pCount = pTIFFCurrentDirectory(This->tiff)+1;
667     LeaveCriticalSection(&This->lock);
668
669     TRACE("(%p) <-- %i\n", iface, *pCount);
670
671     return S_OK;
672 }
673
674 static HRESULT WINAPI TiffDecoder_GetFrame(IWICBitmapDecoder *iface,
675     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
676 {
677     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
678     TiffFrameDecode *result;
679     int res;
680     tiff_decode_info decode_info;
681     HRESULT hr;
682
683     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
684
685     if (!This->tiff)
686         return WINCODEC_ERR_WRONGSTATE;
687
688     EnterCriticalSection(&This->lock);
689     res = pTIFFSetDirectory(This->tiff, index);
690     if (!res) hr = E_INVALIDARG;
691     else hr = tiff_get_decode_info(This->tiff, &decode_info);
692     LeaveCriticalSection(&This->lock);
693
694     if (SUCCEEDED(hr))
695     {
696         result = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode));
697
698         if (result)
699         {
700             result->IWICBitmapFrameDecode_iface.lpVtbl = &TiffFrameDecode_Vtbl;
701             result->IWICMetadataBlockReader_iface.lpVtbl = &TiffFrameDecode_BlockVtbl;
702             result->ref = 1;
703             result->parent = This;
704             result->index = index;
705             result->decode_info = decode_info;
706             result->cached_tile_x = -1;
707             result->cached_tile = HeapAlloc(GetProcessHeap(), 0, decode_info.tile_size);
708
709             if (result->cached_tile)
710                 *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
711             else
712             {
713                 hr = E_OUTOFMEMORY;
714                 HeapFree(GetProcessHeap(), 0, result);
715             }
716         }
717         else hr = E_OUTOFMEMORY;
718     }
719
720     if (FAILED(hr)) *ppIBitmapFrame = NULL;
721
722     return hr;
723 }
724
725 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl = {
726     TiffDecoder_QueryInterface,
727     TiffDecoder_AddRef,
728     TiffDecoder_Release,
729     TiffDecoder_QueryCapability,
730     TiffDecoder_Initialize,
731     TiffDecoder_GetContainerFormat,
732     TiffDecoder_GetDecoderInfo,
733     TiffDecoder_CopyPalette,
734     TiffDecoder_GetMetadataQueryReader,
735     TiffDecoder_GetPreview,
736     TiffDecoder_GetColorContexts,
737     TiffDecoder_GetThumbnail,
738     TiffDecoder_GetFrameCount,
739     TiffDecoder_GetFrame
740 };
741
742 static HRESULT WINAPI TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
743     void **ppv)
744 {
745     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
746     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
747
748     if (!ppv) return E_INVALIDARG;
749
750     if (IsEqualIID(&IID_IUnknown, iid) ||
751         IsEqualIID(&IID_IWICBitmapSource, iid) ||
752         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
753     {
754         *ppv = This;
755     }
756     else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
757     {
758         *ppv = &This->IWICMetadataBlockReader_iface;
759     }
760     else
761     {
762         *ppv = NULL;
763         return E_NOINTERFACE;
764     }
765
766     IUnknown_AddRef((IUnknown*)*ppv);
767     return S_OK;
768 }
769
770 static ULONG WINAPI TiffFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
771 {
772     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
773     ULONG ref = InterlockedIncrement(&This->ref);
774
775     TRACE("(%p) refcount=%u\n", iface, ref);
776
777     return ref;
778 }
779
780 static ULONG WINAPI TiffFrameDecode_Release(IWICBitmapFrameDecode *iface)
781 {
782     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
783     ULONG ref = InterlockedDecrement(&This->ref);
784
785     TRACE("(%p) refcount=%u\n", iface, ref);
786
787     if (ref == 0)
788     {
789         HeapFree(GetProcessHeap(), 0, This->cached_tile);
790         HeapFree(GetProcessHeap(), 0, This);
791     }
792
793     return ref;
794 }
795
796 static HRESULT WINAPI TiffFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
797     UINT *puiWidth, UINT *puiHeight)
798 {
799     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
800
801     *puiWidth = This->decode_info.width;
802     *puiHeight = This->decode_info.height;
803
804     TRACE("(%p) <-- %ux%u\n", iface, *puiWidth, *puiHeight);
805
806     return S_OK;
807 }
808
809 static HRESULT WINAPI TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
810     WICPixelFormatGUID *pPixelFormat)
811 {
812     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
813
814     memcpy(pPixelFormat, This->decode_info.format, sizeof(GUID));
815
816     TRACE("(%p) <-- %s\n", This, debugstr_guid(This->decode_info.format));
817
818     return S_OK;
819 }
820
821 static HRESULT WINAPI TiffFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
822     double *pDpiX, double *pDpiY)
823 {
824     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
825
826     switch (This->decode_info.resolution_unit)
827     {
828     default:
829         FIXME("unknown resolution unit %i\n", This->decode_info.resolution_unit);
830         /* fall through */
831     case 0: /* Not set */
832         *pDpiX = *pDpiY = 96.0;
833         break;
834     case 1: /* Relative measurements */
835         *pDpiX = 96.0;
836         *pDpiY = 96.0 * This->decode_info.yres / This->decode_info.xres;
837         break;
838     case 2: /* Inch */
839         *pDpiX = This->decode_info.xres;
840         *pDpiY = This->decode_info.yres;
841         break;
842     case 3: /* Centimeter */
843         *pDpiX = This->decode_info.xres / 2.54;
844         *pDpiY = This->decode_info.yres / 2.54;
845         break;
846     }
847
848     TRACE("(%p) <-- %f,%f unit=%i\n", iface, *pDpiX, *pDpiY, This->decode_info.resolution_unit);
849
850     return S_OK;
851 }
852
853 static HRESULT WINAPI TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
854     IWICPalette *pIPalette)
855 {
856     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
857     uint16 *red, *green, *blue;
858     WICColor colors[256];
859     int color_count, ret, i;
860
861     TRACE("(%p,%p)\n", iface, pIPalette);
862
863     color_count = 1<<This->decode_info.bps;
864
865     EnterCriticalSection(&This->parent->lock);
866     ret = pTIFFGetField(This->parent->tiff, TIFFTAG_COLORMAP, &red, &green, &blue);
867     LeaveCriticalSection(&This->parent->lock);
868
869     if (!ret)
870     {
871         WARN("Couldn't read color map\n");
872         return E_FAIL;
873     }
874
875     for (i=0; i<color_count; i++)
876     {
877         colors[i] = 0xff000000 |
878             ((red[i]<<8) & 0xff0000) |
879             (green[i] & 0xff00) |
880             ((blue[i]>>8) & 0xff);
881     }
882
883     return IWICPalette_InitializeCustom(pIPalette, colors, color_count);
884 }
885
886 static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT tile_y)
887 {
888     HRESULT hr=S_OK;
889     tsize_t ret;
890     int swap_bytes;
891
892     swap_bytes = pTIFFIsByteSwapped(This->parent->tiff);
893
894     ret = pTIFFSetDirectory(This->parent->tiff, This->index);
895
896     if (ret == -1)
897         hr = E_FAIL;
898
899     if (hr == S_OK)
900     {
901         if (This->decode_info.tiled)
902         {
903             ret = pTIFFReadEncodedTile(This->parent->tiff, tile_x + tile_y * This->decode_info.tiles_across, This->cached_tile, This->decode_info.tile_size);
904         }
905         else
906         {
907             ret = pTIFFReadEncodedStrip(This->parent->tiff, tile_y, This->cached_tile, This->decode_info.tile_size);
908         }
909
910         if (ret == -1)
911             hr = E_FAIL;
912     }
913
914     if (hr == S_OK && This->decode_info.reverse_bgr)
915     {
916         if (This->decode_info.bps == 8)
917         {
918             UINT sample_count = This->decode_info.samples;
919
920             reverse_bgr8(sample_count, This->cached_tile, This->decode_info.tile_width,
921                 This->decode_info.tile_height, This->decode_info.tile_width * sample_count);
922         }
923     }
924
925     if (hr == S_OK && swap_bytes && This->decode_info.bps > 8)
926     {
927         UINT row, i, samples_per_row;
928         BYTE *sample, temp;
929
930         samples_per_row = This->decode_info.tile_width * This->decode_info.samples;
931
932         switch(This->decode_info.bps)
933         {
934         case 16:
935             for (row=0; row<This->decode_info.tile_height; row++)
936             {
937                 sample = This->cached_tile + row * This->decode_info.tile_stride;
938                 for (i=0; i<samples_per_row; i++)
939                 {
940                     temp = sample[1];
941                     sample[1] = sample[0];
942                     sample[0] = temp;
943                     sample += 2;
944                 }
945             }
946             break;
947         default:
948             ERR("unhandled bps for byte swap %u\n", This->decode_info.bps);
949             return E_FAIL;
950         }
951     }
952
953     if (hr == S_OK && This->decode_info.invert_grayscale)
954     {
955         BYTE *byte, *end;
956
957         if (This->decode_info.samples != 1)
958         {
959             ERR("cannot invert grayscale image with %u samples\n", This->decode_info.samples);
960             return E_FAIL;
961         }
962
963         end = This->cached_tile+This->decode_info.tile_size;
964
965         for (byte = This->cached_tile; byte != end; byte++)
966             *byte = ~(*byte);
967     }
968
969     if (hr == S_OK)
970     {
971         This->cached_tile_x = tile_x;
972         This->cached_tile_y = tile_y;
973     }
974
975     return hr;
976 }
977
978 static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
979     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
980 {
981     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
982     UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y;
983     UINT tile_x, tile_y;
984     WICRect rc;
985     HRESULT hr=S_OK;
986     BYTE *dst_tilepos;
987     UINT bytesperrow;
988     WICRect rect;
989
990     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
991
992     if (!prc)
993     {
994         rect.X = 0;
995         rect.Y = 0;
996         rect.Width = This->decode_info.width;
997         rect.Height = This->decode_info.height;
998         prc = &rect;
999     }
1000     else
1001     {
1002         if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->decode_info.width ||
1003             prc->Y+prc->Height > This->decode_info.height)
1004             return E_INVALIDARG;
1005     }
1006
1007     bytesperrow = ((This->decode_info.bpp * prc->Width)+7)/8;
1008
1009     if (cbStride < bytesperrow)
1010         return E_INVALIDARG;
1011
1012     if ((cbStride * prc->Height) > cbBufferSize)
1013         return E_INVALIDARG;
1014
1015     min_tile_x = prc->X / This->decode_info.tile_width;
1016     min_tile_y = prc->Y / This->decode_info.tile_height;
1017     max_tile_x = (prc->X+prc->Width-1) / This->decode_info.tile_width;
1018     max_tile_y = (prc->Y+prc->Height-1) / This->decode_info.tile_height;
1019
1020     EnterCriticalSection(&This->parent->lock);
1021
1022     for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++)
1023     {
1024         for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++)
1025         {
1026             if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y)
1027             {
1028                 hr = TiffFrameDecode_ReadTile(This, tile_x, tile_y);
1029             }
1030
1031             if (SUCCEEDED(hr))
1032             {
1033                 if (prc->X < tile_x * This->decode_info.tile_width)
1034                     rc.X = 0;
1035                 else
1036                     rc.X = prc->X - tile_x * This->decode_info.tile_width;
1037
1038                 if (prc->Y < tile_y * This->decode_info.tile_height)
1039                     rc.Y = 0;
1040                 else
1041                     rc.Y = prc->Y - tile_y * This->decode_info.tile_height;
1042
1043                 if (prc->X+prc->Width > (tile_x+1) * This->decode_info.tile_width)
1044                     rc.Width = This->decode_info.tile_width - rc.X;
1045                 else if (prc->X < tile_x * This->decode_info.tile_width)
1046                     rc.Width = prc->Width + prc->X - tile_x * This->decode_info.tile_width;
1047                 else
1048                     rc.Width = prc->Width;
1049
1050                 if (prc->Y+prc->Height > (tile_y+1) * This->decode_info.tile_height)
1051                     rc.Height = This->decode_info.tile_height - rc.Y;
1052                 else if (prc->Y < tile_y * This->decode_info.tile_height)
1053                     rc.Height = prc->Height + prc->Y - tile_y * This->decode_info.tile_height;
1054                 else
1055                     rc.Height = prc->Height;
1056
1057                 dst_tilepos = pbBuffer + (cbStride * ((rc.Y + tile_y * This->decode_info.tile_height) - prc->Y)) +
1058                     ((This->decode_info.bpp * ((rc.X + tile_x * This->decode_info.tile_width) - prc->X) + 7) / 8);
1059
1060                 hr = copy_pixels(This->decode_info.bpp, This->cached_tile,
1061                     This->decode_info.tile_width, This->decode_info.tile_height, This->decode_info.tile_stride,
1062                     &rc, cbStride, cbBufferSize, dst_tilepos);
1063             }
1064
1065             if (FAILED(hr))
1066             {
1067                 LeaveCriticalSection(&This->parent->lock);
1068                 TRACE("<-- 0x%x\n", hr);
1069                 return hr;
1070             }
1071         }
1072     }
1073
1074     LeaveCriticalSection(&This->parent->lock);
1075
1076     return S_OK;
1077 }
1078
1079 static HRESULT WINAPI TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
1080     IWICMetadataQueryReader **ppIMetadataQueryReader)
1081 {
1082     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
1083     return E_NOTIMPL;
1084 }
1085
1086 static HRESULT WINAPI TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
1087     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1088 {
1089     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
1090     return E_NOTIMPL;
1091 }
1092
1093 static HRESULT WINAPI TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
1094     IWICBitmapSource **ppIThumbnail)
1095 {
1096     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
1097     return E_NOTIMPL;
1098 }
1099
1100 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl = {
1101     TiffFrameDecode_QueryInterface,
1102     TiffFrameDecode_AddRef,
1103     TiffFrameDecode_Release,
1104     TiffFrameDecode_GetSize,
1105     TiffFrameDecode_GetPixelFormat,
1106     TiffFrameDecode_GetResolution,
1107     TiffFrameDecode_CopyPalette,
1108     TiffFrameDecode_CopyPixels,
1109     TiffFrameDecode_GetMetadataQueryReader,
1110     TiffFrameDecode_GetColorContexts,
1111     TiffFrameDecode_GetThumbnail
1112 };
1113
1114 static HRESULT WINAPI TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
1115     REFIID iid, void **ppv)
1116 {
1117     TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
1118     return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
1119 }
1120
1121 static ULONG WINAPI TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
1122 {
1123     TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
1124     return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
1125 }
1126
1127 static ULONG WINAPI TiffFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
1128 {
1129     TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
1130     return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
1131 }
1132
1133 static HRESULT WINAPI TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1134     GUID *guid)
1135 {
1136     FIXME("(%p,%p): stub\n", iface, guid);
1137     return E_NOTIMPL;
1138 }
1139
1140 static HRESULT WINAPI TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
1141     UINT *count)
1142 {
1143     FIXME("(%p,%p): stub\n", iface, count);
1144     return E_NOTIMPL;
1145 }
1146
1147 static HRESULT WINAPI TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1148     UINT index, IWICMetadataReader **reader)
1149 {
1150     FIXME("(%p,%u,%p): stub\n", iface, index, reader);
1151     return E_NOTIMPL;
1152 }
1153
1154 static HRESULT WINAPI TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1155     IEnumUnknown **enum_metadata)
1156 {
1157     FIXME("(%p,%p): stub\n", iface, enum_metadata);
1158     return E_NOTIMPL;
1159 }
1160
1161 static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl =
1162 {
1163     TiffFrameDecode_Block_QueryInterface,
1164     TiffFrameDecode_Block_AddRef,
1165     TiffFrameDecode_Block_Release,
1166     TiffFrameDecode_Block_GetContainerFormat,
1167     TiffFrameDecode_Block_GetCount,
1168     TiffFrameDecode_Block_GetReaderByIndex,
1169     TiffFrameDecode_Block_GetEnumerator
1170 };
1171
1172 HRESULT TiffDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1173 {
1174     HRESULT ret;
1175     TiffDecoder *This;
1176
1177     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1178
1179     *ppv = NULL;
1180
1181     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1182
1183     if (!load_libtiff())
1184     {
1185         ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF);
1186         return E_FAIL;
1187     }
1188
1189     This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder));
1190     if (!This) return E_OUTOFMEMORY;
1191
1192     This->IWICBitmapDecoder_iface.lpVtbl = &TiffDecoder_Vtbl;
1193     This->ref = 1;
1194     This->stream = NULL;
1195     InitializeCriticalSection(&This->lock);
1196     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffDecoder.lock");
1197     This->tiff = NULL;
1198     This->initialized = FALSE;
1199
1200     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
1201     IUnknown_Release((IUnknown*)This);
1202
1203     return ret;
1204 }
1205
1206 struct tiff_encode_format {
1207     const WICPixelFormatGUID *guid;
1208     int photometric;
1209     int bps;
1210     int samples;
1211     int bpp;
1212     int extra_sample;
1213     int extra_sample_type;
1214     int reverse_bgr;
1215 };
1216
1217 static const struct tiff_encode_format formats[] = {
1218     {&GUID_WICPixelFormat24bppBGR, 2, 8, 3, 24, 0, 0, 1},
1219     {&GUID_WICPixelFormatBlackWhite, 1, 1, 1, 1, 0, 0, 0},
1220     {&GUID_WICPixelFormat4bppGray, 1, 4, 1, 4, 0, 0, 0},
1221     {&GUID_WICPixelFormat8bppGray, 1, 8, 1, 8, 0, 0, 0},
1222     {&GUID_WICPixelFormat32bppBGRA, 2, 8, 4, 32, 1, 2, 1},
1223     {&GUID_WICPixelFormat32bppPBGRA, 2, 8, 4, 32, 1, 1, 1},
1224     {&GUID_WICPixelFormat48bppRGB, 2, 16, 3, 48, 0, 0, 0},
1225     {&GUID_WICPixelFormat64bppRGBA, 2, 16, 4, 64, 1, 2, 0},
1226     {&GUID_WICPixelFormat64bppPRGBA, 2, 16, 4, 64, 1, 1, 0},
1227     {0}
1228 };
1229
1230 typedef struct TiffEncoder {
1231     IWICBitmapEncoder IWICBitmapEncoder_iface;
1232     LONG ref;
1233     IStream *stream;
1234     CRITICAL_SECTION lock; /* Must be held when tiff is used or fields below are set */
1235     TIFF *tiff;
1236     BOOL initialized;
1237     BOOL committed;
1238     ULONG num_frames;
1239     ULONG num_frames_committed;
1240 } TiffEncoder;
1241
1242 static inline TiffEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1243 {
1244     return CONTAINING_RECORD(iface, TiffEncoder, IWICBitmapEncoder_iface);
1245 }
1246
1247 typedef struct TiffFrameEncode {
1248     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1249     LONG ref;
1250     TiffEncoder *parent;
1251     /* fields below are protected by parent->lock */
1252     BOOL initialized;
1253     BOOL info_written;
1254     BOOL committed;
1255     const struct tiff_encode_format *format;
1256     UINT width, height;
1257     double xres, yres;
1258     UINT lines_written;
1259 } TiffFrameEncode;
1260
1261 static inline TiffFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1262 {
1263     return CONTAINING_RECORD(iface, TiffFrameEncode, IWICBitmapFrameEncode_iface);
1264 }
1265
1266 static HRESULT WINAPI TiffFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
1267     void **ppv)
1268 {
1269     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1270     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1271
1272     if (!ppv) return E_INVALIDARG;
1273
1274     if (IsEqualIID(&IID_IUnknown, iid) ||
1275         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1276     {
1277         *ppv = &This->IWICBitmapFrameEncode_iface;
1278     }
1279     else
1280     {
1281         *ppv = NULL;
1282         return E_NOINTERFACE;
1283     }
1284
1285     IUnknown_AddRef((IUnknown*)*ppv);
1286     return S_OK;
1287 }
1288
1289 static ULONG WINAPI TiffFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1290 {
1291     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1292     ULONG ref = InterlockedIncrement(&This->ref);
1293
1294     TRACE("(%p) refcount=%u\n", iface, ref);
1295
1296     return ref;
1297 }
1298
1299 static ULONG WINAPI TiffFrameEncode_Release(IWICBitmapFrameEncode *iface)
1300 {
1301     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1302     ULONG ref = InterlockedDecrement(&This->ref);
1303
1304     TRACE("(%p) refcount=%u\n", iface, ref);
1305
1306     if (ref == 0)
1307     {
1308         IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface);
1309         HeapFree(GetProcessHeap(), 0, This);
1310     }
1311
1312     return ref;
1313 }
1314
1315 static HRESULT WINAPI TiffFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
1316     IPropertyBag2 *pIEncoderOptions)
1317 {
1318     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1319     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
1320
1321     EnterCriticalSection(&This->parent->lock);
1322
1323     if (This->initialized)
1324     {
1325         LeaveCriticalSection(&This->parent->lock);
1326         return WINCODEC_ERR_WRONGSTATE;
1327     }
1328
1329     This->initialized = TRUE;
1330
1331     LeaveCriticalSection(&This->parent->lock);
1332
1333     return S_OK;
1334 }
1335
1336 static HRESULT WINAPI TiffFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
1337     UINT uiWidth, UINT uiHeight)
1338 {
1339     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1340     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
1341
1342     EnterCriticalSection(&This->parent->lock);
1343
1344     if (!This->initialized || This->info_written)
1345     {
1346         LeaveCriticalSection(&This->parent->lock);
1347         return WINCODEC_ERR_WRONGSTATE;
1348     }
1349
1350     This->width = uiWidth;
1351     This->height = uiHeight;
1352
1353     LeaveCriticalSection(&This->parent->lock);
1354
1355     return S_OK;
1356 }
1357
1358 static HRESULT WINAPI TiffFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
1359     double dpiX, double dpiY)
1360 {
1361     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1362     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
1363
1364     EnterCriticalSection(&This->parent->lock);
1365
1366     if (!This->initialized || This->info_written)
1367     {
1368         LeaveCriticalSection(&This->parent->lock);
1369         return WINCODEC_ERR_WRONGSTATE;
1370     }
1371
1372     This->xres = dpiX;
1373     This->yres = dpiY;
1374
1375     LeaveCriticalSection(&This->parent->lock);
1376
1377     return S_OK;
1378 }
1379
1380 static HRESULT WINAPI TiffFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
1381     WICPixelFormatGUID *pPixelFormat)
1382 {
1383     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1384     int i;
1385
1386     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
1387
1388     EnterCriticalSection(&This->parent->lock);
1389
1390     if (!This->initialized || This->info_written)
1391     {
1392         LeaveCriticalSection(&This->parent->lock);
1393         return WINCODEC_ERR_WRONGSTATE;
1394     }
1395
1396     for (i=0; formats[i].guid; i++)
1397     {
1398         if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
1399             break;
1400     }
1401
1402     if (!formats[i].guid) i = 0;
1403
1404     This->format = &formats[i];
1405     memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
1406
1407     LeaveCriticalSection(&This->parent->lock);
1408
1409     return S_OK;
1410 }
1411
1412 static HRESULT WINAPI TiffFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
1413     UINT cCount, IWICColorContext **ppIColorContext)
1414 {
1415     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1416     return E_NOTIMPL;
1417 }
1418
1419 static HRESULT WINAPI TiffFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
1420     IWICPalette *pIPalette)
1421 {
1422     FIXME("(%p,%p): stub\n", iface, pIPalette);
1423     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1424 }
1425
1426 static HRESULT WINAPI TiffFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
1427     IWICBitmapSource *pIThumbnail)
1428 {
1429     FIXME("(%p,%p): stub\n", iface, pIThumbnail);
1430     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1431 }
1432
1433 static HRESULT WINAPI TiffFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
1434     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
1435 {
1436     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1437     BYTE *row_data, *swapped_data = NULL;
1438     UINT i, j, line_size;
1439
1440     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
1441
1442     EnterCriticalSection(&This->parent->lock);
1443
1444     if (!This->initialized || !This->width || !This->height || !This->format)
1445     {
1446         LeaveCriticalSection(&This->parent->lock);
1447         return WINCODEC_ERR_WRONGSTATE;
1448     }
1449
1450     if (lineCount == 0 || lineCount + This->lines_written > This->height)
1451     {
1452         LeaveCriticalSection(&This->parent->lock);
1453         return E_INVALIDARG;
1454     }
1455
1456     line_size = ((This->width * This->format->bpp)+7)/8;
1457
1458     if (This->format->reverse_bgr)
1459     {
1460         swapped_data = HeapAlloc(GetProcessHeap(), 0, line_size);
1461         if (!swapped_data)
1462         {
1463             LeaveCriticalSection(&This->parent->lock);
1464             return E_OUTOFMEMORY;
1465         }
1466     }
1467
1468     if (!This->info_written)
1469     {
1470         pTIFFSetField(This->parent->tiff, TIFFTAG_PHOTOMETRIC, (uint16)This->format->photometric);
1471         pTIFFSetField(This->parent->tiff, TIFFTAG_PLANARCONFIG, (uint16)1);
1472         pTIFFSetField(This->parent->tiff, TIFFTAG_BITSPERSAMPLE, (uint16)This->format->bps);
1473         pTIFFSetField(This->parent->tiff, TIFFTAG_SAMPLESPERPIXEL, (uint16)This->format->samples);
1474
1475         if (This->format->extra_sample)
1476         {
1477             uint16 extra_samples;
1478             extra_samples = This->format->extra_sample_type;
1479
1480             pTIFFSetField(This->parent->tiff, TIFFTAG_EXTRASAMPLES, (uint16)1, &extra_samples);
1481         }
1482
1483         pTIFFSetField(This->parent->tiff, TIFFTAG_IMAGEWIDTH, (uint32)This->width);
1484         pTIFFSetField(This->parent->tiff, TIFFTAG_IMAGELENGTH, (uint32)This->height);
1485
1486         if (This->xres != 0.0 && This->yres != 0.0)
1487         {
1488             pTIFFSetField(This->parent->tiff, TIFFTAG_RESOLUTIONUNIT, (uint16)2); /* Inch */
1489             pTIFFSetField(This->parent->tiff, TIFFTAG_XRESOLUTION, (float)This->xres);
1490             pTIFFSetField(This->parent->tiff, TIFFTAG_YRESOLUTION, (float)This->yres);
1491         }
1492
1493         This->info_written = TRUE;
1494     }
1495
1496     for (i=0; i<lineCount; i++)
1497     {
1498         row_data = pbPixels + i * cbStride;
1499
1500         if (This->format->reverse_bgr && This->format->bps == 8)
1501         {
1502             memcpy(swapped_data, row_data, line_size);
1503             for (j=0; j<line_size; j += This->format->samples)
1504             {
1505                 BYTE temp;
1506                 temp = swapped_data[j];
1507                 swapped_data[j] = swapped_data[j+2];
1508                 swapped_data[j+2] = temp;
1509             }
1510             row_data = swapped_data;
1511         }
1512
1513         pTIFFWriteScanline(This->parent->tiff, (tdata_t)row_data, i+This->lines_written, 0);
1514     }
1515
1516     This->lines_written += lineCount;
1517
1518     LeaveCriticalSection(&This->parent->lock);
1519
1520     HeapFree(GetProcessHeap(), 0, swapped_data);
1521
1522     return S_OK;
1523 }
1524
1525 static HRESULT WINAPI TiffFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
1526     IWICBitmapSource *pIBitmapSource, WICRect *prc)
1527 {
1528     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1529     HRESULT hr;
1530     WICRect rc;
1531     WICPixelFormatGUID guid;
1532     UINT stride;
1533     BYTE *pixeldata;
1534
1535     TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
1536
1537     if (!This->initialized || !This->width || !This->height)
1538         return WINCODEC_ERR_WRONGSTATE;
1539
1540     if (!This->format)
1541     {
1542         hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
1543         if (FAILED(hr)) return hr;
1544         hr = IWICBitmapFrameEncode_SetPixelFormat(iface, &guid);
1545         if (FAILED(hr)) return hr;
1546     }
1547
1548     hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
1549     if (FAILED(hr)) return hr;
1550     if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
1551     {
1552         /* FIXME: should use WICConvertBitmapSource to convert */
1553         ERR("format %s unsupported\n", debugstr_guid(&guid));
1554         return E_FAIL;
1555     }
1556
1557     if (This->xres == 0.0 || This->yres == 0.0)
1558     {
1559         double xres, yres;
1560         hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
1561         if (FAILED(hr)) return hr;
1562         hr = IWICBitmapFrameEncode_SetResolution(iface, xres, yres);
1563         if (FAILED(hr)) return hr;
1564     }
1565
1566     if (!prc)
1567     {
1568         UINT width, height;
1569         hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
1570         if (FAILED(hr)) return hr;
1571         rc.X = 0;
1572         rc.Y = 0;
1573         rc.Width = width;
1574         rc.Height = height;
1575         prc = &rc;
1576     }
1577
1578     if (prc->Width != This->width) return E_INVALIDARG;
1579
1580     stride = (This->format->bpp * This->width + 7)/8;
1581
1582     pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
1583     if (!pixeldata) return E_OUTOFMEMORY;
1584
1585     hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
1586         stride*prc->Height, pixeldata);
1587
1588     if (SUCCEEDED(hr))
1589     {
1590         hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
1591             stride*prc->Height, pixeldata);
1592     }
1593
1594     HeapFree(GetProcessHeap(), 0, pixeldata);
1595
1596     return S_OK;
1597 }
1598
1599 static HRESULT WINAPI TiffFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1600 {
1601     TiffFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1602
1603     TRACE("(%p)\n", iface);
1604
1605     EnterCriticalSection(&This->parent->lock);
1606
1607     if (!This->info_written || This->lines_written != This->height || This->committed)
1608     {
1609         LeaveCriticalSection(&This->parent->lock);
1610         return WINCODEC_ERR_WRONGSTATE;
1611     }
1612
1613     /* libtiff will commit the data when creating a new frame or closing the file */
1614
1615     This->committed = TRUE;
1616     This->parent->num_frames_committed++;
1617
1618     LeaveCriticalSection(&This->parent->lock);
1619
1620     return S_OK;
1621 }
1622
1623 static HRESULT WINAPI TiffFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
1624     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1625 {
1626     FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
1627     return E_NOTIMPL;
1628 }
1629
1630 static const IWICBitmapFrameEncodeVtbl TiffFrameEncode_Vtbl = {
1631     TiffFrameEncode_QueryInterface,
1632     TiffFrameEncode_AddRef,
1633     TiffFrameEncode_Release,
1634     TiffFrameEncode_Initialize,
1635     TiffFrameEncode_SetSize,
1636     TiffFrameEncode_SetResolution,
1637     TiffFrameEncode_SetPixelFormat,
1638     TiffFrameEncode_SetColorContexts,
1639     TiffFrameEncode_SetPalette,
1640     TiffFrameEncode_SetThumbnail,
1641     TiffFrameEncode_WritePixels,
1642     TiffFrameEncode_WriteSource,
1643     TiffFrameEncode_Commit,
1644     TiffFrameEncode_GetMetadataQueryWriter
1645 };
1646
1647 static HRESULT WINAPI TiffEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
1648     void **ppv)
1649 {
1650     TiffEncoder *This = impl_from_IWICBitmapEncoder(iface);
1651     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1652
1653     if (!ppv) return E_INVALIDARG;
1654
1655     if (IsEqualIID(&IID_IUnknown, iid) ||
1656         IsEqualIID(&IID_IWICBitmapEncoder, iid))
1657     {
1658         *ppv = This;
1659     }
1660     else
1661     {
1662         *ppv = NULL;
1663         return E_NOINTERFACE;
1664     }
1665
1666     IUnknown_AddRef((IUnknown*)*ppv);
1667     return S_OK;
1668 }
1669
1670 static ULONG WINAPI TiffEncoder_AddRef(IWICBitmapEncoder *iface)
1671 {
1672     TiffEncoder *This = impl_from_IWICBitmapEncoder(iface);
1673     ULONG ref = InterlockedIncrement(&This->ref);
1674
1675     TRACE("(%p) refcount=%u\n", iface, ref);
1676
1677     return ref;
1678 }
1679
1680 static ULONG WINAPI TiffEncoder_Release(IWICBitmapEncoder *iface)
1681 {
1682     TiffEncoder *This = impl_from_IWICBitmapEncoder(iface);
1683     ULONG ref = InterlockedDecrement(&This->ref);
1684
1685     TRACE("(%p) refcount=%u\n", iface, ref);
1686
1687     if (ref == 0)
1688     {
1689         if (This->tiff) pTIFFClose(This->tiff);
1690         if (This->stream) IStream_Release(This->stream);
1691         This->lock.DebugInfo->Spare[0] = 0;
1692         DeleteCriticalSection(&This->lock);
1693         HeapFree(GetProcessHeap(), 0, This);
1694     }
1695
1696     return ref;
1697 }
1698
1699 static HRESULT WINAPI TiffEncoder_Initialize(IWICBitmapEncoder *iface,
1700     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
1701 {
1702     TiffEncoder *This = impl_from_IWICBitmapEncoder(iface);
1703     TIFF *tiff;
1704     HRESULT hr=S_OK;
1705
1706     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
1707
1708     EnterCriticalSection(&This->lock);
1709
1710     if (This->initialized || This->committed)
1711     {
1712         hr = WINCODEC_ERR_WRONGSTATE;
1713         goto exit;
1714     }
1715
1716     tiff = tiff_open_stream(pIStream, "w");
1717
1718     if (!tiff)
1719     {
1720         hr = E_FAIL;
1721         goto exit;
1722     }
1723
1724     This->tiff = tiff;
1725     This->stream = pIStream;
1726     IStream_AddRef(pIStream);
1727     This->initialized = TRUE;
1728
1729 exit:
1730     LeaveCriticalSection(&This->lock);
1731     return hr;
1732 }
1733
1734 static HRESULT WINAPI TiffEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
1735     GUID *pguidContainerFormat)
1736 {
1737     memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID));
1738     return S_OK;
1739 }
1740
1741 static HRESULT WINAPI TiffEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
1742     IWICBitmapEncoderInfo **ppIEncoderInfo)
1743 {
1744     FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
1745     return E_NOTIMPL;
1746 }
1747
1748 static HRESULT WINAPI TiffEncoder_SetColorContexts(IWICBitmapEncoder *iface,
1749     UINT cCount, IWICColorContext **ppIColorContext)
1750 {
1751     FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
1752     return E_NOTIMPL;
1753 }
1754
1755 static HRESULT WINAPI TiffEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
1756 {
1757     TRACE("(%p,%p)\n", iface, pIPalette);
1758     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1759 }
1760
1761 static HRESULT WINAPI TiffEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
1762 {
1763     TRACE("(%p,%p)\n", iface, pIThumbnail);
1764     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1765 }
1766
1767 static HRESULT WINAPI TiffEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
1768 {
1769     TRACE("(%p,%p)\n", iface, pIPreview);
1770     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1771 }
1772
1773 static HRESULT WINAPI TiffEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
1774     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
1775 {
1776     TiffEncoder *This = impl_from_IWICBitmapEncoder(iface);
1777     TiffFrameEncode *result;
1778
1779     HRESULT hr=S_OK;
1780
1781     TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
1782
1783     EnterCriticalSection(&This->lock);
1784
1785     if (!This->initialized || This->committed)
1786     {
1787         hr = WINCODEC_ERR_WRONGSTATE;
1788     }
1789     else if (This->num_frames != This->num_frames_committed)
1790     {
1791         FIXME("New frame created before previous frame was committed\n");
1792         hr = E_FAIL;
1793     }
1794
1795     if (SUCCEEDED(hr))
1796     {
1797         hr = CreatePropertyBag2(ppIEncoderOptions);
1798     }
1799
1800     if (SUCCEEDED(hr))
1801     {
1802         result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result));
1803
1804         if (result)
1805         {
1806             result->IWICBitmapFrameEncode_iface.lpVtbl = &TiffFrameEncode_Vtbl;
1807             result->ref = 1;
1808             result->parent = This;
1809             result->initialized = FALSE;
1810             result->info_written = FALSE;
1811             result->committed = FALSE;
1812             result->format = NULL;
1813             result->width = 0;
1814             result->height = 0;
1815             result->xres = 0.0;
1816             result->yres = 0.0;
1817             result->lines_written = 0;
1818
1819             IWICBitmapEncoder_AddRef(iface);
1820             *ppIFrameEncode = &result->IWICBitmapFrameEncode_iface;
1821
1822             if (This->num_frames != 0)
1823                 pTIFFWriteDirectory(This->tiff);
1824
1825             This->num_frames++;
1826         }
1827         else
1828             hr = E_OUTOFMEMORY;
1829
1830         if (FAILED(hr))
1831         {
1832             IPropertyBag2_Release(*ppIEncoderOptions);
1833             *ppIEncoderOptions = NULL;
1834         }
1835     }
1836
1837     LeaveCriticalSection(&This->lock);
1838
1839     return hr;
1840 }
1841
1842 static HRESULT WINAPI TiffEncoder_Commit(IWICBitmapEncoder *iface)
1843 {
1844     TiffEncoder *This = impl_from_IWICBitmapEncoder(iface);
1845
1846     TRACE("(%p)\n", iface);
1847
1848     EnterCriticalSection(&This->lock);
1849
1850     if (!This->initialized || This->committed)
1851     {
1852         LeaveCriticalSection(&This->lock);
1853         return WINCODEC_ERR_WRONGSTATE;
1854     }
1855
1856     pTIFFClose(This->tiff);
1857     IStream_Release(This->stream);
1858     This->stream = NULL;
1859     This->tiff = NULL;
1860
1861     This->committed = TRUE;
1862
1863     LeaveCriticalSection(&This->lock);
1864
1865     return S_OK;
1866 }
1867
1868 static HRESULT WINAPI TiffEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
1869     IWICMetadataQueryWriter **ppIMetadataQueryWriter)
1870 {
1871     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
1872     return E_NOTIMPL;
1873 }
1874
1875 static const IWICBitmapEncoderVtbl TiffEncoder_Vtbl = {
1876     TiffEncoder_QueryInterface,
1877     TiffEncoder_AddRef,
1878     TiffEncoder_Release,
1879     TiffEncoder_Initialize,
1880     TiffEncoder_GetContainerFormat,
1881     TiffEncoder_GetEncoderInfo,
1882     TiffEncoder_SetColorContexts,
1883     TiffEncoder_SetPalette,
1884     TiffEncoder_SetThumbnail,
1885     TiffEncoder_SetPreview,
1886     TiffEncoder_CreateNewFrame,
1887     TiffEncoder_Commit,
1888     TiffEncoder_GetMetadataQueryWriter
1889 };
1890
1891 HRESULT TiffEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1892 {
1893     TiffEncoder *This;
1894     HRESULT ret;
1895
1896     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1897
1898     *ppv = NULL;
1899
1900     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1901
1902     if (!load_libtiff())
1903     {
1904         ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF);
1905         return E_FAIL;
1906     }
1907
1908     This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffEncoder));
1909     if (!This) return E_OUTOFMEMORY;
1910
1911     This->IWICBitmapEncoder_iface.lpVtbl = &TiffEncoder_Vtbl;
1912     This->ref = 1;
1913     This->stream = NULL;
1914     InitializeCriticalSection(&This->lock);
1915     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffEncoder.lock");
1916     This->tiff = NULL;
1917     This->initialized = FALSE;
1918     This->num_frames = 0;
1919     This->num_frames_committed = 0;
1920     This->committed = FALSE;
1921
1922     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
1923     IUnknown_Release((IUnknown*)This);
1924
1925     return ret;
1926 }
1927
1928 #else /* !SONAME_LIBTIFF */
1929
1930 HRESULT TiffDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1931 {
1932     ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
1933     return E_FAIL;
1934 }
1935
1936 HRESULT TiffEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1937 {
1938     ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");
1939     return E_FAIL;
1940 }
1941
1942 #endif