File indexing completed on 2025-01-18 09:36:59
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
0009 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
0010
0011 #include <boost/gil/extension/io/tiff/tags.hpp>
0012 #include <boost/gil/extension/io/tiff/detail/log.hpp>
0013 #include <boost/gil/detail/mp11.hpp>
0014 #include <boost/gil/io/base.hpp>
0015 #include <boost/gil/io/device.hpp>
0016
0017 #include <algorithm>
0018 #include <cstdint>
0019 #include <memory>
0020 #include <sstream>
0021 #include <type_traits>
0022
0023
0024 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
0025 extern "C" {
0026 #endif
0027
0028 #include <tiff.h>
0029 #include <tiffio.h>
0030
0031 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
0032 }
0033 #endif
0034
0035 #include <tiffio.hxx>
0036
0037 namespace boost { namespace gil { namespace detail {
0038
0039 template <int n_args>
0040 struct get_property_f {
0041 template <typename Property>
0042 bool call_me(typename Property:: type& value, std::shared_ptr<TIFF>& file);
0043 };
0044
0045 template <int n_args>
0046 struct set_property_f {
0047 template <typename Property>
0048 bool call_me(const typename Property:: type& value, std::shared_ptr<TIFF>& file) const;
0049 };
0050
0051 template <> struct get_property_f <1>
0052 {
0053
0054 template <typename Property>
0055 bool call_me(typename Property::type & value, std::shared_ptr<TIFF>& file) const
0056 {
0057
0058 return (1 == TIFFGetFieldDefaulted( file.get()
0059 , Property:: tag
0060 , & value));
0061 }
0062 };
0063
0064 template <> struct get_property_f <2>
0065 {
0066
0067
0068 template <typename Property>
0069 bool call_me(typename Property::type& vs, std::shared_ptr<TIFF>& file) const
0070 {
0071 mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 0>> length;
0072 mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 1>> pointer;
0073 if (1 == TIFFGetFieldDefaulted(file.get(), Property:: tag, & length, & pointer))
0074 {
0075 std:: copy_n(static_cast<typename Property::type::const_pointer>(pointer), length, std:: back_inserter(vs));
0076 return true;
0077 } else
0078 return false;
0079 }
0080 };
0081
0082 template <> struct set_property_f <1>
0083 {
0084
0085 template <typename Property>
0086 inline
0087 bool call_me(typename Property:: type const & value, std::shared_ptr<TIFF>& file) const
0088 {
0089 return (1 == TIFFSetField( file.get()
0090 , Property:: tag
0091 , value));
0092 }
0093 };
0094
0095 template <> struct set_property_f <2>
0096 {
0097
0098
0099
0100
0101
0102
0103 template <typename Property>
0104 inline
0105 bool call_me(typename Property:: type const & values, std::shared_ptr<TIFF>& file) const
0106 {
0107 using length_t = mp11::mp_at_c<typename Property::arg_types, 0>;
0108 auto const length = static_cast<length_t>(values.size());
0109
0110 using pointer_t = mp11::mp_at_c<typename Property::arg_types, 1>;
0111 auto const pointer = static_cast<pointer_t>(&(values.front()));
0112 return (1 == TIFFSetField( file.get(), Property:: tag, length, pointer));
0113 }
0114 };
0115
0116 template< typename Log >
0117 class tiff_device_base
0118 {
0119 public:
0120 using tiff_file_t = std::shared_ptr<TIFF>;
0121
0122 tiff_device_base()
0123 {}
0124
0125 tiff_device_base( TIFF* tiff_file )
0126 : _tiff_file( tiff_file
0127 , TIFFClose )
0128 {}
0129
0130 template <typename Property>
0131 bool get_property( typename Property::type& value )
0132 {
0133 return get_property_f<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
0134 }
0135
0136 template <typename Property>
0137 inline
0138 bool set_property( const typename Property::type& value )
0139 {
0140
0141 return set_property_f<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
0142 }
0143
0144
0145
0146
0147
0148 bool are_bytes_swapped()
0149 {
0150 return ( TIFFIsByteSwapped( _tiff_file.get() )) ? true : false;
0151 }
0152
0153 bool is_tiled() const
0154 {
0155 return ( TIFFIsTiled( _tiff_file.get() )) ? true : false;
0156 }
0157
0158 unsigned int get_default_strip_size()
0159 {
0160 return TIFFDefaultStripSize( _tiff_file.get()
0161 , 0 );
0162 }
0163
0164 std::size_t get_scanline_size()
0165 {
0166 return TIFFScanlineSize( _tiff_file.get() );
0167 }
0168
0169 std::size_t get_tile_size()
0170 {
0171 return TIFFTileSize( _tiff_file.get() );
0172 }
0173
0174
0175 int get_field_defaulted( uint16_t*& red
0176 , uint16_t*& green
0177 , uint16_t*& blue
0178 )
0179 {
0180 return TIFFGetFieldDefaulted( _tiff_file.get()
0181 , TIFFTAG_COLORMAP
0182 , &red
0183 , &green
0184 , &blue
0185 );
0186 }
0187
0188 template< typename Buffer >
0189 void read_scanline( Buffer& buffer
0190 , std::ptrdiff_t row
0191 , tsample_t plane
0192 )
0193 {
0194 io_error_if( TIFFReadScanline( _tiff_file.get()
0195 , reinterpret_cast< tdata_t >( &buffer.front() )
0196 , static_cast<std::uint32_t>( row )
0197 , plane ) == -1
0198 , "Read error."
0199 );
0200 }
0201
0202 void read_scanline( byte_t* buffer
0203 , std::ptrdiff_t row
0204 , tsample_t plane
0205 )
0206 {
0207 io_error_if( TIFFReadScanline( _tiff_file.get()
0208 , reinterpret_cast< tdata_t >( buffer )
0209 , static_cast<std::uint32_t>( row )
0210 , plane ) == -1
0211 , "Read error."
0212 );
0213 }
0214
0215 template< typename Buffer >
0216 void read_tile( Buffer& buffer
0217 , std::ptrdiff_t x
0218 , std::ptrdiff_t y
0219 , std::ptrdiff_t z
0220 , tsample_t plane
0221 )
0222 {
0223 if( TIFFReadTile( _tiff_file.get()
0224 , reinterpret_cast< tdata_t >( &buffer.front() )
0225 , static_cast< std::uint32_t >( x )
0226 , static_cast< std::uint32_t >( y )
0227 , static_cast< std::uint32_t >( z )
0228 , plane
0229 ) == -1 )
0230 {
0231 std::ostringstream oss;
0232 oss << "Read tile error (" << x << "," << y << "," << z << "," << plane << ").";
0233 io_error(oss.str().c_str());
0234 }
0235 }
0236
0237 template< typename Buffer >
0238 void write_scaline( Buffer& buffer
0239 , std::uint32_t row
0240 , tsample_t plane
0241 )
0242 {
0243 io_error_if( TIFFWriteScanline( _tiff_file.get()
0244 , &buffer.front()
0245 , row
0246 , plane
0247 ) == -1
0248 , "Write error"
0249 );
0250 }
0251
0252 void write_scaline( byte_t* buffer
0253 , std::uint32_t row
0254 , tsample_t plane
0255 )
0256 {
0257 io_error_if( TIFFWriteScanline( _tiff_file.get()
0258 , buffer
0259 , row
0260 , plane
0261 ) == -1
0262 , "Write error"
0263 );
0264 }
0265
0266 template< typename Buffer >
0267 void write_tile( Buffer& buffer
0268 , std::uint32_t x
0269 , std::uint32_t y
0270 , std::uint32_t z
0271 , tsample_t plane
0272 )
0273 {
0274 if( TIFFWriteTile( _tiff_file.get()
0275 , &buffer.front()
0276 , x
0277 , y
0278 , z
0279 , plane
0280 ) == -1 )
0281 {
0282 std::ostringstream oss;
0283 oss << "Write tile error (" << x << "," << y << "," << z << "," << plane << ").";
0284 io_error(oss.str().c_str());
0285 }
0286 }
0287
0288 void set_directory( tdir_t directory )
0289 {
0290 io_error_if( TIFFSetDirectory( _tiff_file.get()
0291 , directory
0292 ) != 1
0293 , "Failing to set directory"
0294 );
0295 }
0296
0297
0298 bool check_tile_size( tiff_tile_width::type& width
0299 , tiff_tile_length::type& height
0300
0301 )
0302 {
0303 bool result = true;
0304 std::uint32_t tw = static_cast< std::uint32_t >( width );
0305 std::uint32_t th = static_cast< std::uint32_t >( height );
0306
0307 TIFFDefaultTileSize( _tiff_file.get()
0308 , &tw
0309 , &th
0310 );
0311
0312 if(width==0 || width%16!=0)
0313 {
0314 width = tw;
0315 result = false;
0316 }
0317 if(height==0 || height%16!=0)
0318 {
0319 height = th;
0320 result = false;
0321 }
0322 return result;
0323 }
0324
0325 protected:
0326
0327 tiff_file_t _tiff_file;
0328
0329 Log _log;
0330 };
0331
0332
0333
0334
0335
0336 template<>
0337 class file_stream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
0338 {
0339 public:
0340
0341 struct read_tag {};
0342 struct write_tag {};
0343
0344 file_stream_device( std::string const& file_name, read_tag )
0345 {
0346 TIFF* tiff;
0347
0348 io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "r" )) == nullptr
0349 , "file_stream_device: failed to open file" );
0350
0351 _tiff_file = tiff_file_t( tiff, TIFFClose );
0352 }
0353
0354 file_stream_device( std::string const& file_name, write_tag )
0355 {
0356 TIFF* tiff;
0357
0358 io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "w" )) == nullptr
0359 , "file_stream_device: failed to open file" );
0360
0361 _tiff_file = tiff_file_t( tiff, TIFFClose );
0362 }
0363
0364 file_stream_device( TIFF* tiff_file )
0365 : tiff_device_base( tiff_file )
0366 {}
0367 };
0368
0369
0370
0371
0372
0373 template<>
0374 class ostream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
0375 {
0376 public:
0377 ostream_device( std::ostream & out )
0378 : _out( out )
0379 {
0380 TIFF* tiff;
0381
0382 io_error_if( ( tiff = TIFFStreamOpen( ""
0383 , &_out
0384 )
0385 ) == nullptr
0386 , "ostream_device: failed to stream"
0387 );
0388
0389 _tiff_file = tiff_file_t( tiff, TIFFClose );
0390 }
0391
0392 private:
0393 ostream_device& operator=( const ostream_device& ) { return *this; }
0394
0395 private:
0396
0397 std::ostream& _out;
0398 };
0399
0400
0401
0402
0403
0404 template<>
0405 class istream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
0406 {
0407 public:
0408 istream_device( std::istream & in )
0409 : _in( in )
0410 {
0411 TIFF* tiff;
0412
0413 io_error_if( ( tiff = TIFFStreamOpen( ""
0414 , &_in
0415 )
0416 ) == nullptr
0417 , "istream_device: failed to stream"
0418 );
0419
0420 _tiff_file = tiff_file_t( tiff, TIFFClose );
0421 }
0422
0423 private:
0424 istream_device& operator=( const istream_device& ) { return *this; }
0425
0426 private:
0427
0428 std::istream& _in;
0429 };
0430
0431
0432
0433
0434
0435
0436 template<typename FormatTag>
0437 struct is_adaptable_input_device<FormatTag, TIFF*, void> : std::true_type
0438 {
0439 using device_type = file_stream_device<FormatTag>;
0440 };
0441
0442 template<typename FormatTag>
0443 struct is_adaptable_output_device<FormatTag, TIFF*, void> : std::true_type
0444 {
0445 using device_type = file_stream_device<FormatTag>;
0446 };
0447
0448
0449 template <typename Channel>
0450 struct sample_format : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
0451 template<>
0452 struct sample_format<uint8_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
0453 template<>
0454 struct sample_format<uint16_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
0455 template<>
0456 struct sample_format<uint32_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
0457 template<>
0458 struct sample_format<float32_t> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
0459 template<>
0460 struct sample_format<double> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
0461 template<>
0462 struct sample_format<int8_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
0463 template<>
0464 struct sample_format<int16_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
0465 template<>
0466 struct sample_format<int32_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
0467
0468 template <typename Channel>
0469 struct photometric_interpretation {};
0470 template<>
0471 struct photometric_interpretation<gray_t>
0472 : std::integral_constant<int, PHOTOMETRIC_MINISBLACK> {};
0473 template<>
0474 struct photometric_interpretation<rgb_t>
0475 : std::integral_constant<int, PHOTOMETRIC_RGB> {};
0476 template<>
0477 struct photometric_interpretation<rgba_t>
0478 : std::integral_constant<int, PHOTOMETRIC_RGB> {};
0479 template<>
0480 struct photometric_interpretation<cmyk_t>
0481 : std::integral_constant<int, PHOTOMETRIC_SEPARATED> {};
0482
0483 }
0484 }
0485 }
0486
0487 #endif