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
22 #include <sys/types.h>
26 #define WIN32_NO_STATUS
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
;
44 hr
= stream_read(stream
, data
, size
, &bytes_read
);
45 if (FAILED(hr
)) bytes_read
= 0;
49 static tsize_t
tiff_stream_write(thandle_t client_data
, tdata_t data
, tsize_t size
)
51 IStream
*stream
= (IStream
*)client_data
;
55 hr
= stream_write(stream
, data
, size
, &bytes_written
);
56 if (FAILED(hr
)) bytes_written
= 0;
60 static toff_t
tiff_stream_seek(thandle_t client_data
, toff_t offset
, int whence
)
62 IStream
*stream
= (IStream
*)client_data
;
64 ULONGLONG new_position
;
70 origin
= STREAM_SEEK_SET
;
73 origin
= STREAM_SEEK_CUR
;
76 origin
= STREAM_SEEK_END
;
79 ERR("unknown whence value %i\n", whence
);
83 hr
= stream_seek(stream
, offset
, origin
, &new_position
);
84 if (SUCCEEDED(hr
)) return new_position
;
88 static int tiff_stream_close(thandle_t client_data
)
90 /* Caller is responsible for releasing the stream object. */
94 static toff_t
tiff_stream_size(thandle_t client_data
)
96 IStream
*stream
= (IStream
*)client_data
;
100 hr
= stream_getsize(stream
, &size
);
102 if (SUCCEEDED(hr
)) return size
;
106 static int tiff_stream_map(thandle_t client_data
, tdata_t
*addr
, toff_t
*size
)
108 /* Cannot mmap streams */
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
);
127 struct decoder_frame frame
;
134 int invert_grayscale
;
135 UINT tile_width
, tile_height
;
144 struct decoder decoder
;
149 tiff_decode_info cached_decode_info
;
150 INT cached_tile_x
, cached_tile_y
;
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;
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
);
179 WARN("missing PhotometricInterpretation tag\n");
183 ret
= TIFFGetField(tiff
, TIFFTAG_BITSPERSAMPLE
, &bps
);
185 decode_info
->bps
= bps
;
187 ret
= TIFFGetField(tiff
, TIFFTAG_SAMPLESPERPIXEL
, &samples
);
188 if (!ret
) samples
= 1;
189 decode_info
->samples
= samples
;
195 ret
= TIFFGetField(tiff
, TIFFTAG_PLANARCONFIG
, &planar
);
196 if (!ret
) planar
= 1;
199 FIXME("unhandled planar configuration %u\n", planar
);
203 decode_info
->planar
= planar
;
205 TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar
, photometric
, samples
, bps
);
209 case 0: /* WhiteIsZero */
210 decode_info
->invert_grayscale
= 1;
212 case 1: /* BlackIsZero */
215 ret
= TIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
218 extra_sample_count
= 1;
220 extra_samples
= &extra_sample
;
223 else if (samples
!= 1)
225 FIXME("unhandled %dbpp sample count %u\n", bps
, samples
);
229 decode_info
->frame
.bpp
= bps
* samples
;
230 decode_info
->source_bpp
= decode_info
->frame
.bpp
;
236 FIXME("unhandled 1bpp sample count %u\n", samples
);
239 decode_info
->frame
.pixel_format
= GUID_WICPixelFormatBlackWhite
;
244 FIXME("unhandled 4bpp grayscale sample count %u\n", samples
);
247 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat4bppGray
;
251 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat8bppGray
;
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
;
261 case 0: /* Unspecified data */
262 case 2: /* Unassociated alpha data */
263 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat32bppBGRA
;
266 FIXME("unhandled extra sample type %u\n", extra_samples
[0]);
274 FIXME("unhandled 16bpp grayscale sample count %u\n", samples
);
275 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
277 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat16bppGray
;
282 FIXME("unhandled 32bpp grayscale sample count %u\n", samples
);
283 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
285 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat32bppGrayFloat
;
288 WARN("unhandled greyscale bit count %u\n", bps
);
289 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
295 ret
= TIFFGetField(tiff
, TIFFTAG_EXTRASAMPLES
, &extra_sample_count
, &extra_samples
);
298 extra_sample_count
= 1;
300 extra_samples
= &extra_sample
;
303 else if (samples
!= 3)
305 FIXME("unhandled RGB sample count %u\n", samples
);
309 decode_info
->frame
.bpp
= max(bps
, 8) * samples
;
310 decode_info
->source_bpp
= bps
* samples
;
316 decode_info
->reverse_bgr
= 1;
318 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat24bppBGR
;
320 switch(extra_samples
[0])
322 case 1: /* Associated (pre-multiplied) alpha data */
323 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat32bppPBGRA
;
325 case 0: /* Unspecified data */
326 case 2: /* Unassociated alpha data */
327 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat32bppBGRA
;
330 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
336 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat48bppRGB
;
338 switch(extra_samples
[0])
340 case 1: /* Associated (pre-multiplied) alpha data */
341 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat64bppPRGBA
;
343 case 0: /* Unspecified data */
344 case 2: /* Unassociated alpha data */
345 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat64bppRGBA
;
348 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
354 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat96bppRGBFloat
;
356 switch(extra_samples
[0])
358 case 1: /* Associated (pre-multiplied) alpha data */
359 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat128bppPRGBAFloat
;
361 case 0: /* Unspecified data */
362 case 2: /* Unassociated alpha data */
363 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat128bppRGBAFloat
;
366 FIXME("unhandled extra sample type %i\n", extra_samples
[0]);
371 WARN("unhandled RGB bit count %u\n", bps
);
372 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
375 case 3: /* RGB Palette */
378 FIXME("unhandled indexed sample count %u\n", samples
);
382 decode_info
->indexed
= 1;
383 decode_info
->frame
.bpp
= bps
;
387 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat1bppIndexed
;
390 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat2bppIndexed
;
393 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat4bppIndexed
;
396 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat8bppIndexed
;
399 FIXME("unhandled indexed bit count %u\n", bps
);
404 case 5: /* Separated */
407 FIXME("unhandled Separated sample count %u\n", samples
);
411 decode_info
->frame
.bpp
= bps
* samples
;
415 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat32bppCMYK
;
418 decode_info
->frame
.pixel_format
= GUID_WICPixelFormat64bppCMYK
;
422 WARN("unhandled Separated bit count %u\n", bps
);
423 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
427 case 4: /* Transparency mask */
431 FIXME("unhandled PhotometricInterpretation %u\n", photometric
);
435 ret
= TIFFGetField(tiff
, TIFFTAG_IMAGEWIDTH
, &decode_info
->frame
.width
);
438 WARN("missing image width\n");
442 ret
= TIFFGetField(tiff
, TIFFTAG_IMAGELENGTH
, &decode_info
->frame
.height
);
445 WARN("missing image length\n");
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
);
456 WARN("missing tile height\n");
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
;
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
;
482 TIFFGetField(tiff
, TIFFTAG_RESOLUTIONUNIT
, &resolution_unit
);
484 ret
= TIFFGetField(tiff
, TIFFTAG_XRESOLUTION
, &xres
);
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. */
496 ret
= TIFFGetField(tiff
, TIFFTAG_YRESOLUTION
, &yres
);
499 WARN("missing Y resolution\n");
506 if (xres
== 0.0 || yres
== 0.0)
508 decode_info
->frame
.dpix
= decode_info
->frame
.dpiy
= 96.0;
512 switch (resolution_unit
)
515 FIXME("unknown resolution unit %i\n", resolution_unit
);
517 case 0: /* Not set */
518 case 1: /* Relative measurements */
520 decode_info
->frame
.dpix
= xres
;
521 decode_info
->frame
.dpiy
= yres
;
523 case 3: /* Centimeter */
524 decode_info
->frame
.dpix
= xres
* 2.54;
525 decode_info
->frame
.dpiy
= yres
* 2.54;
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);
544 decode_info
->frame
.num_colors
= 0;
547 if (TIFFGetField(tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
548 decode_info
->frame
.num_color_contexts
= 1;
550 decode_info
->frame
.num_color_contexts
= 0;
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
);
560 This
->tiff
= tiff_open_stream(stream
, "r");
564 This
->frame_count
= TIFFNumberOfDirectories(This
->tiff
);
565 This
->cached_frame
= 0;
566 hr
= tiff_get_decode_info(This
->tiff
, &This
->cached_decode_info
);
570 st
->frame_count
= This
->frame_count
;
571 st
->flags
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
572 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
573 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
577 TIFFClose(This
->tiff
);
582 static HRESULT
tiff_decoder_select_frame(struct tiff_decoder
* This
, DWORD frame
)
588 if (frame
>= This
->frame_count
)
591 if (This
->cached_frame
== frame
)
594 prev_tile_size
= This
->cached_tile
? This
->cached_decode_info
.tile_size
: 0;
596 res
= TIFFSetDirectory(This
->tiff
, frame
);
600 hr
= tiff_get_decode_info(This
->tiff
, &This
->cached_decode_info
);
602 This
->cached_tile_x
= -1;
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
;
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
;
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
);
629 hr
= tiff_decoder_select_frame(This
, frame
);
632 *info
= This
->cached_decode_info
.frame
;
638 static HRESULT
tiff_decoder_read_tile(struct tiff_decoder
*This
, UINT tile_x
, UINT tile_y
)
642 tiff_decode_info
*info
= &This
->cached_decode_info
;
644 swap_bytes
= TIFFIsByteSwapped(This
->tiff
);
647 ret
= TIFFReadEncodedTile(This
->tiff
, tile_x
+ tile_y
* info
->tiles_across
, This
->cached_tile
, info
->tile_size
);
649 ret
= TIFFReadEncodedStrip(This
->tiff
, tile_y
, This
->cached_tile
, info
->tile_size
);
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 */
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 */
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 */
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 */
829 /* 8bpp grayscale with extra alpha */
830 else if (info
->source_bpp
== 16 && info
->samples
== 2 && info
->frame
.bpp
== 32)
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);
840 *dst
-- = src
[0] | (src
[0] << 8) | (src
[0] << 16) | (src
[1] << 24);
845 if (info
->reverse_bgr
)
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
;
861 samples_per_row
= info
->tile_width
* info
->samples
;
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
++)
872 sample
[1] = sample
[0];
879 ERR("unhandled bps for byte swap %u\n", info
->bps
);
884 if (info
->invert_grayscale
)
888 if (info
->samples
!= 1)
890 ERR("cannot invert grayscale image with %u samples\n", info
->samples
);
894 end
= This
->cached_tile
+info
->tile_size
;
896 for (byte
= This
->cached_tile
; byte
!= end
; byte
++)
900 This
->cached_tile_x
= tile_x
;
901 This
->cached_tile_y
= tile_y
;
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
);
911 UINT min_tile_x
, max_tile_x
, min_tile_y
, max_tile_y
;
915 tiff_decode_info
*info
= &This
->cached_decode_info
;
917 hr
= tiff_decoder_select_frame(This
, frame
);
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
);
944 if (prc
->X
< tile_x
* info
->tile_width
)
947 rc
.X
= prc
->X
- tile_x
* info
->tile_width
;
949 if (prc
->Y
< tile_y
* info
->tile_height
)
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
;
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
;
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
);
978 TRACE("<-- 0x%lx\n", hr
);
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
);
995 hr
= tiff_decoder_select_frame(This
, frame
);
999 if (!TIFFGetField(This
->tiff
, TIFFTAG_ICCPROFILE
, &len
, &profile
))
1001 return E_UNEXPECTED
;
1005 *data
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
1007 return E_OUTOFMEMORY
;
1009 memcpy(*data
, profile
, len
);
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
);
1020 struct decoder_block result
;
1022 hr
= tiff_decoder_select_frame(This
, frame
);
1028 result
.offset
= TIFFCurrentDirOffset(This
->tiff
);
1031 byte_swapped
= TIFFIsByteSwapped(This
->tiff
);
1032 #ifdef WORDS_BIGENDIAN
1033 result
.options
= byte_swapped
? WICPersistOptionLittleEndian
: WICPersistOptionBigEndian
;
1035 result
.options
= byte_swapped
? WICPersistOptionBigEndian
: WICPersistOptionLittleEndian
;
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
));
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
;
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
;
1083 struct tiff_encode_format
{
1084 const WICPixelFormatGUID
*guid
;
1090 int extra_sample_type
;
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
;
1115 const struct tiff_encode_format
*format
;
1116 struct encoder_frame encoder_frame
;
1118 DWORD lines_written
;
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
);
1131 tiff
= tiff_open_stream(stream
, "w");
1141 static HRESULT CDECL
tiff_encoder_get_supported_format(struct encoder
*iface
,
1142 GUID
*pixel_format
, DWORD
*bpp
, BOOL
*indexed
)
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
))
1155 if (!formats
[i
].guid
) i
= 0;
1157 *pixel_format
= *formats
[i
].guid
;
1158 *bpp
= formats
[i
].bpp
;
1159 *indexed
= formats
[i
].indexed
;
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
);
1169 if (This
->num_frames
!= 0)
1170 TIFFWriteDirectory(This
->tiff
);
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
))
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];
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
);
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
);
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
)
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
;
1266 static HRESULT CDECL
tiff_encoder_commit_frame(struct encoder
* iface
)
1271 static HRESULT CDECL
tiff_encoder_commit_file(struct encoder
* iface
)
1273 struct tiff_encoder
* This
= impl_from_encoder(iface
);
1275 TIFFClose(This
->tiff
);
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
;
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
;