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