user32: Move unpack_message call to User32CallWindowProc.
[wine.git] / dlls / windowscodecs / libtiff.c
blobc4676601c2c4499ea0e5b7b2d4761c1de67b0f05
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 #include <stdarg.h>
21 #include <math.h>
22 #include <sys/types.h>
23 #include <tiffio.h>
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "windef.h"
28 #include "winternl.h"
29 #include "winbase.h"
30 #include "objbase.h"
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 static tsize_t tiff_stream_read(thandle_t client_data, tdata_t data, tsize_t size)
40 IStream *stream = (IStream*)client_data;
41 ULONG bytes_read;
42 HRESULT hr;
44 hr = stream_read(stream, data, size, &bytes_read);
45 if (FAILED(hr)) bytes_read = 0;
46 return bytes_read;
49 static tsize_t tiff_stream_write(thandle_t client_data, tdata_t data, tsize_t size)
51 IStream *stream = (IStream*)client_data;
52 ULONG bytes_written;
53 HRESULT hr;
55 hr = stream_write(stream, data, size, &bytes_written);
56 if (FAILED(hr)) bytes_written = 0;
57 return bytes_written;
60 static toff_t tiff_stream_seek(thandle_t client_data, toff_t offset, int whence)
62 IStream *stream = (IStream*)client_data;
63 DWORD origin;
64 ULONGLONG new_position;
65 HRESULT hr;
67 switch (whence)
69 case SEEK_SET:
70 origin = STREAM_SEEK_SET;
71 break;
72 case SEEK_CUR:
73 origin = STREAM_SEEK_CUR;
74 break;
75 case SEEK_END:
76 origin = STREAM_SEEK_END;
77 break;
78 default:
79 ERR("unknown whence value %i\n", whence);
80 return -1;
83 hr = stream_seek(stream, offset, origin, &new_position);
84 if (SUCCEEDED(hr)) return new_position;
85 else return -1;
88 static int tiff_stream_close(thandle_t client_data)
90 /* Caller is responsible for releasing the stream object. */
91 return 0;
94 static toff_t tiff_stream_size(thandle_t client_data)
96 IStream *stream = (IStream*)client_data;
97 ULONGLONG size;
98 HRESULT hr;
100 hr = stream_getsize(stream, &size);
102 if (SUCCEEDED(hr)) return size;
103 else return -1;
106 static int tiff_stream_map(thandle_t client_data, tdata_t *addr, toff_t *size)
108 /* Cannot mmap streams */
109 return 0;
112 static void tiff_stream_unmap(thandle_t client_data, tdata_t addr, toff_t size)
114 /* No need to ever do this, since we can't map things. */
117 static TIFF* tiff_open_stream(IStream *stream, const char *mode)
119 stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
121 return TIFFClientOpen("<IStream object>", mode, stream, tiff_stream_read,
122 tiff_stream_write, (void *)tiff_stream_seek, tiff_stream_close,
123 (void *)tiff_stream_size, (void *)tiff_stream_map, (void *)tiff_stream_unmap);
126 typedef struct {
127 struct decoder_frame frame;
128 int bps;
129 int samples;
130 int source_bpp;
131 int planar;
132 int indexed;
133 int reverse_bgr;
134 int invert_grayscale;
135 UINT tile_width, tile_height;
136 UINT tile_stride;
137 UINT tile_size;
138 int tiled;
139 UINT tiles_across;
140 } tiff_decode_info;
142 struct tiff_decoder
144 struct decoder decoder;
145 IStream *stream;
146 TIFF *tiff;
147 DWORD frame_count;
148 DWORD cached_frame;
149 tiff_decode_info cached_decode_info;
150 INT cached_tile_x, cached_tile_y;
151 BYTE *cached_tile;
154 static inline struct tiff_decoder *impl_from_decoder(struct decoder* iface)
156 return CONTAINING_RECORD(iface, struct tiff_decoder, decoder);
159 static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
161 uint16_t photometric, bps, samples, planar;
162 uint16_t extra_sample_count, extra_sample, *extra_samples;
163 uint16_t *red, *green, *blue;
164 UINT resolution_unit;
165 float xres=0.0, yres=0.0;
166 int ret, i;
167 const BYTE *profile;
168 UINT len;
170 decode_info->indexed = 0;
171 decode_info->reverse_bgr = 0;
172 decode_info->invert_grayscale = 0;
173 decode_info->tiled = 0;
174 decode_info->source_bpp = 0;
176 ret = TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
177 if (!ret)
179 WARN("missing PhotometricInterpretation tag\n");
180 return E_FAIL;
183 ret = TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps);
184 if (!ret) bps = 1;
185 decode_info->bps = bps;
187 ret = TIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
188 if (!ret) samples = 1;
189 decode_info->samples = samples;
191 if (samples == 1)
192 planar = 1;
193 else
195 ret = TIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar);
196 if (!ret) planar = 1;
197 if (planar != 1)
199 FIXME("unhandled planar configuration %u\n", planar);
200 return E_FAIL;
203 decode_info->planar = planar;
205 TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar, photometric, samples, bps);
207 switch(photometric)
209 case 0: /* WhiteIsZero */
210 decode_info->invert_grayscale = 1;
211 /* fall through */
212 case 1: /* BlackIsZero */
213 if (samples == 2)
215 ret = TIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
216 if (!ret)
218 extra_sample_count = 1;
219 extra_sample = 0;
220 extra_samples = &extra_sample;
223 else if (samples != 1)
225 FIXME("unhandled %dbpp sample count %u\n", bps, samples);
226 return E_FAIL;
229 decode_info->frame.bpp = bps * samples;
230 decode_info->source_bpp = decode_info->frame.bpp;
231 switch (bps)
233 case 1:
234 if (samples != 1)
236 FIXME("unhandled 1bpp sample count %u\n", samples);
237 return E_FAIL;
239 decode_info->frame.pixel_format = GUID_WICPixelFormatBlackWhite;
240 break;
241 case 4:
242 if (samples != 1)
244 FIXME("unhandled 4bpp grayscale sample count %u\n", samples);
245 return E_FAIL;
247 decode_info->frame.pixel_format = GUID_WICPixelFormat4bppGray;
248 break;
249 case 8:
250 if (samples == 1)
251 decode_info->frame.pixel_format = GUID_WICPixelFormat8bppGray;
252 else
254 decode_info->frame.bpp = 32;
256 switch(extra_samples[0])
258 case 1: /* Associated (pre-multiplied) alpha data */
259 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppPBGRA;
260 break;
261 case 0: /* Unspecified data */
262 case 2: /* Unassociated alpha data */
263 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
264 break;
265 default:
266 FIXME("unhandled extra sample type %u\n", extra_samples[0]);
267 return E_FAIL;
270 break;
271 case 16:
272 if (samples != 1)
274 FIXME("unhandled 16bpp grayscale sample count %u\n", samples);
275 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
277 decode_info->frame.pixel_format = GUID_WICPixelFormat16bppGray;
278 break;
279 case 32:
280 if (samples != 1)
282 FIXME("unhandled 32bpp grayscale sample count %u\n", samples);
283 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
285 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppGrayFloat;
286 break;
287 default:
288 WARN("unhandled greyscale bit count %u\n", bps);
289 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
291 break;
292 case 2: /* RGB */
293 if (samples == 4)
295 ret = TIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
296 if (!ret)
298 extra_sample_count = 1;
299 extra_sample = 0;
300 extra_samples = &extra_sample;
303 else if (samples != 3)
305 FIXME("unhandled RGB sample count %u\n", samples);
306 return E_FAIL;
309 decode_info->frame.bpp = max(bps, 8) * samples;
310 decode_info->source_bpp = bps * samples;
311 switch(bps)
313 case 1:
314 case 4:
315 case 8:
316 decode_info->reverse_bgr = 1;
317 if (samples == 3)
318 decode_info->frame.pixel_format = GUID_WICPixelFormat24bppBGR;
319 else
320 switch(extra_samples[0])
322 case 1: /* Associated (pre-multiplied) alpha data */
323 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppPBGRA;
324 break;
325 case 0: /* Unspecified data */
326 case 2: /* Unassociated alpha data */
327 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
328 break;
329 default:
330 FIXME("unhandled extra sample type %i\n", extra_samples[0]);
331 return E_FAIL;
333 break;
334 case 16:
335 if (samples == 3)
336 decode_info->frame.pixel_format = GUID_WICPixelFormat48bppRGB;
337 else
338 switch(extra_samples[0])
340 case 1: /* Associated (pre-multiplied) alpha data */
341 decode_info->frame.pixel_format = GUID_WICPixelFormat64bppPRGBA;
342 break;
343 case 0: /* Unspecified data */
344 case 2: /* Unassociated alpha data */
345 decode_info->frame.pixel_format = GUID_WICPixelFormat64bppRGBA;
346 break;
347 default:
348 FIXME("unhandled extra sample type %i\n", extra_samples[0]);
349 return E_FAIL;
351 break;
352 case 32:
353 if (samples == 3)
354 decode_info->frame.pixel_format = GUID_WICPixelFormat96bppRGBFloat;
355 else
356 switch(extra_samples[0])
358 case 1: /* Associated (pre-multiplied) alpha data */
359 decode_info->frame.pixel_format = GUID_WICPixelFormat128bppPRGBAFloat;
360 break;
361 case 0: /* Unspecified data */
362 case 2: /* Unassociated alpha data */
363 decode_info->frame.pixel_format = GUID_WICPixelFormat128bppRGBAFloat;
364 break;
365 default:
366 FIXME("unhandled extra sample type %i\n", extra_samples[0]);
367 return E_FAIL;
369 break;
370 default:
371 WARN("unhandled RGB bit count %u\n", bps);
372 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
374 break;
375 case 3: /* RGB Palette */
376 if (samples != 1)
378 FIXME("unhandled indexed sample count %u\n", samples);
379 return E_FAIL;
382 decode_info->indexed = 1;
383 decode_info->frame.bpp = bps;
384 switch (bps)
386 case 1:
387 decode_info->frame.pixel_format = GUID_WICPixelFormat1bppIndexed;
388 break;
389 case 2:
390 decode_info->frame.pixel_format = GUID_WICPixelFormat2bppIndexed;
391 break;
392 case 4:
393 decode_info->frame.pixel_format = GUID_WICPixelFormat4bppIndexed;
394 break;
395 case 8:
396 decode_info->frame.pixel_format = GUID_WICPixelFormat8bppIndexed;
397 break;
398 default:
399 FIXME("unhandled indexed bit count %u\n", bps);
400 return E_NOTIMPL;
402 break;
404 case 5: /* Separated */
405 if (samples != 4)
407 FIXME("unhandled Separated sample count %u\n", samples);
408 return E_FAIL;
411 decode_info->frame.bpp = bps * samples;
412 switch(bps)
414 case 8:
415 decode_info->frame.pixel_format = GUID_WICPixelFormat32bppCMYK;
416 break;
417 case 16:
418 decode_info->frame.pixel_format = GUID_WICPixelFormat64bppCMYK;
419 break;
421 default:
422 WARN("unhandled Separated bit count %u\n", bps);
423 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
425 break;
427 case 4: /* Transparency mask */
428 case 6: /* YCbCr */
429 case 8: /* CIELab */
430 default:
431 FIXME("unhandled PhotometricInterpretation %u\n", photometric);
432 return E_FAIL;
435 ret = TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->frame.width);
436 if (!ret)
438 WARN("missing image width\n");
439 return E_FAIL;
442 ret = TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->frame.height);
443 if (!ret)
445 WARN("missing image length\n");
446 return E_FAIL;
449 if ((ret = TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width)))
451 decode_info->tiled = 1;
453 ret = TIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height);
454 if (!ret)
456 WARN("missing tile height\n");
457 return E_FAIL;
460 decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
461 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
462 decode_info->tiles_across = (decode_info->frame.width + decode_info->tile_width - 1) / decode_info->tile_width;
464 else if ((ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height)))
466 if (decode_info->tile_height > decode_info->frame.height)
467 decode_info->tile_height = decode_info->frame.height;
468 decode_info->tile_width = decode_info->frame.width;
469 decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
470 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
472 else
474 /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
475 decode_info->tile_height = decode_info->frame.height;
476 decode_info->tile_width = decode_info->frame.width;
477 decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
478 decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
481 resolution_unit = 0;
482 TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resolution_unit);
484 ret = TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &xres);
485 if (!ret)
487 WARN("missing X resolution\n");
489 /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131)
490 * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */
491 if (!isfinite(xres))
493 xres = 0.0;
496 ret = TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &yres);
497 if (!ret)
499 WARN("missing Y resolution\n");
501 if (!isfinite(yres))
503 yres = 0.0;
506 if (xres == 0.0 || yres == 0.0)
508 decode_info->frame.dpix = decode_info->frame.dpiy = 96.0;
510 else
512 switch (resolution_unit)
514 default:
515 FIXME("unknown resolution unit %i\n", resolution_unit);
516 /* fall through */
517 case 0: /* Not set */
518 case 1: /* Relative measurements */
519 case 2: /* Inch */
520 decode_info->frame.dpix = xres;
521 decode_info->frame.dpiy = yres;
522 break;
523 case 3: /* Centimeter */
524 decode_info->frame.dpix = xres * 2.54;
525 decode_info->frame.dpiy = yres * 2.54;
526 break;
530 if (decode_info->indexed &&
531 TIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue))
533 decode_info->frame.num_colors = 1 << decode_info->bps;
534 for (i=0; i<decode_info->frame.num_colors; i++)
536 decode_info->frame.palette[i] = 0xff000000 |
537 ((red[i]<<8) & 0xff0000) |
538 (green[i] & 0xff00) |
539 ((blue[i]>>8) & 0xff);
542 else
544 decode_info->frame.num_colors = 0;
547 if (TIFFGetField(tiff, TIFFTAG_ICCPROFILE, &len, &profile))
548 decode_info->frame.num_color_contexts = 1;
549 else
550 decode_info->frame.num_color_contexts = 0;
552 return S_OK;
555 static HRESULT CDECL tiff_decoder_initialize(struct decoder* iface, IStream *stream, struct decoder_stat *st)
557 struct tiff_decoder *This = impl_from_decoder(iface);
558 HRESULT hr;
560 This->tiff = tiff_open_stream(stream, "r");
561 if (!This->tiff)
562 return E_FAIL;
564 This->frame_count = TIFFNumberOfDirectories(This->tiff);
565 This->cached_frame = 0;
566 hr = tiff_get_decode_info(This->tiff, &This->cached_decode_info);
567 if (FAILED(hr))
568 goto fail;
570 st->frame_count = This->frame_count;
571 st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
572 WICBitmapDecoderCapabilityCanDecodeSomeImages |
573 WICBitmapDecoderCapabilityCanEnumerateMetadata;
574 return S_OK;
576 fail:
577 TIFFClose(This->tiff);
578 This->tiff = NULL;
579 return hr;
582 static HRESULT tiff_decoder_select_frame(struct tiff_decoder* This, DWORD frame)
584 HRESULT hr;
585 UINT prev_tile_size;
586 int res;
588 if (frame >= This->frame_count)
589 return E_INVALIDARG;
591 if (This->cached_frame == frame)
592 return S_OK;
594 prev_tile_size = This->cached_tile ? This->cached_decode_info.tile_size : 0;
596 res = TIFFSetDirectory(This->tiff, frame);
597 if (!res)
598 return E_INVALIDARG;
600 hr = tiff_get_decode_info(This->tiff, &This->cached_decode_info);
602 This->cached_tile_x = -1;
604 if (SUCCEEDED(hr))
606 This->cached_frame = frame;
607 if (This->cached_decode_info.tile_size > prev_tile_size)
609 free(This->cached_tile);
610 This->cached_tile = NULL;
613 else
615 /* Set an invalid value to ensure we'll refresh cached_decode_info before using it. */
616 This->cached_frame = This->frame_count;
617 free(This->cached_tile);
618 This->cached_tile = NULL;
621 return hr;
624 static HRESULT CDECL tiff_decoder_get_frame_info(struct decoder* iface, UINT frame, struct decoder_frame *info)
626 struct tiff_decoder *This = impl_from_decoder(iface);
627 HRESULT hr;
629 hr = tiff_decoder_select_frame(This, frame);
630 if (SUCCEEDED(hr))
632 *info = This->cached_decode_info.frame;
635 return hr;
638 static HRESULT tiff_decoder_read_tile(struct tiff_decoder *This, UINT tile_x, UINT tile_y)
640 tsize_t ret;
641 int swap_bytes;
642 tiff_decode_info *info = &This->cached_decode_info;
644 swap_bytes = TIFFIsByteSwapped(This->tiff);
646 if (info->tiled)
647 ret = TIFFReadEncodedTile(This->tiff, tile_x + tile_y * info->tiles_across, This->cached_tile, info->tile_size);
648 else
649 ret = TIFFReadEncodedStrip(This->tiff, tile_y, This->cached_tile, info->tile_size);
651 if (ret == -1)
652 return E_FAIL;
654 /* 3bps RGB */
655 if (info->source_bpp == 3 && info->samples == 3 && info->frame.bpp == 24)
657 BYTE *srcdata, *src, *dst;
658 DWORD x, y, count, width_bytes = (info->tile_width * 3 + 7) / 8;
660 count = width_bytes * info->tile_height;
662 srcdata = malloc(count);
663 if (!srcdata) return E_OUTOFMEMORY;
664 memcpy(srcdata, This->cached_tile, count);
666 for (y = 0; y < info->tile_height; y++)
668 src = srcdata + y * width_bytes;
669 dst = This->cached_tile + y * info->tile_width * 3;
671 for (x = 0; x < info->tile_width; x += 8)
673 dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
674 dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
675 dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
676 if (x + 1 < info->tile_width)
678 dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */
679 dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */
680 dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */
682 if (x + 2 < info->tile_width)
684 dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */
685 dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */
686 dst[6] = (src[1] & 0x80) ? 0xff : 0; /* B */
688 if (x + 3 < info->tile_width)
690 dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */
691 dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */
692 dst[9] = (src[1] & 0x10) ? 0xff : 0; /* B */
694 if (x + 4 < info->tile_width)
696 dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */
697 dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */
698 dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */
700 if (x + 5 < info->tile_width)
702 dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */
703 dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */
704 dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */
706 if (x + 6 < info->tile_width)
708 dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */
709 dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */
710 dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */
712 if (x + 7 < info->tile_width)
714 dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */
715 dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */
716 dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */
718 src += 3;
719 dst += 24;
723 free(srcdata);
725 /* 12bps RGB */
726 else if (info->source_bpp == 12 && info->samples == 3 && info->frame.bpp == 24)
728 BYTE *srcdata, *src, *dst;
729 DWORD x, y, count, width_bytes = (info->tile_width * 12 + 7) / 8;
731 count = width_bytes * info->tile_height;
733 srcdata = malloc(count);
734 if (!srcdata) return E_OUTOFMEMORY;
735 memcpy(srcdata, This->cached_tile, count);
737 for (y = 0; y < info->tile_height; y++)
739 src = srcdata + y * width_bytes;
740 dst = This->cached_tile + y * info->tile_width * 3;
742 for (x = 0; x < info->tile_width; x += 2)
744 dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
745 dst[1] = (src[0] & 0x0f) * 17; /* G */
746 dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
747 if (x + 1 < info->tile_width)
749 dst[5] = (src[1] & 0x0f) * 17; /* B */
750 dst[4] = ((src[2] & 0xf0) >> 4) * 17; /* G */
751 dst[3] = (src[2] & 0x0f) * 17; /* R */
753 src += 3;
754 dst += 6;
758 free(srcdata);
760 /* 4bps RGBA */
761 else if (info->source_bpp == 4 && info->samples == 4 && info->frame.bpp == 32)
763 BYTE *srcdata, *src, *dst;
764 DWORD x, y, count, width_bytes = (info->tile_width * 3 + 7) / 8;
766 count = width_bytes * info->tile_height;
768 srcdata = malloc(count);
769 if (!srcdata) return E_OUTOFMEMORY;
770 memcpy(srcdata, This->cached_tile, count);
772 for (y = 0; y < info->tile_height; y++)
774 src = srcdata + y * width_bytes;
775 dst = This->cached_tile + y * info->tile_width * 4;
777 /* 1 source byte expands to 2 BGRA samples */
779 for (x = 0; x < info->tile_width; x += 2)
781 dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
782 dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
783 dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
784 dst[3] = (src[0] & 0x10) ? 0xff : 0; /* A */
785 if (x + 1 < info->tile_width)
787 dst[4] = (src[0] & 0x02) ? 0xff : 0; /* B */
788 dst[5] = (src[0] & 0x04) ? 0xff : 0; /* G */
789 dst[6] = (src[0] & 0x08) ? 0xff : 0; /* R */
790 dst[7] = (src[0] & 0x01) ? 0xff : 0; /* A */
792 src++;
793 dst += 8;
797 free(srcdata);
799 /* 16bps RGBA */
800 else if (info->source_bpp == 16 && info->samples == 4 && info->frame.bpp == 32)
802 BYTE *srcdata, *src, *dst;
803 DWORD x, y, count, width_bytes = (info->tile_width * 12 + 7) / 8;
805 count = width_bytes * info->tile_height;
807 srcdata = malloc(count);
808 if (!srcdata) return E_OUTOFMEMORY;
809 memcpy(srcdata, This->cached_tile, count);
811 for (y = 0; y < info->tile_height; y++)
813 src = srcdata + y * width_bytes;
814 dst = This->cached_tile + y * info->tile_width * 4;
816 for (x = 0; x < info->tile_width; x++)
818 dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
819 dst[1] = (src[0] & 0x0f) * 17; /* G */
820 dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
821 dst[3] = (src[1] & 0x0f) * 17; /* A */
822 src += 2;
823 dst += 4;
827 free(srcdata);
829 /* 8bpp grayscale with extra alpha */
830 else if (info->source_bpp == 16 && info->samples == 2 && info->frame.bpp == 32)
832 BYTE *src;
833 DWORD *dst, count = info->tile_width * info->tile_height;
835 src = This->cached_tile + info->tile_width * info->tile_height * 2 - 2;
836 dst = (DWORD *)(This->cached_tile + info->tile_size - 4);
838 while (count--)
840 *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24);
841 src -= 2;
845 if (info->reverse_bgr)
847 if (info->bps == 8)
849 UINT sample_count = info->samples;
851 reverse_bgr8(sample_count, This->cached_tile, info->tile_width,
852 info->tile_height, info->tile_width * sample_count);
856 if (swap_bytes && info->bps > 8)
858 UINT row, i, samples_per_row;
859 BYTE *sample, temp;
861 samples_per_row = info->tile_width * info->samples;
863 switch(info->bps)
865 case 16:
866 for (row=0; row<info->tile_height; row++)
868 sample = This->cached_tile + row * info->tile_stride;
869 for (i=0; i<samples_per_row; i++)
871 temp = sample[1];
872 sample[1] = sample[0];
873 sample[0] = temp;
874 sample += 2;
877 break;
878 default:
879 ERR("unhandled bps for byte swap %u\n", info->bps);
880 return E_FAIL;
884 if (info->invert_grayscale)
886 BYTE *byte, *end;
888 if (info->samples != 1)
890 ERR("cannot invert grayscale image with %u samples\n", info->samples);
891 return E_FAIL;
894 end = This->cached_tile+info->tile_size;
896 for (byte = This->cached_tile; byte != end; byte++)
897 *byte = ~(*byte);
900 This->cached_tile_x = tile_x;
901 This->cached_tile_y = tile_y;
903 return S_OK;
906 static HRESULT CDECL tiff_decoder_copy_pixels(struct decoder* iface, UINT frame,
907 const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
909 struct tiff_decoder *This = impl_from_decoder(iface);
910 HRESULT hr;
911 UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y;
912 UINT tile_x, tile_y;
913 BYTE *dst_tilepos;
914 WICRect rc;
915 tiff_decode_info *info = &This->cached_decode_info;
917 hr = tiff_decoder_select_frame(This, frame);
918 if (FAILED(hr))
919 return hr;
921 if (!This->cached_tile)
923 This->cached_tile = malloc(info->tile_size);
924 if (!This->cached_tile)
925 return E_OUTOFMEMORY;
928 min_tile_x = prc->X / info->tile_width;
929 min_tile_y = prc->Y / info->tile_height;
930 max_tile_x = (prc->X+prc->Width-1) / info->tile_width;
931 max_tile_y = (prc->Y+prc->Height-1) / info->tile_height;
933 for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++)
935 for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++)
937 if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y)
939 hr = tiff_decoder_read_tile(This, tile_x, tile_y);
942 if (SUCCEEDED(hr))
944 if (prc->X < tile_x * info->tile_width)
945 rc.X = 0;
946 else
947 rc.X = prc->X - tile_x * info->tile_width;
949 if (prc->Y < tile_y * info->tile_height)
950 rc.Y = 0;
951 else
952 rc.Y = prc->Y - tile_y * info->tile_height;
954 if (prc->X+prc->Width > (tile_x+1) * info->tile_width)
955 rc.Width = info->tile_width - rc.X;
956 else if (prc->X < tile_x * info->tile_width)
957 rc.Width = prc->Width + prc->X - tile_x * info->tile_width;
958 else
959 rc.Width = prc->Width;
961 if (prc->Y+prc->Height > (tile_y+1) * info->tile_height)
962 rc.Height = info->tile_height - rc.Y;
963 else if (prc->Y < tile_y * info->tile_height)
964 rc.Height = prc->Height + prc->Y - tile_y * info->tile_height;
965 else
966 rc.Height = prc->Height;
968 dst_tilepos = buffer + (stride * ((rc.Y + tile_y * info->tile_height) - prc->Y)) +
969 ((info->frame.bpp * ((rc.X + tile_x * info->tile_width) - prc->X) + 7) / 8);
971 hr = copy_pixels(info->frame.bpp, This->cached_tile,
972 info->tile_width, info->tile_height, info->tile_stride,
973 &rc, stride, buffersize, dst_tilepos);
976 if (FAILED(hr))
978 TRACE("<-- 0x%lx\n", hr);
979 return hr;
984 return S_OK;
987 static HRESULT CDECL tiff_decoder_get_color_context(struct decoder *iface,
988 UINT frame, UINT num, BYTE **data, DWORD *datasize)
990 struct tiff_decoder *This = impl_from_decoder(iface);
991 const BYTE *profile;
992 UINT len;
993 HRESULT hr;
995 hr = tiff_decoder_select_frame(This, frame);
996 if (FAILED(hr))
997 return hr;
999 if (!TIFFGetField(This->tiff, TIFFTAG_ICCPROFILE, &len, &profile))
1001 return E_UNEXPECTED;
1004 *datasize = len;
1005 *data = RtlAllocateHeap(GetProcessHeap(), 0, len);
1006 if (!*data)
1007 return E_OUTOFMEMORY;
1009 memcpy(*data, profile, len);
1011 return S_OK;
1014 static HRESULT CDECL tiff_decoder_get_metadata_blocks(struct decoder *iface,
1015 UINT frame, UINT *count, struct decoder_block **blocks)
1017 struct tiff_decoder *This = impl_from_decoder(iface);
1018 HRESULT hr;
1019 BOOL byte_swapped;
1020 struct decoder_block result;
1022 hr = tiff_decoder_select_frame(This, frame);
1023 if (FAILED(hr))
1024 return hr;
1026 *count = 1;
1028 result.offset = TIFFCurrentDirOffset(This->tiff);
1029 result.length = 0;
1031 byte_swapped = TIFFIsByteSwapped(This->tiff);
1032 #ifdef WORDS_BIGENDIAN
1033 result.options = byte_swapped ? WICPersistOptionLittleEndian : WICPersistOptionBigEndian;
1034 #else
1035 result.options = byte_swapped ? WICPersistOptionBigEndian : WICPersistOptionLittleEndian;
1036 #endif
1037 result.options |= WICPersistOptionNoCacheStream|DECODER_BLOCK_FULL_STREAM|DECODER_BLOCK_READER_CLSID;
1038 result.reader_clsid = CLSID_WICIfdMetadataReader;
1040 *blocks = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(**blocks));
1041 **blocks = result;
1043 return S_OK;
1046 static void CDECL tiff_decoder_destroy(struct decoder* iface)
1048 struct tiff_decoder *This = impl_from_decoder(iface);
1049 if (This->tiff) TIFFClose(This->tiff);
1050 free(This->cached_tile);
1051 RtlFreeHeap(GetProcessHeap(), 0, This);
1054 static const struct decoder_funcs tiff_decoder_vtable = {
1055 tiff_decoder_initialize,
1056 tiff_decoder_get_frame_info,
1057 tiff_decoder_copy_pixels,
1058 tiff_decoder_get_metadata_blocks,
1059 tiff_decoder_get_color_context,
1060 tiff_decoder_destroy
1063 HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result)
1065 struct tiff_decoder *This;
1067 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
1068 if (!This) return E_OUTOFMEMORY;
1070 This->decoder.vtable = &tiff_decoder_vtable;
1071 This->tiff = NULL;
1072 This->cached_tile = NULL;
1073 This->cached_tile_x = -1;
1074 *result = &This->decoder;
1076 info->container_format = GUID_ContainerFormatTiff;
1077 info->block_format = GUID_ContainerFormatTiff;
1078 info->clsid = CLSID_WICTiffDecoder;
1080 return S_OK;
1083 struct tiff_encode_format {
1084 const WICPixelFormatGUID *guid;
1085 int photometric;
1086 int bps;
1087 int samples;
1088 int bpp;
1089 int extra_sample;
1090 int extra_sample_type;
1091 int reverse_bgr;
1092 int indexed;
1095 static const struct tiff_encode_format formats[] = {
1096 {&GUID_WICPixelFormat24bppBGR, 2, 8, 3, 24, 0, 0, 1},
1097 {&GUID_WICPixelFormat24bppRGB, 2, 8, 3, 24, 0, 0, 0},
1098 {&GUID_WICPixelFormatBlackWhite, 1, 1, 1, 1, 0, 0, 0},
1099 {&GUID_WICPixelFormat4bppGray, 1, 4, 1, 4, 0, 0, 0},
1100 {&GUID_WICPixelFormat8bppGray, 1, 8, 1, 8, 0, 0, 0},
1101 {&GUID_WICPixelFormat32bppBGRA, 2, 8, 4, 32, 1, 2, 1},
1102 {&GUID_WICPixelFormat32bppPBGRA, 2, 8, 4, 32, 1, 1, 1},
1103 {&GUID_WICPixelFormat48bppRGB, 2, 16, 3, 48, 0, 0, 0},
1104 {&GUID_WICPixelFormat64bppRGBA, 2, 16, 4, 64, 1, 2, 0},
1105 {&GUID_WICPixelFormat64bppPRGBA, 2, 16, 4, 64, 1, 1, 0},
1106 {&GUID_WICPixelFormat1bppIndexed, 3, 1, 1, 1, 0, 0, 0, 1},
1107 {&GUID_WICPixelFormat4bppIndexed, 3, 4, 1, 4, 0, 0, 0, 1},
1108 {&GUID_WICPixelFormat8bppIndexed, 3, 8, 1, 8, 0, 0, 0, 1},
1112 typedef struct tiff_encoder {
1113 struct encoder encoder;
1114 TIFF *tiff;
1115 const struct tiff_encode_format *format;
1116 struct encoder_frame encoder_frame;
1117 DWORD num_frames;
1118 DWORD lines_written;
1119 } tiff_encoder;
1121 static inline struct tiff_encoder *impl_from_encoder(struct encoder* iface)
1123 return CONTAINING_RECORD(iface, struct tiff_encoder, encoder);
1126 static HRESULT CDECL tiff_encoder_initialize(struct encoder* iface, IStream *stream)
1128 struct tiff_encoder* This = impl_from_encoder(iface);
1129 TIFF *tiff;
1131 tiff = tiff_open_stream(stream, "w");
1133 if (!tiff)
1134 return E_FAIL;
1136 This->tiff = tiff;
1138 return S_OK;
1141 static HRESULT CDECL tiff_encoder_get_supported_format(struct encoder *iface,
1142 GUID *pixel_format, DWORD *bpp, BOOL *indexed)
1144 int i;
1146 if (IsEqualGUID(pixel_format, &GUID_WICPixelFormat2bppIndexed))
1147 *pixel_format = GUID_WICPixelFormat4bppIndexed;
1149 for (i=0; formats[i].guid; i++)
1151 if (IsEqualGUID(formats[i].guid, pixel_format))
1152 break;
1155 if (!formats[i].guid) i = 0;
1157 *pixel_format = *formats[i].guid;
1158 *bpp = formats[i].bpp;
1159 *indexed = formats[i].indexed;
1161 return S_OK;
1164 static HRESULT CDECL tiff_encoder_create_frame(struct encoder* iface, const struct encoder_frame *frame)
1166 struct tiff_encoder* This = impl_from_encoder(iface);
1167 int i;
1169 if (This->num_frames != 0)
1170 TIFFWriteDirectory(This->tiff);
1172 This->num_frames++;
1173 This->lines_written = 0;
1174 This->encoder_frame = *frame;
1176 for (i=0; formats[i].guid; i++)
1178 if (IsEqualGUID(formats[i].guid, &frame->pixel_format))
1179 break;
1182 This->format = &formats[i];
1184 TIFFSetField(This->tiff, TIFFTAG_PHOTOMETRIC, (uint16_t)This->format->photometric);
1185 TIFFSetField(This->tiff, TIFFTAG_PLANARCONFIG, (uint16_t)1);
1186 TIFFSetField(This->tiff, TIFFTAG_BITSPERSAMPLE, (uint16_t)This->format->bps);
1187 TIFFSetField(This->tiff, TIFFTAG_SAMPLESPERPIXEL, (uint16_t)This->format->samples);
1189 if (This->format->extra_sample)
1191 uint16_t extra_samples;
1192 extra_samples = This->format->extra_sample_type;
1194 TIFFSetField(This->tiff, TIFFTAG_EXTRASAMPLES, (uint16_t)1, &extra_samples);
1197 TIFFSetField(This->tiff, TIFFTAG_IMAGEWIDTH, (uint32_t)frame->width);
1198 TIFFSetField(This->tiff, TIFFTAG_IMAGELENGTH, (uint32_t)frame->height);
1200 if (frame->dpix != 0.0 && frame->dpiy != 0.0)
1202 TIFFSetField(This->tiff, TIFFTAG_RESOLUTIONUNIT, (uint16_t)2); /* Inch */
1203 TIFFSetField(This->tiff, TIFFTAG_XRESOLUTION, (float)frame->dpix);
1204 TIFFSetField(This->tiff, TIFFTAG_YRESOLUTION, (float)frame->dpiy);
1207 if (This->format->bpp <= 8 && frame->num_colors && This->format->indexed)
1209 uint16_t red[256], green[256], blue[256];
1210 UINT i;
1212 for (i = 0; i < frame->num_colors; i++)
1214 red[i] = (frame->palette[i] >> 8) & 0xff00;
1215 green[i] = frame->palette[i] & 0xff00;
1216 blue[i] = (frame->palette[i] << 8) & 0xff00;
1219 TIFFSetField(This->tiff, TIFFTAG_COLORMAP, red, green, blue);
1222 return S_OK;
1225 static HRESULT CDECL tiff_encoder_write_lines(struct encoder* iface,
1226 BYTE *data, DWORD line_count, DWORD stride)
1228 struct tiff_encoder* This = impl_from_encoder(iface);
1229 BYTE *row_data, *swapped_data = NULL;
1230 UINT i, j, line_size;
1232 line_size = ((This->encoder_frame.width * This->format->bpp)+7)/8;
1234 if (This->format->reverse_bgr)
1236 swapped_data = malloc(line_size);
1237 if (!swapped_data)
1238 return E_OUTOFMEMORY;
1241 for (i=0; i<line_count; i++)
1243 row_data = data + i * stride;
1245 if (This->format->reverse_bgr && This->format->bps == 8)
1247 memcpy(swapped_data, row_data, line_size);
1248 for (j=0; j<line_size; j += This->format->samples)
1250 BYTE temp;
1251 temp = swapped_data[j];
1252 swapped_data[j] = swapped_data[j+2];
1253 swapped_data[j+2] = temp;
1255 row_data = swapped_data;
1258 TIFFWriteScanline(This->tiff, (tdata_t)row_data, i+This->lines_written, 0);
1261 This->lines_written += line_count;
1263 return S_OK;
1266 static HRESULT CDECL tiff_encoder_commit_frame(struct encoder* iface)
1268 return S_OK;
1271 static HRESULT CDECL tiff_encoder_commit_file(struct encoder* iface)
1273 struct tiff_encoder* This = impl_from_encoder(iface);
1275 TIFFClose(This->tiff);
1276 This->tiff = NULL;
1278 return S_OK;
1281 static void CDECL tiff_encoder_destroy(struct encoder* iface)
1283 struct tiff_encoder *This = impl_from_encoder(iface);
1285 if (This->tiff) TIFFClose(This->tiff);
1286 RtlFreeHeap(GetProcessHeap(), 0, This);
1289 static const struct encoder_funcs tiff_encoder_vtable = {
1290 tiff_encoder_initialize,
1291 tiff_encoder_get_supported_format,
1292 tiff_encoder_create_frame,
1293 tiff_encoder_write_lines,
1294 tiff_encoder_commit_frame,
1295 tiff_encoder_commit_file,
1296 tiff_encoder_destroy
1299 HRESULT CDECL tiff_encoder_create(struct encoder_info *info, struct encoder **result)
1301 struct tiff_encoder *This;
1303 This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
1304 if (!This) return E_OUTOFMEMORY;
1306 This->encoder.vtable = &tiff_encoder_vtable;
1307 This->tiff = NULL;
1308 This->num_frames = 0;
1310 info->flags = ENCODER_FLAGS_MULTI_FRAME | ENCODER_FLAGS_SUPPORTS_METADATA;
1311 info->container_format = GUID_ContainerFormatTiff;
1312 info->clsid = CLSID_WICTiffEncoder;
1313 info->encoder_options[0] = ENCODER_OPTION_COMPRESSION_METHOD;
1314 info->encoder_options[1] = ENCODER_OPTION_COMPRESSION_QUALITY;
1315 info->encoder_options[2] = ENCODER_OPTION_END;
1317 *result = &This->encoder;
1319 return S_OK;