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