2 Copyright 2005-2007 Adobe Systems Incorporated
4 Use, modification and distribution are subject to the Boost Software License,
5 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt).
8 See http://opensource.adobe.com/gil for most recent version including documentation.
11 /*************************************************************************************************/
17 /// \brief Support for reading and writing TIFF files
19 /// \author Hailin Jin and Lubomir Bourdev \n
20 /// Adobe Systems Incorporated
21 /// \date 2005-2007 \n Last updated September 24, 2006
26 #include <boost/static_assert.hpp>
28 #include "../../gil_all.hpp"
29 #include "io_error.hpp"
31 namespace boost { namespace gil {
35 template <typename Channel,typename ColorSpace>
36 struct tiff_read_support_private {
37 BOOST_STATIC_CONSTANT(bool,is_supported=false);
38 BOOST_STATIC_CONSTANT(int,bit_depth=0);
39 BOOST_STATIC_CONSTANT(int,color_type=0);
42 struct tiff_read_support_private<bits8,gray_t> {
43 BOOST_STATIC_CONSTANT(bool,is_supported=true);
44 BOOST_STATIC_CONSTANT(int,bit_depth=8);
45 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK);
48 struct tiff_read_support_private<bits8,rgb_t> {
49 BOOST_STATIC_CONSTANT(bool,is_supported=true);
50 BOOST_STATIC_CONSTANT(int,bit_depth=8);
51 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB);
54 struct tiff_read_support_private<bits16,gray_t> {
55 BOOST_STATIC_CONSTANT(bool,is_supported=true);
56 BOOST_STATIC_CONSTANT(int,bit_depth=16);
57 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK);
60 struct tiff_read_support_private<bits16,rgb_t> {
61 BOOST_STATIC_CONSTANT(bool,is_supported=true);
62 BOOST_STATIC_CONSTANT(int,bit_depth=16);
63 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB);
66 struct tiff_read_support_private<bits32f,gray_t> {
67 BOOST_STATIC_CONSTANT(bool,is_supported=true);
68 BOOST_STATIC_CONSTANT(int,bit_depth=32);
69 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK);
72 struct tiff_read_support_private<bits32f,rgb_t> {
73 BOOST_STATIC_CONSTANT(bool,is_supported=true);
74 BOOST_STATIC_CONSTANT(int,bit_depth=32);
75 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB);
78 template <typename Channel,typename ColorSpace>
79 struct tiff_write_support_private {
80 BOOST_STATIC_CONSTANT(bool,is_supported=false);
81 BOOST_STATIC_CONSTANT(int,bit_depth=0);
82 BOOST_STATIC_CONSTANT(int,color_type=0);
85 struct tiff_write_support_private<bits8,gray_t> {
86 BOOST_STATIC_CONSTANT(bool,is_supported=true);
87 BOOST_STATIC_CONSTANT(int,bit_depth=8);
88 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK);
91 struct tiff_write_support_private<bits8,rgb_t> {
92 BOOST_STATIC_CONSTANT(bool,is_supported=true);
93 BOOST_STATIC_CONSTANT(int,bit_depth=8);
94 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB);
97 struct tiff_write_support_private<bits16,gray_t> {
98 BOOST_STATIC_CONSTANT(bool,is_supported=true);
99 BOOST_STATIC_CONSTANT(int,bit_depth=16);
100 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK);
103 struct tiff_write_support_private<bits16,rgb_t> {
104 BOOST_STATIC_CONSTANT(bool,is_supported=true);
105 BOOST_STATIC_CONSTANT(int,bit_depth=16);
106 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB);
109 struct tiff_write_support_private<bits32f,gray_t> {
110 BOOST_STATIC_CONSTANT(bool,is_supported=true);
111 BOOST_STATIC_CONSTANT(int,bit_depth=32);
112 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_MINISBLACK);
115 struct tiff_write_support_private<bits32f,rgb_t> {
116 BOOST_STATIC_CONSTANT(bool,is_supported=true);
117 BOOST_STATIC_CONSTANT(int,bit_depth=32);
118 BOOST_STATIC_CONSTANT(int,color_type=PHOTOMETRIC_RGB);
125 tiff_reader(const char* filename,tdir_t dirnum=0) {
126 io_error_if((_tp=TIFFOpen(filename,"r"))==NULL,
127 "tiff_reader: fail to open file");
129 io_error_if(TIFFSetDirectory(_tp,dirnum)!=1,
130 "tiff_reader: fail to set directory");
133 ~tiff_reader() { TIFFClose(_tp); }
134 template <typename View>
135 void apply(const View& view) {
136 unsigned short bps,photometric;
137 point2<std::ptrdiff_t> dims=get_dimensions();
138 io_error_if(TIFFGetField(_tp,TIFFTAG_BITSPERSAMPLE,&bps)!=1);
139 io_error_if(TIFFGetField(_tp,TIFFTAG_PHOTOMETRIC,&photometric)!=1);
140 io_error_if(dims!=view.dimensions(),
141 "tiff_read_view: input view size does not match TIFF file size");
142 io_error_if(tiff_read_support_private<typename channel_type<View>::type,
143 typename color_space_type<View>::type>::bit_depth!=bps ||
144 tiff_read_support_private<typename channel_type<View>::type,
145 typename color_space_type<View>::type>::color_type!=photometric,
146 "tiff_read_view: input view type is incompatible with the image type");
147 std::size_t element_size=sizeof(pixel<typename channel_type<View>::type,
148 layout<typename color_space_type<View>::type> >);
149 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
150 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
151 std::vector<pixel<typename channel_type<View>::type,
152 layout<typename color_space_type<View>::type> > > row(size_to_allocate);
153 for (int y=0;y<view.height();++y) {
154 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
155 std::copy(row.begin(),row.begin()+view.width(),view.row_begin(y));
158 point2<std::ptrdiff_t> get_dimensions() {
160 io_error_if(TIFFGetField(_tp,TIFFTAG_IMAGEWIDTH, &w)!=1);
161 io_error_if(TIFFGetField(_tp,TIFFTAG_IMAGELENGTH,&h)!=1);
162 return point2<std::ptrdiff_t>(w,h);
165 template <typename Image>
166 void read_image(Image& im) {
167 im.recreate(get_dimensions());
172 // This code will be simplified...
173 template <typename CC>
174 class tiff_reader_color_convert : public tiff_reader {
178 tiff_reader_color_convert(const char* filename,tdir_t dirnum=0) :
179 tiff_reader(filename,dirnum) {}
180 tiff_reader_color_convert(const char* filename,CC cc_in,tdir_t dirnum=0) :
181 tiff_reader(filename,dirnum),_cc(cc_in) {}
182 template <typename View>
183 void apply(const View& view) {
184 point2<std::ptrdiff_t> dims=get_dimensions();
185 unsigned short bps,photometric;
186 io_error_if(TIFFGetField(_tp,TIFFTAG_BITSPERSAMPLE,&bps)!=1);
187 io_error_if(TIFFGetField(_tp,TIFFTAG_PHOTOMETRIC,&photometric)!=1);
188 io_error_if(dims!=view.dimensions(),
189 "tiff_reader_color_convert::apply(): input view size does not match TIFF file size");
190 switch (photometric) {
191 case PHOTOMETRIC_MINISBLACK: {
194 std::size_t element_size=sizeof(gray8_pixel_t);
195 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
196 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
197 std::vector<gray8_pixel_t> row(size_to_allocate);
198 for (int y=0;y<view.height();++y) {
199 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
200 std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y),
201 color_convert_deref_fn<gray8_ref_t,typename View::value_type,CC>(_cc));
206 std::size_t element_size=sizeof(gray16_pixel_t);
207 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
208 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
209 std::vector<gray16_pixel_t> row(size_to_allocate);
210 for (int y=0;y<view.height();++y) {
211 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
212 std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y),
213 color_convert_deref_fn<gray16_ref_t,typename View::value_type,CC>(_cc));
218 std::size_t element_size=sizeof(gray32f_pixel_t);
219 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
220 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
221 std::vector<gray32f_pixel_t> row(size_to_allocate);
222 for (int y=0;y<view.height();++y) {
223 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
224 std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y),
225 color_convert_deref_fn<gray32f_ref_t,typename View::value_type,CC>(_cc));
230 io_error("tiff_reader_color_convert::apply(): unknown combination of color type and bit depth");
234 case PHOTOMETRIC_RGB: {
237 std::size_t element_size=sizeof(rgb8_pixel_t);
238 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
239 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
240 std::vector<rgb8_pixel_t> row(size_to_allocate);
241 for (int y=0;y<view.height();++y) {
242 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
243 std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y),
244 color_convert_deref_fn<rgb8_ref_t,typename View::value_type,CC>(_cc));
249 std::size_t element_size=sizeof(rgb16_pixel_t);
250 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
251 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
252 std::vector<rgb16_pixel_t> row(size_to_allocate);
253 for (int y=0;y<view.height();++y) {
254 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
255 std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y),
256 color_convert_deref_fn<rgb16_ref_t,typename View::value_type,CC>(_cc));
261 std::size_t element_size=sizeof(rgb32f_pixel_t);
262 std::size_t size_to_allocate = (std::max)((std::size_t)view.width(),
263 (std::size_t)(TIFFScanlineSize(_tp)+element_size-1)/element_size);
264 std::vector<rgb32f_pixel_t> row(size_to_allocate);
265 for (int y=0;y<view.height();++y) {
266 io_error_if(TIFFReadScanline(_tp,&row.front(), y)!=1);
267 std::transform(row.begin(),row.begin()+view.width(),view.row_begin(y),
268 color_convert_deref_fn<rgb32f_ref_t,typename View::value_type,CC>(_cc));
273 io_error("tiff_reader_color_convert::apply(): unknown combination of color type and bit depth");
278 // reads an image in incompatible format via TIFFReadRGBAImage
279 rgba8_image_t rgbaImg(dims);
280 io_error_if(!TIFFReadRGBAImage(_tp, dims.x, dims.y, (uint32*)&gil::view(rgbaImg)(0,0), 0),
281 "tiff_reader_color_convert::unsupported image format");
282 copy_and_convert_pixels(flipped_up_down_view(const_view(rgbaImg)), view, _cc);
286 template <typename Image>
287 void read_image(Image& im) {
288 im.recreate(get_dimensions());
297 tiff_writer(const char *filename) {
298 io_error_if((_tp=TIFFOpen(filename,"w"))==NULL,
299 "tiff_writer: fail to open file");
301 ~tiff_writer() {TIFFClose(_tp);}
302 template <typename View>
303 void apply(const View& view) {
304 io_error_if(TIFFSetField(_tp,TIFFTAG_IMAGELENGTH, view.height())!=1);
305 io_error_if(TIFFSetField(_tp,TIFFTAG_IMAGEWIDTH, view.width())!=1);
306 io_error_if(TIFFSetField(_tp,TIFFTAG_PHOTOMETRIC, tiff_write_support_private<typename channel_type<View>::type,
307 typename color_space_type<View>::type>::color_type)!=1);
308 io_error_if(TIFFSetField(_tp,TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE)!=1);
309 io_error_if(TIFFSetField(_tp,TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)!=1);
310 io_error_if(TIFFSetField(_tp,TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)!=1);
311 io_error_if(TIFFSetField(_tp,TIFFTAG_SAMPLESPERPIXEL,num_channels<View>::value)!=1);
312 io_error_if(TIFFSetField(_tp,TIFFTAG_BITSPERSAMPLE, tiff_write_support_private<typename channel_type<View>::type,
313 typename color_space_type<View>::type>::bit_depth)!=1);
314 io_error_if(TIFFSetField(_tp,TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(_tp, 0))!=1);
315 std::vector<pixel<typename channel_type<View>::type,
316 layout<typename color_space_type<View>::type> > > row(view.width());
317 for (int y=0;y<view.height();++y) {
318 std::copy(view.row_begin(y),view.row_end(y),row.begin());
319 io_error_if(TIFFWriteScanline(_tp,&row.front(),y,0)!=1,
320 "tiff_write_view: fail to write file");
325 } // namespace detail
328 /// \brief Determines whether the given view type is supported for reading
329 template <typename View>
330 struct tiff_read_support {
331 BOOST_STATIC_CONSTANT(bool,is_supported=
332 (detail::tiff_read_support_private<typename channel_type<View>::type,
333 typename color_space_type<View>::type>::is_supported));
334 BOOST_STATIC_CONSTANT(int,bit_depth=
335 (detail::tiff_read_support_private<typename channel_type<View>::type,
336 typename color_space_type<View>::type>::bit_depth));
337 BOOST_STATIC_CONSTANT(int,color_type=
338 (detail::tiff_read_support_private<typename channel_type<View>::type,
339 typename color_space_type<View>::type>::color_type));
343 /// \brief Returns the number of directories in the TIFF file
344 inline int tiff_get_directory_count(const char* filename) {
346 io_error_if((tif=TIFFOpen(filename,"r"))==NULL,
347 "tiff_get_count: fail to open file");
352 } while (TIFFReadDirectory(tif));
359 /// \brief Returns the width and height of the TIFF file at the specified location.
360 /// Throws std::ios_base::failure if the location does not correspond to a valid TIFF file
361 inline point2<std::ptrdiff_t> tiff_read_dimensions(const char* filename,tdir_t dirnum=0) {
362 detail::tiff_reader m(filename,dirnum);
363 return m.get_dimensions();
367 /// \brief Returns the width and height of the TIFF file at the specified location.
368 /// Throws std::ios_base::failure if the location does not correspond to a valid TIFF file
369 inline point2<std::ptrdiff_t> tiff_read_dimensions(const std::string& filename,tdir_t dirnum=0) {
370 return tiff_read_dimensions(filename.c_str(),dirnum);
374 /// \brief Loads the image specified by the given tiff image file name into the given view.
375 /// Triggers a compile assert if the view color space and channel depth are not supported by the TIFF library or by the I/O extension.
376 /// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its color space or channel depth are not
377 /// compatible with the ones specified by View, or if its dimensions don't match the ones of the view.
378 template <typename View>
379 inline void tiff_read_view(const char* filename,const View& view,tdir_t dirnum=0) {
380 BOOST_STATIC_ASSERT(tiff_read_support<View>::is_supported);
381 detail::tiff_reader m(filename,dirnum);
386 /// \brief Loads the image specified by the given tiff image file name into the given view.
387 template <typename View>
388 inline void tiff_read_view(const std::string& filename,const View& view,tdir_t dirnum=0) {
389 tiff_read_view(filename.c_str(),view,dirnum);
393 /// \brief Allocates a new image whose dimensions are determined by the given tiff image file, and loads the pixels into it.
394 /// Triggers a compile assert if the image color space or channel depth are not supported by the TIFF library or by the I/O extension.
395 /// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its color space or channel depth are not
396 /// compatible with the ones specified by Image
397 template <typename Image>
398 void tiff_read_image(const char* filename,Image& im,tdir_t dirnum=0) {
399 BOOST_STATIC_ASSERT(tiff_read_support<typename Image::view_t>::is_supported);
400 detail::tiff_reader m(filename,dirnum);
405 /// \brief Allocates a new image whose dimensions are determined by the given tiff image file, and loads the pixels into it.
406 template <typename Image>
407 inline void tiff_read_image(const std::string& filename,Image& im,tdir_t dirnum=0) {
408 tiff_read_image(filename.c_str(),im,dirnum);
412 /// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
413 /// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its dimensions don't match the ones of the view.
414 template <typename View,typename CC>
415 inline void tiff_read_and_convert_view(const char* filename,const View& view,CC cc,tdir_t dirnum=0) {
416 detail::tiff_reader_color_convert<CC> m(filename,cc,dirnum);
421 /// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
422 /// Throws std::ios_base::failure if the file is not a valid TIFF file, or if its dimensions don't match the ones of the view.
423 template <typename View>
424 inline void tiff_read_and_convert_view(const char* filename,const View& view,tdir_t dirnum=0) {
425 detail::tiff_reader_color_convert<default_color_converter> m(filename,default_color_converter(),dirnum);
430 /// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
431 template <typename View,typename CC>
432 inline void tiff_read_and_convert_view(const std::string& filename,const View& view,CC cc,tdir_t dirnum=0) {
433 tiff_read_and_convert_view(filename.c_str(),view,cc,dirnum);
437 /// \brief Loads and color-converts the image specified by the given tiff image file name into the given view.
438 template <typename View>
439 inline void tiff_read_and_convert_view(const std::string& filename,const View& view,tdir_t dirnum=0) {
440 tiff_read_and_convert_view(filename.c_str(),view,dirnum);
444 /// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
445 /// Throws std::ios_base::failure if the file is not a valid TIFF file
446 template <typename Image,typename CC>
447 void tiff_read_and_convert_image(const char* filename,Image& im,CC cc,tdir_t dirnum=0) {
448 detail::tiff_reader_color_convert<CC> m(filename,cc,dirnum);
453 /// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
454 /// Throws std::ios_base::failure if the file is not a valid TIFF file
455 template <typename Image>
456 void tiff_read_and_convert_image(const char* filename,Image& im,tdir_t dirnum=0) {
457 detail::tiff_reader_color_convert<default_color_converter> m(filename,default_color_converter(),dirnum);
462 /// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
463 template <typename Image,typename CC>
464 inline void tiff_read_and_convert_image(const std::string& filename,Image& im,CC cc,tdir_t dirnum=0) {
465 tiff_read_and_convert_image(filename.c_str(),im,cc,dirnum);
469 /// \brief Allocates a new image whose dimensions are determined by the given tiff image file, loads and color-converts the pixels into it.
470 template <typename Image>
471 inline void tiff_read_and_convert_image(const std::string& filename,Image& im,tdir_t dirnum=0) {
472 tiff_read_and_convert_image(filename.c_str(),im,dirnum);
476 /// \brief Determines whether the given view type is supported for writing
477 template <typename View>
478 struct tiff_write_support {
479 BOOST_STATIC_CONSTANT(bool,is_supported=
480 (detail::tiff_write_support_private<typename channel_type<View>::type,
481 typename color_space_type<View>::type>::is_supported));
482 BOOST_STATIC_CONSTANT(int,bit_depth=
483 (detail::tiff_write_support_private<typename channel_type<View>::type,
484 typename color_space_type<View>::type>::bit_depth));
485 BOOST_STATIC_CONSTANT(int,color_type=
486 (detail::tiff_write_support_private<typename channel_type<View>::type,
487 typename color_space_type<View>::type>::color_type));
488 BOOST_STATIC_CONSTANT(bool, value=is_supported);
492 /// \brief Saves the view to a tiff file specified by the given tiff image file name.
493 /// Triggers a compile assert if the view color space and channel depth are not supported by the TIFF library or by the I/O extension.
494 /// Throws std::ios_base::failure if it fails to create the file.
495 template <typename View>
496 inline void tiff_write_view(const char* filename,const View& view) {
497 BOOST_STATIC_ASSERT(tiff_write_support<View>::is_supported);
498 detail::tiff_writer m(filename);
503 /// \brief Saves the view to a tiff file specified by the given tiff image file name.
504 template <typename View>
505 inline void tiff_write_view(const std::string& filename,const View& view) {
506 tiff_write_view(filename.c_str(),view);
509 } } // namespace boost::gil