2 // Copyright 2007-2008 Andreas Pokorny, Christian Henning
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
9 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
11 #include <boost/gil/extension/io/tiff/tags.hpp>
12 #include <boost/gil/extension/io/tiff/detail/log.hpp>
13 #include <boost/gil/detail/mp11.hpp>
14 #include <boost/gil/io/base.hpp>
15 #include <boost/gil/io/device.hpp>
20 #include <type_traits>
22 // taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
23 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
30 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
36 namespace boost { namespace gil { namespace detail {
39 struct get_property_f {
40 template <typename Property>
41 bool call_me(typename Property:: type& value, std::shared_ptr<TIFF>& file);
45 struct set_property_f {
46 template <typename Property>
47 bool call_me(const typename Property:: type& value, std::shared_ptr<TIFF>& file) const;
50 template <> struct get_property_f <1>
52 // For single-valued properties
53 template <typename Property>
54 bool call_me(typename Property::type & value, std::shared_ptr<TIFF>& file) const
56 // @todo: defaulted, really?
57 return (1 == TIFFGetFieldDefaulted( file.get()
63 template <> struct get_property_f <2>
65 // Specialisation for multi-valued properties. @todo: add one of
66 // these for the three-parameter fields too.
67 template <typename Property>
68 bool call_me(typename Property::type& vs, std::shared_ptr<TIFF>& file) const
70 mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 0>> length;
71 mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 1>> pointer;
72 if (1 == TIFFGetFieldDefaulted(file.get(), Property:: tag, & length, & pointer))
74 std:: copy_n(static_cast<typename Property::type::const_pointer>(pointer), length, std:: back_inserter(vs));
81 template <> struct set_property_f <1>
83 // For single-valued properties
84 template <typename Property>
86 bool call_me(typename Property:: type const & value, std::shared_ptr<TIFF>& file) const
88 return (1 == TIFFSetField( file.get()
94 template <> struct set_property_f <2>
96 // Specialisation for multi-valued properties. @todo: add one
97 // of these for the three-parameter fields too. Actually we
98 // will need further templation / specialisation for the
99 // two-element fields which aren't a length and a data buffer
100 // (e.g. http://www.awaresystems.be/imaging/tiff/tifftags/dotrange.html
102 template <typename Property>
104 bool call_me(typename Property:: type const & values, std::shared_ptr<TIFF>& file) const
106 using length_t = mp11::mp_at_c<typename Property::arg_types, 0>;
107 auto const length = static_cast<length_t>(values.size());
109 using pointer_t = mp11::mp_at_c<typename Property::arg_types, 1>;
110 auto const pointer = static_cast<pointer_t>(&(values.front()));
111 return (1 == TIFFSetField( file.get(), Property:: tag, length, pointer));
115 template< typename Log >
116 class tiff_device_base
119 using tiff_file_t = std::shared_ptr<TIFF>;
124 tiff_device_base( TIFF* tiff_file )
125 : _tiff_file( tiff_file
129 template <typename Property>
130 bool get_property( typename Property::type& value )
132 return get_property_f<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
135 template <typename Property>
137 bool set_property( const typename Property::type& value )
139 // http://www.remotesensing.org/libtiff/man/TIFFSetField.3tiff.html
140 return set_property_f<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
143 // TIFFIsByteSwapped returns a non-zero value if the image data was in a different
144 // byte-order than the host machine. Zero is returned if the TIFF file and local
145 // host byte-orders are the same. Note that TIFFReadTile(), TIFFReadStrip() and TIFFReadScanline()
146 // functions already normally perform byte swapping to local host order if needed.
147 bool are_bytes_swapped()
149 return ( TIFFIsByteSwapped( _tiff_file.get() )) ? true : false;
152 bool is_tiled() const
154 return ( TIFFIsTiled( _tiff_file.get() )) ? true : false;
157 unsigned int get_default_strip_size()
159 return TIFFDefaultStripSize( _tiff_file.get()
163 std::size_t get_scanline_size()
165 return TIFFScanlineSize( _tiff_file.get() );
168 std::size_t get_tile_size()
170 return TIFFTileSize( _tiff_file.get() );
174 int get_field_defaulted( uint16_t*& red
179 return TIFFGetFieldDefaulted( _tiff_file.get()
187 template< typename Buffer >
188 void read_scanline( Buffer& buffer
193 io_error_if( TIFFReadScanline( _tiff_file.get()
194 , reinterpret_cast< tdata_t >( &buffer.front() )
201 void read_scanline( byte_t* buffer
206 io_error_if( TIFFReadScanline( _tiff_file.get()
207 , reinterpret_cast< tdata_t >( buffer )
214 template< typename Buffer >
215 void read_tile( Buffer& buffer
222 if( TIFFReadTile( _tiff_file.get()
223 , reinterpret_cast< tdata_t >( &buffer.front() )
230 std::ostringstream oss;
231 oss << "Read tile error (" << x << "," << y << "," << z << "," << plane << ").";
232 io_error(oss.str().c_str());
236 template< typename Buffer >
237 void write_scaline( Buffer& buffer
242 io_error_if( TIFFWriteScanline( _tiff_file.get()
251 void write_scaline( byte_t* buffer
256 io_error_if( TIFFWriteScanline( _tiff_file.get()
265 template< typename Buffer >
266 void write_tile( Buffer& buffer
273 if( TIFFWriteTile( _tiff_file.get()
281 std::ostringstream oss;
282 oss << "Write tile error (" << x << "," << y << "," << z << "," << plane << ").";
283 io_error(oss.str().c_str());
287 void set_directory( tdir_t directory )
289 io_error_if( TIFFSetDirectory( _tiff_file.get()
292 , "Failing to set directory"
296 // return false if the given tile width or height is not TIFF compliant (multiple of 16) or larger than image size, true otherwise
297 bool check_tile_size( tiff_tile_width::type& width
298 , tiff_tile_length::type& height
303 uint32 tw = static_cast< uint32 >( width );
304 uint32 th = static_cast< uint32 >( height );
306 TIFFDefaultTileSize( _tiff_file.get()
311 if(width==0 || width%16!=0)
316 if(height==0 || height%16!=0)
326 tiff_file_t _tiff_file;
333 * file_stream_device specialization for tiff images, which are based on TIFF*.
336 class file_stream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
343 file_stream_device( std::string const& file_name, read_tag )
347 io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "r" )) == nullptr
348 , "file_stream_device: failed to open file" );
350 _tiff_file = tiff_file_t( tiff, TIFFClose );
353 file_stream_device( std::string const& file_name, write_tag )
357 io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "w" )) == nullptr
358 , "file_stream_device: failed to open file" );
360 _tiff_file = tiff_file_t( tiff, TIFFClose );
363 file_stream_device( TIFF* tiff_file )
364 : tiff_device_base( tiff_file )
370 * ostream_device specialization for tiff images.
373 class ostream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
376 ostream_device( std::ostream & out )
381 io_error_if( ( tiff = TIFFStreamOpen( ""
385 , "ostream_device: failed to stream"
388 _tiff_file = tiff_file_t( tiff, TIFFClose );
392 ostream_device& operator=( const ostream_device& ) { return *this; }
401 * ostream_device specialization for tiff images.
404 class istream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
407 istream_device( std::istream & in )
412 io_error_if( ( tiff = TIFFStreamOpen( ""
416 , "istream_device: failed to stream"
419 _tiff_file = tiff_file_t( tiff, TIFFClose );
423 istream_device& operator=( const istream_device& ) { return *this; }
431 template< typename T, typename D >
432 struct is_adaptable_input_device< tiff_tag, T, D > : std::false_type {};
435 template<typename FormatTag>
436 struct is_adaptable_input_device<FormatTag, TIFF*, void> : std::true_type
438 using device_type = file_stream_device<FormatTag>;
441 template<typename FormatTag>
442 struct is_adaptable_output_device<FormatTag, TIFF*, void> : std::true_type
444 using device_type = file_stream_device<FormatTag>;
448 template <typename Channel>
449 struct sample_format : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
451 struct sample_format<uint8_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
453 struct sample_format<uint16_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
455 struct sample_format<uint32_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
457 struct sample_format<float32_t> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
459 struct sample_format<double> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
461 struct sample_format<int8_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
463 struct sample_format<int16_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
465 struct sample_format<int32_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
467 template <typename Channel>
468 struct photometric_interpretation {};
470 struct photometric_interpretation<gray_t>
471 : std::integral_constant<int, PHOTOMETRIC_MINISBLACK> {};
473 struct photometric_interpretation<rgb_t>
474 : std::integral_constant<int, PHOTOMETRIC_RGB> {};
476 struct photometric_interpretation<rgba_t>
477 : std::integral_constant<int, PHOTOMETRIC_RGB> {};
479 struct photometric_interpretation<cmyk_t>
480 : std::integral_constant<int, PHOTOMETRIC_SEPARATED> {};
482 } // namespace detail