comctl32: Use current month and year when checking day of month.
[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
37 #include "wincodecs_private.h"
38
39 #include "wine/debug.h"
40 #include "wine/library.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
43
44 #ifdef SONAME_LIBTIFF
45
46 static CRITICAL_SECTION init_tiff_cs;
47 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug =
48 {
49     0, 0, &init_tiff_cs,
50     { &init_tiff_cs_debug.ProcessLocksList,
51       &init_tiff_cs_debug.ProcessLocksList },
52     0, 0, { (DWORD_PTR)(__FILE__ ": init_tiff_cs") }
53 };
54 static CRITICAL_SECTION init_tiff_cs = { &init_tiff_cs_debug, -1, 0, 0, 0, 0 };
55
56 static void *libtiff_handle;
57 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
58 MAKE_FUNCPTR(TIFFClientOpen);
59 MAKE_FUNCPTR(TIFFClose);
60 MAKE_FUNCPTR(TIFFCurrentDirectory);
61 MAKE_FUNCPTR(TIFFGetField);
62 MAKE_FUNCPTR(TIFFIsByteSwapped);
63 MAKE_FUNCPTR(TIFFReadDirectory);
64 MAKE_FUNCPTR(TIFFReadEncodedStrip);
65 MAKE_FUNCPTR(TIFFReadEncodedTile);
66 MAKE_FUNCPTR(TIFFSetDirectory);
67 #undef MAKE_FUNCPTR
68
69 static void *load_libtiff(void)
70 {
71     void *result;
72
73     EnterCriticalSection(&init_tiff_cs);
74
75     if (!libtiff_handle &&
76         (libtiff_handle = wine_dlopen(SONAME_LIBTIFF, RTLD_NOW, NULL, 0)) != NULL)
77     {
78
79 #define LOAD_FUNCPTR(f) \
80     if((p##f = wine_dlsym(libtiff_handle, #f, NULL, 0)) == NULL) { \
81         ERR("failed to load symbol %s\n", #f); \
82         libtiff_handle = NULL; \
83         LeaveCriticalSection(&init_tiff_cs); \
84         return NULL; \
85     }
86         LOAD_FUNCPTR(TIFFClientOpen);
87         LOAD_FUNCPTR(TIFFClose);
88         LOAD_FUNCPTR(TIFFCurrentDirectory);
89         LOAD_FUNCPTR(TIFFGetField);
90         LOAD_FUNCPTR(TIFFIsByteSwapped);
91         LOAD_FUNCPTR(TIFFReadDirectory);
92         LOAD_FUNCPTR(TIFFReadEncodedStrip);
93         LOAD_FUNCPTR(TIFFReadEncodedTile);
94         LOAD_FUNCPTR(TIFFSetDirectory);
95 #undef LOAD_FUNCPTR
96
97     }
98
99     result = libtiff_handle;
100
101     LeaveCriticalSection(&init_tiff_cs);
102     return result;
103 }
104
105 static tsize_t tiff_stream_read(thandle_t client_data, tdata_t data, tsize_t size)
106 {
107     IStream *stream = (IStream*)client_data;
108     ULONG bytes_read;
109     HRESULT hr;
110
111     hr = IStream_Read(stream, data, size, &bytes_read);
112     if (FAILED(hr)) bytes_read = 0;
113     return bytes_read;
114 }
115
116 static tsize_t tiff_stream_write(thandle_t client_data, tdata_t data, tsize_t size)
117 {
118     IStream *stream = (IStream*)client_data;
119     ULONG bytes_written;
120     HRESULT hr;
121
122     hr = IStream_Write(stream, data, size, &bytes_written);
123     if (FAILED(hr)) bytes_written = 0;
124     return bytes_written;
125 }
126
127 static toff_t tiff_stream_seek(thandle_t client_data, toff_t offset, int whence)
128 {
129     IStream *stream = (IStream*)client_data;
130     LARGE_INTEGER move;
131     DWORD origin;
132     ULARGE_INTEGER new_position;
133     HRESULT hr;
134
135     move.QuadPart = offset;
136     switch (whence)
137     {
138         case SEEK_SET:
139             origin = STREAM_SEEK_SET;
140             break;
141         case SEEK_CUR:
142             origin = STREAM_SEEK_CUR;
143             break;
144         case SEEK_END:
145             origin = STREAM_SEEK_END;
146             break;
147         default:
148             ERR("unknown whence value %i\n", whence);
149             return -1;
150     }
151
152     hr = IStream_Seek(stream, move, origin, &new_position);
153     if (SUCCEEDED(hr)) return new_position.QuadPart;
154     else return -1;
155 }
156
157 static int tiff_stream_close(thandle_t client_data)
158 {
159     /* Caller is responsible for releasing the stream object. */
160     return 0;
161 }
162
163 static toff_t tiff_stream_size(thandle_t client_data)
164 {
165     IStream *stream = (IStream*)client_data;
166     STATSTG statstg;
167     HRESULT hr;
168
169     hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
170
171     if (SUCCEEDED(hr)) return statstg.cbSize.QuadPart;
172     else return -1;
173 }
174
175 static int tiff_stream_map(thandle_t client_data, tdata_t *addr, toff_t *size)
176 {
177     /* Cannot mmap streams */
178     return 0;
179 }
180
181 static void tiff_stream_unmap(thandle_t client_data, tdata_t addr, toff_t size)
182 {
183     /* No need to ever do this, since we can't map things. */
184 }
185
186 static TIFF* tiff_open_stream(IStream *stream, const char *mode)
187 {
188     LARGE_INTEGER zero;
189
190     zero.QuadPart = 0;
191     IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL);
192
193     return pTIFFClientOpen("<IStream object>", mode, stream, tiff_stream_read,
194         tiff_stream_write, tiff_stream_seek, tiff_stream_close,
195         tiff_stream_size, tiff_stream_map, tiff_stream_unmap);
196 }
197
198 typedef struct {
199     IWICBitmapDecoder IWICBitmapDecoder_iface;
200     LONG ref;
201     IStream *stream;
202     CRITICAL_SECTION lock; /* Must be held when tiff is used or initiailzed is set */
203     TIFF *tiff;
204     BOOL initialized;
205 } TiffDecoder;
206
207 typedef struct {
208     const WICPixelFormatGUID *format;
209     int bps;
210     int samples;
211     int bpp;
212     int planar;
213     int indexed;
214     int reverse_bgr;
215     int invert_grayscale;
216     UINT width, height;
217     UINT tile_width, tile_height;
218     UINT tile_stride;
219     UINT tile_size;
220     int tiled;
221     UINT tiles_across;
222 } tiff_decode_info;
223
224 typedef struct {
225     IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
226     LONG ref;
227     TiffDecoder *parent;
228     UINT index;
229     tiff_decode_info decode_info;
230     INT cached_tile_x, cached_tile_y;
231     BYTE *cached_tile;
232 } TiffFrameDecode;
233
234 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl;
235
236 static inline TiffDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
237 {
238     return CONTAINING_RECORD(iface, TiffDecoder, IWICBitmapDecoder_iface);
239 }
240
241 static inline TiffFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
242 {
243     return CONTAINING_RECORD(iface, TiffFrameDecode, IWICBitmapFrameDecode_iface);
244 }
245
246 static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
247 {
248     uint16 photometric, bps, samples, planar;
249     uint16 extra_sample_count, *extra_samples;
250     int ret;
251
252     decode_info->indexed = 0;
253     decode_info->reverse_bgr = 0;
254     decode_info->invert_grayscale = 0;
255     decode_info->tiled = 0;
256
257     ret = pTIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
258     if (!ret)
259     {
260         WARN("missing PhotometricInterpretation tag\n");
261         return E_FAIL;
262     }
263
264     ret = pTIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps);
265     if (!ret) bps = 1;
266     decode_info->bps = bps;
267
268     ret = pTIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
269     if (!ret) samples = 1;
270     decode_info->samples = samples;
271
272     if (samples == 1)
273         planar = 1;
274     else
275     {
276         ret = pTIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar);
277         if (!ret) planar = 1;
278         if (planar != 1)
279         {
280             FIXME("unhandled planar configuration %u\n", planar);
281             return E_FAIL;
282         }
283     }
284     decode_info->planar = planar;
285
286     switch(photometric)
287     {
288     case 0: /* WhiteIsZero */
289         decode_info->invert_grayscale = 1;
290     case 1: /* BlackIsZero */
291         if (samples != 1)
292         {
293             FIXME("unhandled grayscale sample count %u\n", samples);
294             return E_FAIL;
295         }
296
297         decode_info->bpp = bps;
298         switch (bps)
299         {
300         case 1:
301             decode_info->format = &GUID_WICPixelFormatBlackWhite;
302             break;
303         case 4:
304             decode_info->format = &GUID_WICPixelFormat4bppGray;
305             break;
306         case 8:
307             decode_info->format = &GUID_WICPixelFormat8bppGray;
308             break;
309         default:
310             FIXME("unhandled greyscale bit count %u\n", bps);
311             return E_FAIL;
312         }
313         break;
314     case 2: /* RGB */
315         decode_info->bpp = bps * samples;
316
317         if (samples == 4)
318         {
319             ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
320             if (!ret)
321             {
322                 WARN("Cannot get extra sample type for RGB data, ret=%i count=%i\n", ret, extra_sample_count);
323                 return E_FAIL;
324             }
325         }
326         else if (samples != 3)
327         {
328             FIXME("unhandled RGB sample count %u\n", samples);
329             return E_FAIL;
330         }
331
332         switch(bps)
333         {
334         case 8:
335             decode_info->reverse_bgr = 1;
336             if (samples == 3)
337                 decode_info->format = &GUID_WICPixelFormat24bppBGR;
338             else
339                 switch(extra_samples[0])
340                 {
341                 case 0: /* Unspecified data */
342                     decode_info->format = &GUID_WICPixelFormat32bppBGR;
343                     break;
344                 case 1: /* Associated (pre-multiplied) alpha data */
345                     decode_info->format = &GUID_WICPixelFormat32bppPBGRA;
346                     break;
347                 case 2: /* Unassociated alpha data */
348                     decode_info->format = &GUID_WICPixelFormat32bppBGRA;
349                     break;
350                 default:
351                     FIXME("unhandled extra sample type %i\n", extra_samples[0]);
352                     return E_FAIL;
353                 }
354             break;
355         case 16:
356             if (samples == 3)
357                 decode_info->format = &GUID_WICPixelFormat48bppRGB;
358             else
359                 switch(extra_samples[0])
360                 {
361                 case 0: /* Unspecified data */
362                     /* decode_info->format = &GUID_WICPixelFormat64bppRGB; */
363                     FIXME("64-bit RGB is unsupported\n");
364                     return E_FAIL;
365                 case 1: /* Associated (pre-multiplied) alpha data */
366                     decode_info->format = &GUID_WICPixelFormat64bppPRGBA;
367                     break;
368                 case 2: /* Unassociated alpha data */
369                     decode_info->format = &GUID_WICPixelFormat64bppRGBA;
370                     break;
371                 default:
372                     FIXME("unhandled extra sample type %i\n", extra_samples[0]);
373                     return E_FAIL;
374                 }
375             break;
376         default:
377             FIXME("unhandled RGB bit count %u\n", bps);
378             return E_FAIL;
379         }
380         break;
381     case 3: /* RGB Palette */
382         if (samples != 1)
383         {
384             FIXME("unhandled indexed sample count %u\n", samples);
385             return E_FAIL;
386         }
387
388         decode_info->indexed = 1;
389         decode_info->bpp = bps;
390         switch (bps)
391         {
392         case 4:
393             decode_info->format = &GUID_WICPixelFormat4bppIndexed;
394             break;
395         case 8:
396             decode_info->format = &GUID_WICPixelFormat8bppIndexed;
397             break;
398         default:
399             FIXME("unhandled indexed bit count %u\n", bps);
400             return E_FAIL;
401         }
402         break;
403     case 4: /* Transparency mask */
404     case 5: /* CMYK */
405     case 6: /* YCbCr */
406     case 8: /* CIELab */
407     default:
408         FIXME("unhandled PhotometricInterpretation %u\n", photometric);
409         return E_FAIL;
410     }
411
412     ret = pTIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->width);
413     if (!ret)
414     {
415         WARN("missing image width\n");
416         return E_FAIL;
417     }
418
419     ret = pTIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->height);
420     if (!ret)
421     {
422         WARN("missing image length\n");
423         return E_FAIL;
424     }
425
426     if ((ret = pTIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width)))
427     {
428         decode_info->tiled = 1;
429
430         if (!ret)
431         {
432             WARN("missing tile width\n");
433             return E_FAIL;
434         }
435
436         ret = pTIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height);
437         if (!ret)
438         {
439             WARN("missing tile height\n");
440             return E_FAIL;
441         }
442
443         decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8);
444         decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
445         decode_info->tiles_across = (decode_info->width + decode_info->tile_width - 1) / decode_info->tile_width;
446     }
447     else if ((ret = pTIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height)))
448     {
449         if (decode_info->tile_height > decode_info->height)
450             decode_info->tile_height = decode_info->height;
451         decode_info->tile_width = decode_info->width;
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     }
455     else
456     {
457         FIXME("missing RowsPerStrip value\n");
458         return E_FAIL;
459     }
460
461     return S_OK;
462 }
463
464 static HRESULT WINAPI TiffDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
465     void **ppv)
466 {
467     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
468     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
469
470     if (!ppv) return E_INVALIDARG;
471
472     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
473     {
474         *ppv = This;
475     }
476     else
477     {
478         *ppv = NULL;
479         return E_NOINTERFACE;
480     }
481
482     IUnknown_AddRef((IUnknown*)*ppv);
483     return S_OK;
484 }
485
486 static ULONG WINAPI TiffDecoder_AddRef(IWICBitmapDecoder *iface)
487 {
488     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
489     ULONG ref = InterlockedIncrement(&This->ref);
490
491     TRACE("(%p) refcount=%u\n", iface, ref);
492
493     return ref;
494 }
495
496 static ULONG WINAPI TiffDecoder_Release(IWICBitmapDecoder *iface)
497 {
498     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
499     ULONG ref = InterlockedDecrement(&This->ref);
500
501     TRACE("(%p) refcount=%u\n", iface, ref);
502
503     if (ref == 0)
504     {
505         if (This->tiff) pTIFFClose(This->tiff);
506         if (This->stream) IStream_Release(This->stream);
507         This->lock.DebugInfo->Spare[0] = 0;
508         DeleteCriticalSection(&This->lock);
509         HeapFree(GetProcessHeap(), 0, This);
510     }
511
512     return ref;
513 }
514
515 static HRESULT WINAPI TiffDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
516     DWORD *pdwCapability)
517 {
518     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
519     return E_NOTIMPL;
520 }
521
522 static HRESULT WINAPI TiffDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
523     WICDecodeOptions cacheOptions)
524 {
525     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
526     TIFF *tiff;
527     HRESULT hr=S_OK;
528
529     TRACE("(%p,%p,%x): stub\n", iface, pIStream, cacheOptions);
530
531     EnterCriticalSection(&This->lock);
532
533     if (This->initialized)
534     {
535         hr = WINCODEC_ERR_WRONGSTATE;
536         goto exit;
537     }
538
539     tiff = tiff_open_stream(pIStream, "r");
540
541     if (!tiff)
542     {
543         hr = E_FAIL;
544         goto exit;
545     }
546
547     This->tiff = tiff;
548     This->stream = pIStream;
549     IStream_AddRef(pIStream);
550     This->initialized = TRUE;
551
552 exit:
553     LeaveCriticalSection(&This->lock);
554     return hr;
555 }
556
557 static HRESULT WINAPI TiffDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
558     GUID *pguidContainerFormat)
559 {
560     memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID));
561     return S_OK;
562 }
563
564 static HRESULT WINAPI TiffDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
565     IWICBitmapDecoderInfo **ppIDecoderInfo)
566 {
567     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
568     return E_NOTIMPL;
569 }
570
571 static HRESULT WINAPI TiffDecoder_CopyPalette(IWICBitmapDecoder *iface,
572     IWICPalette *pIPalette)
573 {
574     FIXME("(%p,%p): stub\n", iface, pIPalette);
575     return E_NOTIMPL;
576 }
577
578 static HRESULT WINAPI TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
579     IWICMetadataQueryReader **ppIMetadataQueryReader)
580 {
581     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
582     return E_NOTIMPL;
583 }
584
585 static HRESULT WINAPI TiffDecoder_GetPreview(IWICBitmapDecoder *iface,
586     IWICBitmapSource **ppIBitmapSource)
587 {
588     FIXME("(%p,%p): stub\n", iface, ppIBitmapSource);
589     return E_NOTIMPL;
590 }
591
592 static HRESULT WINAPI TiffDecoder_GetColorContexts(IWICBitmapDecoder *iface,
593     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
594 {
595     FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
596     return E_NOTIMPL;
597 }
598
599 static HRESULT WINAPI TiffDecoder_GetThumbnail(IWICBitmapDecoder *iface,
600     IWICBitmapSource **ppIThumbnail)
601 {
602     TRACE("(%p,%p)\n", iface, ppIThumbnail);
603     return WINCODEC_ERR_CODECNOTHUMBNAIL;
604 }
605
606 static HRESULT WINAPI TiffDecoder_GetFrameCount(IWICBitmapDecoder *iface,
607     UINT *pCount)
608 {
609     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
610
611     if (!This->tiff)
612     {
613         WARN("(%p) <-- WINCODEC_ERR_WRONGSTATE\n", iface);
614         return WINCODEC_ERR_WRONGSTATE;
615     }
616
617     EnterCriticalSection(&This->lock);
618     while (pTIFFReadDirectory(This->tiff)) { }
619     *pCount = pTIFFCurrentDirectory(This->tiff)+1;
620     LeaveCriticalSection(&This->lock);
621
622     TRACE("(%p) <-- %i\n", iface, *pCount);
623
624     return S_OK;
625 }
626
627 static HRESULT WINAPI TiffDecoder_GetFrame(IWICBitmapDecoder *iface,
628     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
629 {
630     TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
631     TiffFrameDecode *result;
632     int res;
633     tiff_decode_info decode_info;
634     HRESULT hr;
635
636     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
637
638     if (!This->tiff)
639         return WINCODEC_ERR_WRONGSTATE;
640
641     EnterCriticalSection(&This->lock);
642     res = pTIFFSetDirectory(This->tiff, index);
643     if (!res) hr = E_INVALIDARG;
644     else hr = tiff_get_decode_info(This->tiff, &decode_info);
645     LeaveCriticalSection(&This->lock);
646
647     if (SUCCEEDED(hr))
648     {
649         result = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode));
650
651         if (result)
652         {
653             result->IWICBitmapFrameDecode_iface.lpVtbl = &TiffFrameDecode_Vtbl;
654             result->ref = 1;
655             result->parent = This;
656             result->index = index;
657             result->decode_info = decode_info;
658             result->cached_tile_x = -1;
659             result->cached_tile = HeapAlloc(GetProcessHeap(), 0, decode_info.tile_size);
660
661             if (result->cached_tile)
662                 *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
663             else
664             {
665                 hr = E_OUTOFMEMORY;
666                 HeapFree(GetProcessHeap(), 0, result);
667             }
668         }
669         else hr = E_OUTOFMEMORY;
670     }
671
672     if (FAILED(hr)) *ppIBitmapFrame = NULL;
673
674     return hr;
675 }
676
677 static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl = {
678     TiffDecoder_QueryInterface,
679     TiffDecoder_AddRef,
680     TiffDecoder_Release,
681     TiffDecoder_QueryCapability,
682     TiffDecoder_Initialize,
683     TiffDecoder_GetContainerFormat,
684     TiffDecoder_GetDecoderInfo,
685     TiffDecoder_CopyPalette,
686     TiffDecoder_GetMetadataQueryReader,
687     TiffDecoder_GetPreview,
688     TiffDecoder_GetColorContexts,
689     TiffDecoder_GetThumbnail,
690     TiffDecoder_GetFrameCount,
691     TiffDecoder_GetFrame
692 };
693
694 static HRESULT WINAPI TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
695     void **ppv)
696 {
697     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
698     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
699
700     if (!ppv) return E_INVALIDARG;
701
702     if (IsEqualIID(&IID_IUnknown, iid) ||
703         IsEqualIID(&IID_IWICBitmapSource, iid) ||
704         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
705     {
706         *ppv = This;
707     }
708     else
709     {
710         *ppv = NULL;
711         return E_NOINTERFACE;
712     }
713
714     IUnknown_AddRef((IUnknown*)*ppv);
715     return S_OK;
716 }
717
718 static ULONG WINAPI TiffFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
719 {
720     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
721     ULONG ref = InterlockedIncrement(&This->ref);
722
723     TRACE("(%p) refcount=%u\n", iface, ref);
724
725     return ref;
726 }
727
728 static ULONG WINAPI TiffFrameDecode_Release(IWICBitmapFrameDecode *iface)
729 {
730     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
731     ULONG ref = InterlockedDecrement(&This->ref);
732
733     TRACE("(%p) refcount=%u\n", iface, ref);
734
735     if (ref == 0)
736     {
737         HeapFree(GetProcessHeap(), 0, This->cached_tile);
738         HeapFree(GetProcessHeap(), 0, This);
739     }
740
741     return ref;
742 }
743
744 static HRESULT WINAPI TiffFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
745     UINT *puiWidth, UINT *puiHeight)
746 {
747     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
748
749     *puiWidth = This->decode_info.width;
750     *puiHeight = This->decode_info.height;
751
752     TRACE("(%p) <-- %ux%u\n", iface, *puiWidth, *puiHeight);
753
754     return S_OK;
755 }
756
757 static HRESULT WINAPI TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
758     WICPixelFormatGUID *pPixelFormat)
759 {
760     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
761
762     memcpy(pPixelFormat, This->decode_info.format, sizeof(GUID));
763
764     TRACE("(%p) <-- %s\n", This, debugstr_guid(This->decode_info.format));
765
766     return S_OK;
767 }
768
769 static HRESULT WINAPI TiffFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
770     double *pDpiX, double *pDpiY)
771 {
772     FIXME("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
773     return E_NOTIMPL;
774 }
775
776 static HRESULT WINAPI TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
777     IWICPalette *pIPalette)
778 {
779     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
780     uint16 *red, *green, *blue;
781     WICColor colors[256];
782     int color_count, ret, i;
783
784     TRACE("(%p,%p)\n", iface, pIPalette);
785
786     color_count = 1<<This->decode_info.bps;
787
788     EnterCriticalSection(&This->parent->lock);
789     ret = pTIFFGetField(This->parent->tiff, TIFFTAG_COLORMAP, &red, &green, &blue);
790     LeaveCriticalSection(&This->parent->lock);
791
792     if (!ret)
793     {
794         WARN("Couldn't read color map\n");
795         return E_FAIL;
796     }
797
798     for (i=0; i<color_count; i++)
799     {
800         colors[i] = 0xff000000 |
801             ((red[i]<<8) & 0xff0000) |
802             (green[i] & 0xff00) |
803             ((blue[i]>>8) & 0xff);
804     }
805
806     return IWICPalette_InitializeCustom(pIPalette, colors, color_count);
807 }
808
809 static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT tile_y)
810 {
811     HRESULT hr=S_OK;
812     tsize_t ret;
813     int swap_bytes;
814
815     swap_bytes = pTIFFIsByteSwapped(This->parent->tiff);
816
817     ret = pTIFFSetDirectory(This->parent->tiff, This->index);
818
819     if (ret == -1)
820         hr = E_FAIL;
821
822     if (hr == S_OK)
823     {
824         if (This->decode_info.tiled)
825         {
826             ret = pTIFFReadEncodedTile(This->parent->tiff, tile_x + tile_y * This->decode_info.tiles_across, This->cached_tile, This->decode_info.tile_size);
827         }
828         else
829         {
830             ret = pTIFFReadEncodedStrip(This->parent->tiff, tile_y, This->cached_tile, This->decode_info.tile_size);
831         }
832
833         if (ret == -1)
834             hr = E_FAIL;
835     }
836
837     if (hr == S_OK && This->decode_info.reverse_bgr)
838     {
839         if (This->decode_info.bps == 8)
840         {
841             UINT sample_count = This->decode_info.samples;
842
843             reverse_bgr8(sample_count, This->cached_tile, This->decode_info.tile_width,
844                 This->decode_info.tile_height, This->decode_info.tile_width * sample_count);
845         }
846     }
847
848     if (hr == S_OK && swap_bytes && This->decode_info.bps > 8)
849     {
850         UINT row, i, samples_per_row;
851         BYTE *sample, temp;
852
853         samples_per_row = This->decode_info.tile_width * This->decode_info.samples;
854
855         switch(This->decode_info.bps)
856         {
857         case 16:
858             for (row=0; row<This->decode_info.tile_height; row++)
859             {
860                 sample = This->cached_tile + row * This->decode_info.tile_stride;
861                 for (i=0; i<samples_per_row; i++)
862                 {
863                     temp = sample[1];
864                     sample[1] = sample[0];
865                     sample[0] = temp;
866                     sample += 2;
867                 }
868             }
869             break;
870         default:
871             ERR("unhandled bps for byte swap %u\n", This->decode_info.bps);
872             return E_FAIL;
873         }
874     }
875
876     if (hr == S_OK && This->decode_info.invert_grayscale)
877     {
878         BYTE *byte, *end;
879
880         if (This->decode_info.samples != 1)
881         {
882             ERR("cannot invert grayscale image with %u samples\n", This->decode_info.samples);
883             return E_FAIL;
884         }
885
886         end = This->cached_tile+This->decode_info.tile_size;
887
888         for (byte = This->cached_tile; byte != end; byte++)
889             *byte = ~(*byte);
890     }
891
892     if (hr == S_OK)
893     {
894         This->cached_tile_x = tile_x;
895         This->cached_tile_y = tile_y;
896     }
897
898     return hr;
899 }
900
901 static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
902     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
903 {
904     TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
905     UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y;
906     UINT tile_x, tile_y;
907     WICRect rc;
908     HRESULT hr=S_OK;
909     BYTE *dst_tilepos;
910     UINT bytesperrow;
911     WICRect rect;
912
913     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
914
915     if (!prc)
916     {
917         rect.X = 0;
918         rect.Y = 0;
919         rect.Width = This->decode_info.width;
920         rect.Height = This->decode_info.height;
921         prc = &rect;
922     }
923     else
924     {
925         if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->decode_info.width ||
926             prc->Y+prc->Height > This->decode_info.height)
927             return E_INVALIDARG;
928     }
929
930     bytesperrow = ((This->decode_info.bpp * prc->Width)+7)/8;
931
932     if (cbStride < bytesperrow)
933         return E_INVALIDARG;
934
935     if ((cbStride * prc->Height) > cbBufferSize)
936         return E_INVALIDARG;
937
938     min_tile_x = prc->X / This->decode_info.tile_width;
939     min_tile_y = prc->Y / This->decode_info.tile_height;
940     max_tile_x = (prc->X+prc->Width-1) / This->decode_info.tile_width;
941     max_tile_y = (prc->Y+prc->Height-1) / This->decode_info.tile_height;
942
943     EnterCriticalSection(&This->parent->lock);
944
945     for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++)
946     {
947         for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++)
948         {
949             if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y)
950             {
951                 hr = TiffFrameDecode_ReadTile(This, tile_x, tile_y);
952             }
953
954             if (SUCCEEDED(hr))
955             {
956                 if (prc->X < tile_x * This->decode_info.tile_width)
957                     rc.X = 0;
958                 else
959                     rc.X = prc->X - tile_x * This->decode_info.tile_width;
960
961                 if (prc->Y < tile_y * This->decode_info.tile_height)
962                     rc.Y = 0;
963                 else
964                     rc.Y = prc->Y - tile_y * This->decode_info.tile_height;
965
966                 if (prc->X+prc->Width > (tile_x+1) * This->decode_info.tile_width)
967                     rc.Width = This->decode_info.tile_width - rc.X;
968                 else if (prc->X < tile_x * This->decode_info.tile_width)
969                     rc.Width = prc->Width + prc->X - tile_x * This->decode_info.tile_width;
970                 else
971                     rc.Width = prc->Width;
972
973                 if (prc->Y+prc->Height > (tile_y+1) * This->decode_info.tile_height)
974                     rc.Height = This->decode_info.tile_height - rc.Y;
975                 else if (prc->Y < tile_y * This->decode_info.tile_height)
976                     rc.Height = prc->Height + prc->Y - tile_y * This->decode_info.tile_height;
977                 else
978                     rc.Height = prc->Height;
979
980                 dst_tilepos = pbBuffer + (cbStride * ((rc.Y + tile_y * This->decode_info.tile_height) - prc->Y)) +
981                     ((This->decode_info.bpp * ((rc.X + tile_x * This->decode_info.tile_width) - prc->X) + 7) / 8);
982
983                 hr = copy_pixels(This->decode_info.bpp, This->cached_tile,
984                     This->decode_info.tile_width, This->decode_info.tile_height, This->decode_info.tile_stride,
985                     &rc, cbStride, cbBufferSize, dst_tilepos);
986             }
987
988             if (FAILED(hr))
989             {
990                 LeaveCriticalSection(&This->parent->lock);
991                 TRACE("<-- 0x%x\n", hr);
992                 return hr;
993             }
994         }
995     }
996
997     LeaveCriticalSection(&This->parent->lock);
998
999     return S_OK;
1000 }
1001
1002 static HRESULT WINAPI TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
1003     IWICMetadataQueryReader **ppIMetadataQueryReader)
1004 {
1005     FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader);
1006     return E_NOTIMPL;
1007 }
1008
1009 static HRESULT WINAPI TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
1010     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1011 {
1012     FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount);
1013     return E_NOTIMPL;
1014 }
1015
1016 static HRESULT WINAPI TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
1017     IWICBitmapSource **ppIThumbnail)
1018 {
1019     FIXME("(%p,%p): stub\n", iface, ppIThumbnail);
1020     return E_NOTIMPL;
1021 }
1022
1023 static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl = {
1024     TiffFrameDecode_QueryInterface,
1025     TiffFrameDecode_AddRef,
1026     TiffFrameDecode_Release,
1027     TiffFrameDecode_GetSize,
1028     TiffFrameDecode_GetPixelFormat,
1029     TiffFrameDecode_GetResolution,
1030     TiffFrameDecode_CopyPalette,
1031     TiffFrameDecode_CopyPixels,
1032     TiffFrameDecode_GetMetadataQueryReader,
1033     TiffFrameDecode_GetColorContexts,
1034     TiffFrameDecode_GetThumbnail
1035 };
1036
1037 HRESULT TiffDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1038 {
1039     HRESULT ret;
1040     TiffDecoder *This;
1041
1042     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1043
1044     *ppv = NULL;
1045
1046     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1047
1048     if (!load_libtiff())
1049     {
1050         ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF);
1051         return E_FAIL;
1052     }
1053
1054     This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder));
1055     if (!This) return E_OUTOFMEMORY;
1056
1057     This->IWICBitmapDecoder_iface.lpVtbl = &TiffDecoder_Vtbl;
1058     This->ref = 1;
1059     This->stream = NULL;
1060     InitializeCriticalSection(&This->lock);
1061     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffDecoder.lock");
1062     This->tiff = NULL;
1063     This->initialized = FALSE;
1064
1065     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
1066     IUnknown_Release((IUnknown*)This);
1067
1068     return ret;
1069 }
1070
1071 #else /* !SONAME_LIBTIFF */
1072
1073 HRESULT TiffDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1074 {
1075     ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
1076     return E_FAIL;
1077 }
1078
1079 #endif