mfplat: Remove duplicated GUID entry from attribute tracing.
[wine/zf.git] / dlls / windowscodecs / libtiff.c
blob25d8c1c6081b5850985266a424900966ff1b7a98
1 /*
2 * Copyright 2010 Vincent Povirk for CodeWeavers
3 * Copyright 2016 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #if 0
21 #pragma makedep unix
22 #endif
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_TIFFIO_H
32 #include <tiffio.h>
33 #endif
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "winternl.h"
39 #include "winbase.h"
40 #include "objbase.h"
42 #include "wincodecs_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
48 #ifdef SONAME_LIBTIFF
50 /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which
51 * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they
52 * are supposed to be always 64-bit.
53 * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x.
55 #ifdef TIFF_UINT64_T
56 # undef toff_t
57 # define toff_t UINT64
58 #endif
60 static CRITICAL_SECTION init_tiff_cs;
61 static CRITICAL_SECTION_DEBUG init_tiff_cs_debug =
63 0, 0, &init_tiff_cs,
64 { &init_tiff_cs_debug.ProcessLocksList,
65 &init_tiff_cs_debug.ProcessLocksList },
66 0, 0, { (DWORD_PTR)(__FILE__ ": init_tiff_cs") }
68 static CRITICAL_SECTION init_tiff_cs = { &init_tiff_cs_debug, -1, 0, 0, 0, 0 };
70 static void *libtiff_handle;
71 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
72 MAKE_FUNCPTR(TIFFClientOpen);
73 MAKE_FUNCPTR(TIFFClose);
74 MAKE_FUNCPTR(TIFFCurrentDirOffset);
75 MAKE_FUNCPTR(TIFFGetField);
76 MAKE_FUNCPTR(TIFFIsByteSwapped);
77 MAKE_FUNCPTR(TIFFNumberOfDirectories);
78 MAKE_FUNCPTR(TIFFReadDirectory);
79 MAKE_FUNCPTR(TIFFReadEncodedStrip);
80 MAKE_FUNCPTR(TIFFReadEncodedTile);
81 MAKE_FUNCPTR(TIFFSetDirectory);
82 MAKE_FUNCPTR(TIFFSetField);
83 MAKE_FUNCPTR(TIFFWriteDirectory);
84 MAKE_FUNCPTR(TIFFWriteScanline);
85 #undef MAKE_FUNCPTR
87 static void *load_libtiff(void)
89 void *result;
91 RtlEnterCriticalSection(&init_tiff_cs);
93 if (!libtiff_handle &&
94 (libtiff_handle = dlopen(SONAME_LIBTIFF, RTLD_NOW)) != NULL)
96 void * (*pTIFFSetWarningHandler)(void *);
97 void * (*pTIFFSetWarningHandlerExt)(void *);
99 #define LOAD_FUNCPTR(f) \
100 if((p##f = dlsym(libtiff_handle, #f)) == NULL) { \
101 ERR("failed to load symbol %s\n", #f); \
102 libtiff_handle = NULL; \
103 RtlLeaveCriticalSection(&init_tiff_cs); \
104 return NULL; \
106 LOAD_FUNCPTR(TIFFClientOpen);
107 LOAD_FUNCPTR(TIFFClose);
108 LOAD_FUNCPTR(TIFFCurrentDirOffset);
109 LOAD_FUNCPTR(TIFFGetField);
110 LOAD_FUNCPTR(TIFFIsByteSwapped);
111 LOAD_FUNCPTR(TIFFNumberOfDirectories);
112 LOAD_FUNCPTR(TIFFReadDirectory);
113 LOAD_FUNCPTR(TIFFReadEncodedStrip);
114 LOAD_FUNCPTR(TIFFReadEncodedTile);
115 LOAD_FUNCPTR(TIFFSetDirectory);
116 LOAD_FUNCPTR(TIFFSetField);
117 LOAD_FUNCPTR(TIFFWriteDirectory);
118 LOAD_FUNCPTR(TIFFWriteScanline);
119 #undef LOAD_FUNCPTR
121 if ((pTIFFSetWarningHandler = dlsym(libtiff_handle, "TIFFSetWarningHandler")))
122 pTIFFSetWarningHandler(NULL);
123 if ((pTIFFSetWarningHandlerExt = dlsym(libtiff_handle, "TIFFSetWarningHandlerExt")))
124 pTIFFSetWarningHandlerExt(NULL);
127 result = libtiff_handle;
129 RtlLeaveCriticalSection(&init_tiff_cs);
130 return result;
133 static tsize_t tiff_stream_read(thandle_t client_data, tdata_t data, tsize_t size)
135 IStream *stream = (IStream*)client_data;
136 ULONG bytes_read;
137 HRESULT hr;
139 hr = stream_read(stream, data, size, &bytes_read);
140 if (FAILED(hr)) bytes_read = 0;
141 return bytes_read;
144 static tsize_t tiff_stream_write(thandle_t client_data, tdata_t data, tsize_t size)
146 IStream *stream = (IStream*)client_data;
147 ULONG bytes_written;
148 HRESULT hr;
150 hr = stream_write(stream, data, size, &bytes_written);
151 if (FAILED(hr)) bytes_written = 0;
152 return bytes_written;
155 static toff_t tiff_stream_seek(thandle_t client_data, toff_t offset, int whence)
157 IStream *stream = (IStream*)client_data;
158 DWORD origin;
159 ULONGLONG new_position;
160 HRESULT hr;
162 switch (whence)
164 case SEEK_SET:
165 origin = STREAM_SEEK_SET;
166 break;
167 case SEEK_CUR:
168 origin = STREAM_SEEK_CUR;
169 break;
170 case SEEK_END:
171 origin = STREAM_SEEK_END;
172 break;
173 default:
174 ERR("unknown whence value %i\n", whence);
175 return -1;
178 hr = stream_seek(stream, offset, origin, &new_position);
179 if (SUCCEEDED(hr)) return new_position;
180 else return -1;
183 static int tiff_stream_close(thandle_t client_data)
185 /* Caller is responsible for releasing the stream object. */
186 return 0;
189 static toff_t tiff_stream_size(thandle_t client_data)
191 IStream *stream = (IStream*)client_data;
192 ULONGLONG size;
193 HRESULT hr;
195 hr = stream_getsize(stream, &size);
197 if (SUCCEEDED(hr)) return size;
198 else return -1;
201 static int tiff_stream_map(thandle_t client_data, tdata_t *addr, toff_t *size)
203 /* Cannot mmap streams */
204 return 0;
207 static void tiff_stream_unmap(thandle_t client_data, tdata_t addr, toff_t size)
209 /* No need to ever do this, since we can't map things. */
212 static TIFF* tiff_open_stream(IStream *stream, const char *mode)
214 stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
216 return pTIFFClientOpen("<IStream object>", mode, stream, tiff_stream_read,
217 tiff_stream_write, (void *)tiff_stream_seek, tiff_stream_close,
218 (void *)tiff_stream_size, (void *)tiff_stream_map, (void *)tiff_stream_unmap);
221 typedef struct {
222 struct decoder_frame frame;
223 int bps;
224 int samples;
225 int source_bpp;
226 int planar;
227 int indexed;
228 int reverse_bgr;
229 int invert_grayscale;
230 UINT tile_width, tile_height;
231 UINT tile_stride;
232 UINT tile_size;
233 int tiled;
234 UINT tiles_across;
235 } tiff_decode_info;
237 struct tiff_decoder
239 struct decoder decoder;
240 IStream *stream;
241 TIFF *tiff;
242 DWORD frame_count;
243 DWORD cached_frame;
244 tiff_decode_info cached_decode_info;
245 INT cached_tile_x, cached_tile_y;
246 BYTE *cached_tile;
249 static inline struct tiff_decoder *impl_from_decoder(struct decoder* iface)
251 return CONTAINING_RECORD(iface, struct tiff_decoder, decoder);
254 static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
256 uint16 photometric, bps, samples, planar;
257 uint16 extra_sample_count, extra_sample, *extra_samples;
258 uint16 *red, *green, *blue;
259 UINT resolution_unit;
260 float xres=0.0, yres=0.0;
261 int ret, i;
262 const BYTE *profile;
263 UINT len;
265 decode_info->indexed = 0;
266 decode_info->reverse_bgr = 0;
267 decode_info->invert_grayscale = 0;
268 decode_info->tiled = 0;
269 decode_info->source_bpp = 0;
271 ret = pTIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
272 if (!ret)
274 WARN("missing PhotometricInterpretation tag\n");
275 return E_FAIL;
278 ret = pTIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps);
279 if (!ret) bps = 1;
280 decode_info->bps = bps;
282 ret = pTIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
283 if (!ret) samples = 1;
284 decode_info->samples = samples;
286 if (samples == 1)
287 planar = 1;
288 else
290 ret = pTIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar);
291 if (!ret) planar = 1;
292 if (planar != 1)
294 FIXME("unhandled planar configuration %u\n", planar);
295 return E_FAIL;
298 decode_info->planar = planar;
300 TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar, photometric, samples, bps);
302 switch(photometric)
304 case 0: /* WhiteIsZero */
305 decode_info->invert_grayscale = 1;
306 /* fall through */
307 case 1: /* BlackIsZero */
308 if (samples == 2)
310 ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
311 if (!ret)
313 extra_sample_count = 1;
314 extra_sample = 0;
315 extra_samples = &extra_sample;
318 else if (samples != 1)
320 FIXME("unhandled %dbpp sample count %u\n", bps, samples);
321 return E_FAIL;
324 decode_info->frame.bpp = bps * samples;
325 decode_info->source_bpp = decode_info->frame.bpp;
326 switch (bps)
328 case 1:
329 if (samples != 1)
331 FIXME("unhandled 1bpp sample count %u\n", samples);
332 return E_FAIL;
334 decode_info->frame.pixel_format = GUID_WICPixelFormatBlackWhite;
335 break;
336 case 4:
337 if (samples != 1)
339 FIXME("unhandled 4bpp grayscale sample count %u\n", samples);
340 return E_FAIL;
342 decode_info->frame.pixel_format = GUID_WICPixelFormat4bppGray;
343 break;
344 case 8:
345 if (samples == 1)
346 decode_info->frame.pixel_format = GUID_WICPixelFormat8bppGray;
347 else
349 decode_info->frame.bpp = 32;
351 switch(extra_samples[0])
353 case 1: /* Associated (pre-multiplied) alpha data */
354 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppPBGRA;
355 break;
356 case 0: /* Unspecified data */
357 case 2: /* Unassociated alpha data */
358 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
359 break;
360 default:
361 FIXME("unhandled extra sample type %u\n", extra_samples[0]);
362 return E_FAIL;
365 break;
366 case 16:
367 if (samples != 1)
369 FIXME("unhandled 16bpp grayscale sample count %u\n", samples);
370 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
372 decode_info->frame.pixel_format = GUID_WICPixelFormat16bppGray;
373 break;
374 case 32:
375 if (samples != 1)
377 FIXME("unhandled 32bpp grayscale sample count %u\n", samples);
378 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
380 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppGrayFloat;
381 break;
382 default:
383 WARN("unhandled greyscale bit count %u\n", bps);
384 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
386 break;
387 case 2: /* RGB */
388 if (samples == 4)
390 ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
391 if (!ret)
393 extra_sample_count = 1;
394 extra_sample = 0;
395 extra_samples = &extra_sample;
398 else if (samples != 3)
400 FIXME("unhandled RGB sample count %u\n", samples);
401 return E_FAIL;
404 decode_info->frame.bpp = max(bps, 8) * samples;
405 decode_info->source_bpp = bps * samples;
406 switch(bps)
408 case 1:
409 case 4:
410 case 8:
411 decode_info->reverse_bgr = 1;
412 if (samples == 3)
413 decode_info->frame.pixel_format = GUID_WICPixelFormat24bppBGR;
414 else
415 switch(extra_samples[0])
417 case 1: /* Associated (pre-multiplied) alpha data */
418 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppPBGRA;
419 break;
420 case 0: /* Unspecified data */
421 case 2: /* Unassociated alpha data */
422 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
423 break;
424 default:
425 FIXME("unhandled extra sample type %i\n", extra_samples[0]);
426 return E_FAIL;
428 break;
429 case 16:
430 if (samples == 3)
431 decode_info->frame.pixel_format = GUID_WICPixelFormat48bppRGB;
432 else
433 switch(extra_samples[0])
435 case 1: /* Associated (pre-multiplied) alpha data */
436 decode_info->frame.pixel_format = GUID_WICPixelFormat64bppPRGBA;
437 break;
438 case 0: /* Unspecified data */
439 case 2: /* Unassociated alpha data */
440 decode_info->frame.pixel_format = GUID_WICPixelFormat64bppRGBA;
441 break;
442 default:
443 FIXME("unhandled extra sample type %i\n", extra_samples[0]);
444 return E_FAIL;
446 break;
447 case 32:
448 if (samples == 3)
449 decode_info->frame.pixel_format = GUID_WICPixelFormat96bppRGBFloat;
450 else
451 switch(extra_samples[0])
453 case 1: /* Associated (pre-multiplied) alpha data */
454 decode_info->frame.pixel_format = GUID_WICPixelFormat128bppPRGBAFloat;
455 break;
456 case 0: /* Unspecified data */
457 case 2: /* Unassociated alpha data */
458 decode_info->frame.pixel_format = GUID_WICPixelFormat128bppRGBAFloat;
459 break;
460 default:
461 FIXME("unhandled extra sample type %i\n", extra_samples[0]);
462 return E_FAIL;
464 break;
465 default:
466 WARN("unhandled RGB bit count %u\n", bps);
467 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
469 break;
470 case 3: /* RGB Palette */
471 if (samples != 1)
473 FIXME("unhandled indexed sample count %u\n", samples);
474 return E_FAIL;
477 decode_info->indexed = 1;
478 decode_info->frame.bpp = bps;
479 switch (bps)
481 case 1:
482 decode_info->frame.pixel_format = GUID_WICPixelFormat1bppIndexed;
483 break;
484 case 2:
485 decode_info->frame.pixel_format = GUID_WICPixelFormat2bppIndexed;
486 break;
487 case 4:
488 decode_info->frame.pixel_format = GUID_WICPixelFormat4bppIndexed;
489 break;
490 case 8:
491 decode_info->frame.pixel_format = GUID_WICPixelFormat8bppIndexed;
492 break;
493 default:
494 FIXME("unhandled indexed bit count %u\n", bps);
495 return E_NOTIMPL;
497 break;
499 case 5: /* Separated */
500 if (samples != 4)
502 FIXME("unhandled Separated sample count %u\n", samples);
503 return E_FAIL;
506 decode_info->frame.bpp = bps * samples;
507 switch(bps)
509 case 8:
510 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppCMYK;
511 break;
512 case 16:
513 decode_info->frame.pixel_format = GUID_WICPixelFormat64bppCMYK;
514 break;
516 default:
517 WARN("unhandled Separated bit count %u\n", bps);
518 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
520 break;
522 case 4: /* Transparency mask */
523 case 6: /* YCbCr */
524 case 8: /* CIELab */
525 default:
526 FIXME("unhandled PhotometricInterpretation %u\n", photometric);
527 return E_FAIL;
530 ret = pTIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->frame.width);
531 if (!ret)
533 WARN("missing image width\n");
534 return E_FAIL;
537 ret = pTIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->frame.height);
538 if (!ret)
540 WARN("missing image length\n");
541 return E_FAIL;
544 if ((ret = pTIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width)))
546 decode_info->tiled = 1;
548 ret = pTIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height);
549 if (!ret)
551 WARN("missing tile height\n");
552 return E_FAIL;
555 decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
556 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
557 decode_info->tiles_across = (decode_info->frame.width + decode_info->tile_width - 1) / decode_info->tile_width;
559 else if ((ret = pTIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height)))
561 if (decode_info->tile_height > decode_info->frame.height)
562 decode_info->tile_height = decode_info->frame.height;
563 decode_info->tile_width = decode_info->frame.width;
564 decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
565 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
567 else
569 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
570 decode_info->tile_height = decode_info->frame.height;
571 decode_info->tile_width = decode_info->frame.width;
572 decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
573 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
576 resolution_unit = 0;
577 pTIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resolution_unit);
579 ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &xres);
580 if (!ret)
582 WARN("missing X resolution\n");
584 /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131)
585 * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */
586 if (!isfinite(xres))
588 xres = 0.0;
591 ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &yres);
592 if (!ret)
594 WARN("missing Y resolution\n");
596 if (!isfinite(yres))
598 yres = 0.0;
601 if (xres == 0.0 || yres == 0.0)
603 decode_info->frame.dpix = decode_info->frame.dpiy = 96.0;
605 else
607 switch (resolution_unit)
609 default:
610 FIXME("unknown resolution unit %i\n", resolution_unit);
611 /* fall through */
612 case 0: /* Not set */
613 case 1: /* Relative measurements */
614 case 2: /* Inch */
615 decode_info->frame.dpix = xres;
616 decode_info->frame.dpiy = yres;
617 break;
618 case 3: /* Centimeter */
619 decode_info->frame.dpix = xres * 2.54;
620 decode_info->frame.dpiy = yres * 2.54;
621 break;
625 if (decode_info->indexed &&
626 pTIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue))
628 decode_info->frame.num_colors = 1 << decode_info->bps;
629 for (i=0; i<decode_info->frame.num_colors; i++)
631 decode_info->frame.palette[i] = 0xff000000 |
632 ((red[i]<<8) & 0xff0000) |
633 (green[i] & 0xff00) |
634 ((blue[i]>>8) & 0xff);
637 else
639 decode_info->frame.num_colors = 0;
642 if (pTIFFGetField(tiff, TIFFTAG_ICCPROFILE, &len, &profile))
643 decode_info->frame.num_color_contexts = 1;
644 else
645 decode_info->frame.num_color_contexts = 0;
647 return S_OK;
650 static HRESULT CDECL tiff_decoder_initialize(struct decoder* iface, IStream *stream, struct decoder_stat *st)
652 struct tiff_decoder *This = impl_from_decoder(iface);
653 HRESULT hr;
655 This->tiff = tiff_open_stream(stream, "r");
656 if (!This->tiff)
657 return E_FAIL;
659 This->frame_count = pTIFFNumberOfDirectories(This->tiff);
660 This->cached_frame = 0;
661 hr = tiff_get_decode_info(This->tiff, &This->cached_decode_info);
662 if (FAILED(hr))
663 goto fail;
665 st->frame_count = This->frame_count;
666 st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
667 WICBitmapDecoderCapabilityCanDecodeSomeImages |
668 WICBitmapDecoderCapabilityCanEnumerateMetadata;
669 return S_OK;
671 fail:
672 pTIFFClose(This->tiff);
673 This->tiff = NULL;
674 return hr;
677 static HRESULT tiff_decoder_select_frame(struct tiff_decoder* This, DWORD frame)
679 HRESULT hr;
680 UINT prev_tile_size;
681 int res;
683 if (frame >= This->frame_count)
684 return E_INVALIDARG;
686 if (This->cached_frame == frame)
687 return S_OK;
689 prev_tile_size = This->cached_tile ? This->cached_decode_info.tile_size : 0;
691 res = pTIFFSetDirectory(This->tiff, frame);
692 if (!res)
693 return E_INVALIDARG;
695 hr = tiff_get_decode_info(This->tiff, &This->cached_decode_info);
697 This->cached_tile_x = -1;
699 if (SUCCEEDED(hr))
701 This->cached_frame = frame;
702 if (This->cached_decode_info.tile_size > prev_tile_size)
704 free(This->cached_tile);
705 This->cached_tile = NULL;
708 else
710 /* Set an invalid value to ensure we'll refresh cached_decode_info before using it. */
711 This->cached_frame = This->frame_count;
712 free(This->cached_tile);
713 This->cached_tile = NULL;
716 return hr;
719 static HRESULT CDECL tiff_decoder_get_frame_info(struct decoder* iface, UINT frame, struct decoder_frame *info)
721 struct tiff_decoder *This = impl_from_decoder(iface);
722 HRESULT hr;
724 hr = tiff_decoder_select_frame(This, frame);
725 if (SUCCEEDED(hr))
727 *info = This->cached_decode_info.frame;
730 return hr;
733 static HRESULT tiff_decoder_read_tile(struct tiff_decoder *This, UINT tile_x, UINT tile_y)
735 tsize_t ret;
736 int swap_bytes;
737 tiff_decode_info *info = &This->cached_decode_info;
739 swap_bytes = pTIFFIsByteSwapped(This->tiff);
741 if (info->tiled)
742 ret = pTIFFReadEncodedTile(This->tiff, tile_x + tile_y * info->tiles_across, This->cached_tile, info->tile_size);
743 else
744 ret = pTIFFReadEncodedStrip(This->tiff, tile_y, This->cached_tile, info->tile_size);
746 if (ret == -1)
747 return E_FAIL;
749 /* 3bps RGB */
750 if (info->source_bpp == 3 && info->samples == 3 && info->frame.bpp == 24)
752 BYTE *srcdata, *src, *dst;
753 DWORD x, y, count, width_bytes = (info->tile_width * 3 + 7) / 8;
755 count = width_bytes * info->tile_height;
757 srcdata = malloc(count);
758 if (!srcdata) return E_OUTOFMEMORY;
759 memcpy(srcdata, This->cached_tile, count);
761 for (y = 0; y < info->tile_height; y++)
763 src = srcdata + y * width_bytes;
764 dst = This->cached_tile + y * info->tile_width * 3;
766 for (x = 0; x < info->tile_width; x += 8)
768 dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
769 dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
770 dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
771 if (x + 1 < info->tile_width)
773 dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */
774 dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */
775 dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */
777 if (x + 2 < info->tile_width)
779 dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */
780 dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */
781 dst[6] = (src[1] & 0x80) ? 0xff : 0; /* B */
783 if (x + 3 < info->tile_width)
785 dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */
786 dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */
787 dst[9] = (src[1] & 0x10) ? 0xff : 0; /* B */
789 if (x + 4 < info->tile_width)
791 dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */
792 dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */
793 dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */
795 if (x + 5 < info->tile_width)
797 dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */
798 dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */
799 dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */
801 if (x + 6 < info->tile_width)
803 dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */
804 dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */
805 dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */
807 if (x + 7 < info->tile_width)
809 dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */
810 dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */
811 dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */
813 src += 3;
814 dst += 24;
818 free(srcdata);
820 /* 12bps RGB */
821 else if (info->source_bpp == 12 && info->samples == 3 && info->frame.bpp == 24)
823 BYTE *srcdata, *src, *dst;
824 DWORD x, y, count, width_bytes = (info->tile_width * 12 + 7) / 8;
826 count = width_bytes * info->tile_height;
828 srcdata = malloc(count);
829 if (!srcdata) return E_OUTOFMEMORY;
830 memcpy(srcdata, This->cached_tile, count);
832 for (y = 0; y < info->tile_height; y++)
834 src = srcdata + y * width_bytes;
835 dst = This->cached_tile + y * info->tile_width * 3;
837 for (x = 0; x < info->tile_width; x += 2)
839 dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
840 dst[1] = (src[0] & 0x0f) * 17; /* G */
841 dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
842 if (x + 1 < info->tile_width)
844 dst[5] = (src[1] & 0x0f) * 17; /* B */
845 dst[4] = ((src[2] & 0xf0) >> 4) * 17; /* G */
846 dst[3] = (src[2] & 0x0f) * 17; /* R */
848 src += 3;
849 dst += 6;
853 free(srcdata);
855 /* 4bps RGBA */
856 else if (info->source_bpp == 4 && info->samples == 4 && info->frame.bpp == 32)
858 BYTE *srcdata, *src, *dst;
859 DWORD x, y, count, width_bytes = (info->tile_width * 3 + 7) / 8;
861 count = width_bytes * info->tile_height;
863 srcdata = malloc(count);
864 if (!srcdata) return E_OUTOFMEMORY;
865 memcpy(srcdata, This->cached_tile, count);
867 for (y = 0; y < info->tile_height; y++)
869 src = srcdata + y * width_bytes;
870 dst = This->cached_tile + y * info->tile_width * 4;
872 /* 1 source byte expands to 2 BGRA samples */
874 for (x = 0; x < info->tile_width; x += 2)
876 dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
877 dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
878 dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
879 dst[3] = (src[0] & 0x10) ? 0xff : 0; /* A */
880 if (x + 1 < info->tile_width)
882 dst[4] = (src[0] & 0x02) ? 0xff : 0; /* B */
883 dst[5] = (src[0] & 0x04) ? 0xff : 0; /* G */
884 dst[6] = (src[0] & 0x08) ? 0xff : 0; /* R */
885 dst[7] = (src[0] & 0x01) ? 0xff : 0; /* A */
887 src++;
888 dst += 8;
892 free(srcdata);
894 /* 16bps RGBA */
895 else if (info->source_bpp == 16 && info->samples == 4 && info->frame.bpp == 32)
897 BYTE *srcdata, *src, *dst;
898 DWORD x, y, count, width_bytes = (info->tile_width * 12 + 7) / 8;
900 count = width_bytes * info->tile_height;
902 srcdata = malloc(count);
903 if (!srcdata) return E_OUTOFMEMORY;
904 memcpy(srcdata, This->cached_tile, count);
906 for (y = 0; y < info->tile_height; y++)
908 src = srcdata + y * width_bytes;
909 dst = This->cached_tile + y * info->tile_width * 4;
911 for (x = 0; x < info->tile_width; x++)
913 dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
914 dst[1] = (src[0] & 0x0f) * 17; /* G */
915 dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
916 dst[3] = (src[1] & 0x0f) * 17; /* A */
917 src += 2;
918 dst += 4;
922 free(srcdata);
924 /* 8bpp grayscale with extra alpha */
925 else if (info->source_bpp == 16 && info->samples == 2 && info->frame.bpp == 32)
927 BYTE *src;
928 DWORD *dst, count = info->tile_width * info->tile_height;
930 src = This->cached_tile + info->tile_width * info->tile_height * 2 - 2;
931 dst = (DWORD *)(This->cached_tile + info->tile_size - 4);
933 while (count--)
935 *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24);
936 src -= 2;
940 if (info->reverse_bgr)
942 if (info->bps == 8)
944 UINT sample_count = info->samples;
946 reverse_bgr8(sample_count, This->cached_tile, info->tile_width,
947 info->tile_height, info->tile_width * sample_count);
951 if (swap_bytes && info->bps > 8)
953 UINT row, i, samples_per_row;
954 BYTE *sample, temp;
956 samples_per_row = info->tile_width * info->samples;
958 switch(info->bps)
960 case 16:
961 for (row=0; row<info->tile_height; row++)
963 sample = This->cached_tile + row * info->tile_stride;
964 for (i=0; i<samples_per_row; i++)
966 temp = sample[1];
967 sample[1] = sample[0];
968 sample[0] = temp;
969 sample += 2;
972 break;
973 default:
974 ERR("unhandled bps for byte swap %u\n", info->bps);
975 return E_FAIL;
979 if (info->invert_grayscale)
981 BYTE *byte, *end;
983 if (info->samples != 1)
985 ERR("cannot invert grayscale image with %u samples\n", info->samples);
986 return E_FAIL;
989 end = This->cached_tile+info->tile_size;
991 for (byte = This->cached_tile; byte != end; byte++)
992 *byte = ~(*byte);
995 This->cached_tile_x = tile_x;
996 This->cached_tile_y = tile_y;
998 return S_OK;
1001 static HRESULT CDECL tiff_decoder_copy_pixels(struct decoder* iface, UINT frame,
1002 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
1004 struct tiff_decoder *This = impl_from_decoder(iface);
1005 HRESULT hr;
1006 UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y;
1007 UINT tile_x, tile_y;
1008 BYTE *dst_tilepos;
1009 WICRect rc;
1010 tiff_decode_info *info = &This->cached_decode_info;
1012 hr = tiff_decoder_select_frame(This, frame);
1013 if (FAILED(hr))
1014 return hr;
1016 if (!This->cached_tile)
1018 This->cached_tile = malloc(info->tile_size);
1019 if (!This->cached_tile)
1020 return E_OUTOFMEMORY;
1023 min_tile_x = prc->X / info->tile_width;
1024 min_tile_y = prc->Y / info->tile_height;
1025 max_tile_x = (prc->X+prc->Width-1) / info->tile_width;
1026 max_tile_y = (prc->Y+prc->Height-1) / info->tile_height;
1028 for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++)
1030 for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++)
1032 if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y)
1034 hr = tiff_decoder_read_tile(This, tile_x, tile_y);
1037 if (SUCCEEDED(hr))
1039 if (prc->X < tile_x * info->tile_width)
1040 rc.X = 0;
1041 else
1042 rc.X = prc->X - tile_x * info->tile_width;
1044 if (prc->Y < tile_y * info->tile_height)
1045 rc.Y = 0;
1046 else
1047 rc.Y = prc->Y - tile_y * info->tile_height;
1049 if (prc->X+prc->Width > (tile_x+1) * info->tile_width)
1050 rc.Width = info->tile_width - rc.X;
1051 else if (prc->X < tile_x * info->tile_width)
1052 rc.Width = prc->Width + prc->X - tile_x * info->tile_width;
1053 else
1054 rc.Width = prc->Width;
1056 if (prc->Y+prc->Height > (tile_y+1) * info->tile_height)
1057 rc.Height = info->tile_height - rc.Y;
1058 else if (prc->Y < tile_y * info->tile_height)
1059 rc.Height = prc->Height + prc->Y - tile_y * info->tile_height;
1060 else
1061 rc.Height = prc->Height;
1063 dst_tilepos = buffer + (stride * ((rc.Y + tile_y * info->tile_height) - prc->Y)) +
1064 ((info->frame.bpp * ((rc.X + tile_x * info->tile_width) - prc->X) + 7) / 8);
1066 hr = copy_pixels(info->frame.bpp, This->cached_tile,
1067 info->tile_width, info->tile_height, info->tile_stride,
1068 &rc, stride, buffersize, dst_tilepos);
1071 if (FAILED(hr))
1073 TRACE("<-- 0x%x\n", hr);
1074 return hr;
1079 return S_OK;
1082 static HRESULT CDECL tiff_decoder_get_color_context(struct decoder *iface,
1083 UINT frame, UINT num, BYTE **data, DWORD *datasize)
1085 struct tiff_decoder *This = impl_from_decoder(iface);
1086 const BYTE *profile;
1087 UINT len;
1088 HRESULT hr;
1090 hr = tiff_decoder_select_frame(This, frame);
1091 if (FAILED(hr))
1092 return hr;
1094 if (!pTIFFGetField(This->tiff, TIFFTAG_ICCPROFILE, &len, &profile))
1096 return E_UNEXPECTED;
1099 *datasize = len;
1100 *data = RtlAllocateHeap(GetProcessHeap(), 0, len);
1101 if (!*data)
1102 return E_OUTOFMEMORY;
1104 memcpy(*data, profile, len);
1106 return S_OK;
1109 static HRESULT CDECL tiff_decoder_get_metadata_blocks(struct decoder *iface,
1110 UINT frame, UINT *count, struct decoder_block **blocks)
1112 struct tiff_decoder *This = impl_from_decoder(iface);
1113 HRESULT hr;
1114 BOOL byte_swapped;
1115 struct decoder_block result;
1117 hr = tiff_decoder_select_frame(This, frame);
1118 if (FAILED(hr))
1119 return hr;
1121 *count = 1;
1123 result.offset = pTIFFCurrentDirOffset(This->tiff);
1124 result.length = 0;
1126 byte_swapped = pTIFFIsByteSwapped(This->tiff);
1127 #ifdef WORDS_BIGENDIAN
1128 result.options = byte_swapped ? WICPersistOptionLittleEndian : WICPersistOptionBigEndian;
1129 #else
1130 result.options = byte_swapped ? WICPersistOptionBigEndian : WICPersistOptionLittleEndian;
1131 #endif
1132 result.options |= WICPersistOptionNoCacheStream|DECODER_BLOCK_FULL_STREAM|DECODER_BLOCK_READER_CLSID;
1133 result.reader_clsid = CLSID_WICIfdMetadataReader;
1135 *blocks = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(**blocks));
1136 **blocks = result;
1138 return S_OK;
1141 static void CDECL tiff_decoder_destroy(struct decoder* iface)
1143 struct tiff_decoder *This = impl_from_decoder(iface);
1144 if (This->tiff) pTIFFClose(This->tiff);
1145 free(This->cached_tile);
1146 RtlFreeHeap(GetProcessHeap(), 0, This);
1149 static const struct decoder_funcs tiff_decoder_vtable = {
1150 tiff_decoder_initialize,
1151 tiff_decoder_get_frame_info,
1152 tiff_decoder_copy_pixels,
1153 tiff_decoder_get_metadata_blocks,
1154 tiff_decoder_get_color_context,
1155 tiff_decoder_destroy
1158 HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result)
1160 struct tiff_decoder *This;
1162 if (!load_libtiff())
1164 ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF);
1165 return E_FAIL;
1168 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
1169 if (!This) return E_OUTOFMEMORY;
1171 This->decoder.vtable = &tiff_decoder_vtable;
1172 This->tiff = NULL;
1173 This->cached_tile = NULL;
1174 This->cached_tile_x = -1;
1175 *result = &This->decoder;
1177 info->container_format = GUID_ContainerFormatTiff;
1178 info->block_format = GUID_ContainerFormatTiff;
1179 info->clsid = CLSID_WICTiffDecoder;
1181 return S_OK;
1184 struct tiff_encode_format {
1185 const WICPixelFormatGUID *guid;
1186 int photometric;
1187 int bps;
1188 int samples;
1189 int bpp;
1190 int extra_sample;
1191 int extra_sample_type;
1192 int reverse_bgr;
1193 int indexed;
1196 static const struct tiff_encode_format formats[] = {
1197 {&GUID_WICPixelFormat24bppBGR, 2, 8, 3, 24, 0, 0, 1},
1198 {&GUID_WICPixelFormat24bppRGB, 2, 8, 3, 24, 0, 0, 0},
1199 {&GUID_WICPixelFormatBlackWhite, 1, 1, 1, 1, 0, 0, 0},
1200 {&GUID_WICPixelFormat4bppGray, 1, 4, 1, 4, 0, 0, 0},
1201 {&GUID_WICPixelFormat8bppGray, 1, 8, 1, 8, 0, 0, 0},
1202 {&GUID_WICPixelFormat32bppBGRA, 2, 8, 4, 32, 1, 2, 1},
1203 {&GUID_WICPixelFormat32bppPBGRA, 2, 8, 4, 32, 1, 1, 1},
1204 {&GUID_WICPixelFormat48bppRGB, 2, 16, 3, 48, 0, 0, 0},
1205 {&GUID_WICPixelFormat64bppRGBA, 2, 16, 4, 64, 1, 2, 0},
1206 {&GUID_WICPixelFormat64bppPRGBA, 2, 16, 4, 64, 1, 1, 0},
1207 {&GUID_WICPixelFormat1bppIndexed, 3, 1, 1, 1, 0, 0, 0, 1},
1208 {&GUID_WICPixelFormat4bppIndexed, 3, 4, 1, 4, 0, 0, 0, 1},
1209 {&GUID_WICPixelFormat8bppIndexed, 3, 8, 1, 8, 0, 0, 0, 1},
1213 typedef struct tiff_encoder {
1214 struct encoder encoder;
1215 TIFF *tiff;
1216 const struct tiff_encode_format *format;
1217 struct encoder_frame encoder_frame;
1218 DWORD num_frames;
1219 DWORD lines_written;
1220 } tiff_encoder;
1222 static inline struct tiff_encoder *impl_from_encoder(struct encoder* iface)
1224 return CONTAINING_RECORD(iface, struct tiff_encoder, encoder);
1227 static HRESULT CDECL tiff_encoder_initialize(struct encoder* iface, IStream *stream)
1229 struct tiff_encoder* This = impl_from_encoder(iface);
1230 TIFF *tiff;
1232 tiff = tiff_open_stream(stream, "w");
1234 if (!tiff)
1235 return E_FAIL;
1237 This->tiff = tiff;
1239 return S_OK;
1242 static HRESULT CDECL tiff_encoder_get_supported_format(struct encoder *iface,
1243 GUID *pixel_format, DWORD *bpp, BOOL *indexed)
1245 int i;
1247 if (IsEqualGUID(pixel_format, &GUID_WICPixelFormat2bppIndexed))
1248 *pixel_format = GUID_WICPixelFormat4bppIndexed;
1250 for (i=0; formats[i].guid; i++)
1252 if (IsEqualGUID(formats[i].guid, pixel_format))
1253 break;
1256 if (!formats[i].guid) i = 0;
1258 *pixel_format = *formats[i].guid;
1259 *bpp = formats[i].bpp;
1260 *indexed = formats[i].indexed;
1262 return S_OK;
1265 static HRESULT CDECL tiff_encoder_create_frame(struct encoder* iface, const struct encoder_frame *frame)
1267 struct tiff_encoder* This = impl_from_encoder(iface);
1268 int i;
1270 if (This->num_frames != 0)
1271 pTIFFWriteDirectory(This->tiff);
1273 This->num_frames++;
1274 This->lines_written = 0;
1275 This->encoder_frame = *frame;
1277 for (i=0; formats[i].guid; i++)
1279 if (IsEqualGUID(formats[i].guid, &frame->pixel_format))
1280 break;
1283 This->format = &formats[i];
1285 pTIFFSetField(This->tiff, TIFFTAG_PHOTOMETRIC, (uint16)This->format->photometric);
1286 pTIFFSetField(This->tiff, TIFFTAG_PLANARCONFIG, (uint16)1);
1287 pTIFFSetField(This->tiff, TIFFTAG_BITSPERSAMPLE, (uint16)This->format->bps);
1288 pTIFFSetField(This->tiff, TIFFTAG_SAMPLESPERPIXEL, (uint16)This->format->samples);
1290 if (This->format->extra_sample)
1292 uint16 extra_samples;
1293 extra_samples = This->format->extra_sample_type;
1295 pTIFFSetField(This->tiff, TIFFTAG_EXTRASAMPLES, (uint16)1, &extra_samples);
1298 pTIFFSetField(This->tiff, TIFFTAG_IMAGEWIDTH, (uint32)frame->width);
1299 pTIFFSetField(This->tiff, TIFFTAG_IMAGELENGTH, (uint32)frame->height);
1301 if (frame->dpix != 0.0 && frame->dpiy != 0.0)
1303 pTIFFSetField(This->tiff, TIFFTAG_RESOLUTIONUNIT, (uint16)2); /* Inch */
1304 pTIFFSetField(This->tiff, TIFFTAG_XRESOLUTION, (float)frame->dpix);
1305 pTIFFSetField(This->tiff, TIFFTAG_YRESOLUTION, (float)frame->dpiy);
1308 if (This->format->bpp <= 8 && frame->num_colors && This->format->indexed)
1310 uint16 red[256], green[256], blue[256];
1311 UINT i;
1313 for (i = 0; i < frame->num_colors; i++)
1315 red[i] = (frame->palette[i] >> 8) & 0xff00;
1316 green[i] = frame->palette[i] & 0xff00;
1317 blue[i] = (frame->palette[i] << 8) & 0xff00;
1320 pTIFFSetField(This->tiff, TIFFTAG_COLORMAP, red, green, blue);
1323 return S_OK;
1326 static HRESULT CDECL tiff_encoder_write_lines(struct encoder* iface,
1327 BYTE *data, DWORD line_count, DWORD stride)
1329 struct tiff_encoder* This = impl_from_encoder(iface);
1330 BYTE *row_data, *swapped_data = NULL;
1331 UINT i, j, line_size;
1333 line_size = ((This->encoder_frame.width * This->format->bpp)+7)/8;
1335 if (This->format->reverse_bgr)
1337 swapped_data = malloc(line_size);
1338 if (!swapped_data)
1339 return E_OUTOFMEMORY;
1342 for (i=0; i<line_count; i++)
1344 row_data = data + i * stride;
1346 if (This->format->reverse_bgr && This->format->bps == 8)
1348 memcpy(swapped_data, row_data, line_size);
1349 for (j=0; j<line_size; j += This->format->samples)
1351 BYTE temp;
1352 temp = swapped_data[j];
1353 swapped_data[j] = swapped_data[j+2];
1354 swapped_data[j+2] = temp;
1356 row_data = swapped_data;
1359 pTIFFWriteScanline(This->tiff, (tdata_t)row_data, i+This->lines_written, 0);
1362 This->lines_written += line_count;
1364 return S_OK;
1367 static HRESULT CDECL tiff_encoder_commit_frame(struct encoder* iface)
1369 return S_OK;
1372 static HRESULT CDECL tiff_encoder_commit_file(struct encoder* iface)
1374 struct tiff_encoder* This = impl_from_encoder(iface);
1376 pTIFFClose(This->tiff);
1377 This->tiff = NULL;
1379 return S_OK;
1382 static void CDECL tiff_encoder_destroy(struct encoder* iface)
1384 struct tiff_encoder *This = impl_from_encoder(iface);
1386 if (This->tiff) pTIFFClose(This->tiff);
1387 RtlFreeHeap(GetProcessHeap(), 0, This);
1390 static const struct encoder_funcs tiff_encoder_vtable = {
1391 tiff_encoder_initialize,
1392 tiff_encoder_get_supported_format,
1393 tiff_encoder_create_frame,
1394 tiff_encoder_write_lines,
1395 tiff_encoder_commit_frame,
1396 tiff_encoder_commit_file,
1397 tiff_encoder_destroy
1400 HRESULT CDECL tiff_encoder_create(struct encoder_info *info, struct encoder **result)
1402 struct tiff_encoder *This;
1404 if (!load_libtiff())
1406 ERR("Failed writing TIFF because unable to load %s\n",SONAME_LIBTIFF);
1407 return E_FAIL;
1410 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
1411 if (!This) return E_OUTOFMEMORY;
1413 This->encoder.vtable = &tiff_encoder_vtable;
1414 This->tiff = NULL;
1415 This->num_frames = 0;
1417 info->flags = ENCODER_FLAGS_MULTI_FRAME | ENCODER_FLAGS_SUPPORTS_METADATA;
1418 info->container_format = GUID_ContainerFormatTiff;
1419 info->clsid = CLSID_WICTiffEncoder;
1420 info->encoder_options[0] = ENCODER_OPTION_COMPRESSION_METHOD;
1421 info->encoder_options[1] = ENCODER_OPTION_COMPRESSION_QUALITY;
1422 info->encoder_options[2] = ENCODER_OPTION_END;
1424 *result = &This->encoder;
1426 return S_OK;
1429 #else /* !SONAME_LIBTIFF */
1431 HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result)
1433 ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
1434 return E_FAIL;
1437 HRESULT CDECL tiff_encoder_create(struct encoder_info *info, struct encoder **result)
1439 ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");
1440 return E_FAIL;
1443 #endif