File indexing completed on 2025-01-18 09:37:00
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
0009 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
0010
0011 #include <boost/gil/extension/io/tiff/tags.hpp>
0012 #include <boost/gil/extension/io/tiff/detail/writer_backend.hpp>
0013 #include <boost/gil/extension/io/tiff/detail/device.hpp>
0014
0015 #include <boost/gil/premultiply.hpp>
0016 #include <boost/gil/io/base.hpp>
0017 #include <boost/gil/io/device.hpp>
0018 #include <boost/gil/io/detail/dynamic.hpp>
0019
0020 #include <algorithm>
0021 #include <cstdint>
0022 #include <string>
0023 #include <type_traits>
0024 #include <vector>
0025
0026 extern "C" {
0027 #include "tiff.h"
0028 #include "tiffio.h"
0029 }
0030
0031 namespace boost { namespace gil {
0032
0033 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0034 #pragma warning(push)
0035 #pragma warning(disable:4512)
0036 #endif
0037
0038 namespace detail {
0039
0040 template <typename PixelReference>
0041 struct my_interleaved_pixel_iterator_type_from_pixel_reference
0042 {
0043 private:
0044 using pixel_t = typename std::remove_reference<PixelReference>::type::value_type;
0045
0046 public:
0047 using type = typename iterator_type_from_pixel
0048 <
0049 pixel_t,
0050 false,
0051 false,
0052 true
0053 >::type;
0054 };
0055
0056
0057 template< typename Channel
0058 , typename Layout
0059 , bool Mutable
0060 >
0061 struct my_interleaved_pixel_iterator_type_from_pixel_reference< const bit_aligned_pixel_reference< byte_t
0062 , Channel
0063 , Layout
0064 , Mutable
0065 >
0066 >
0067 : public iterator_type_from_pixel< const bit_aligned_pixel_reference< uint8_t
0068 , Channel
0069 , Layout
0070 , Mutable
0071 >
0072 ,false
0073 ,false
0074 ,true
0075 > {};
0076
0077 struct tiff_write_is_supported
0078 {
0079 template< typename View >
0080 struct apply
0081 : public is_write_supported< typename get_pixel_type< View >::type
0082 , tiff_tag
0083 >
0084 {};
0085 };
0086
0087 }
0088
0089
0090
0091
0092 template < typename Device, typename Log >
0093 class writer< Device
0094 , tiff_tag
0095 , Log
0096 >
0097 : public writer_backend< Device
0098 , tiff_tag
0099 >
0100 {
0101 private:
0102 using backend_t = writer_backend<Device, tiff_tag>;
0103
0104 public:
0105
0106 writer( const Device& io_dev
0107 , const image_write_info< tiff_tag >& info
0108 )
0109 : backend_t( io_dev
0110 , info
0111 )
0112 {}
0113
0114 template<typename View>
0115 void apply( const View& view )
0116 {
0117 write_view( view );
0118 }
0119
0120 private:
0121
0122 template< typename View >
0123 void write_view( const View& view )
0124 {
0125 using pixel_t = typename View::value_type;
0126
0127 using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
0128 tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
0129
0130 tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
0131
0132 this->write_header( view );
0133
0134 if( this->_info._is_tiled == false )
0135 {
0136 write_data( view
0137 , (view.width() * samples_per_pixel * bits_per_sample + 7) / 8
0138 , typename is_bit_aligned< pixel_t >::type()
0139 );
0140 }
0141 else
0142 {
0143 tiff_tile_width::type tw = this->_info._tile_width;
0144 tiff_tile_length::type th = this->_info._tile_length;
0145
0146 if(!this->_io_dev.check_tile_size( tw, th ))
0147 {
0148 io_error( "Tile sizes need to be multiples of 16." );
0149 }
0150
0151
0152 this->_io_dev.template set_property<tiff_tile_width> ( tw );
0153 this->_io_dev.template set_property<tiff_tile_length>( th );
0154
0155 write_tiled_data( view
0156 , tw
0157 , th
0158 , typename is_bit_aligned< pixel_t >::type()
0159 );
0160 }
0161 }
0162
0163
0164
0165 template<typename View>
0166 void write_bit_aligned_view_to_dev( const View& view
0167 , const std::size_t row_size_in_bytes
0168 , const std::true_type&
0169 )
0170 {
0171 byte_vector_t row( row_size_in_bytes );
0172
0173 using x_it_t = typename View::x_iterator;
0174 x_it_t row_it = x_it_t( &(*row.begin()));
0175
0176 auto pm_view = premultiply_view <typename View:: value_type> (view);
0177
0178 for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
0179 {
0180 std::copy( pm_view.row_begin( y )
0181 , pm_view.row_end( y )
0182 , row_it
0183 );
0184
0185
0186 this->_io_dev.write_scaline( row
0187 , static_cast<std::uint32_t>( y )
0188 , 0
0189 );
0190
0191
0192 }
0193 }
0194
0195 template<typename View>
0196 void write_bit_aligned_view_to_dev( const View& view
0197 , const std::size_t row_size_in_bytes
0198 , const std::false_type&
0199 )
0200 {
0201 byte_vector_t row( row_size_in_bytes );
0202
0203 using x_it_t = typename View::x_iterator;
0204 x_it_t row_it = x_it_t( &(*row.begin()));
0205
0206 for( typename View::y_coord_t y = 0; y < view.height(); ++y )
0207 {
0208 std::copy( view.row_begin( y )
0209 , view.row_end( y )
0210 , row_it
0211 );
0212
0213
0214 this->_io_dev.write_scaline( row
0215 , static_cast<std::uint32_t>( y )
0216 , 0
0217 );
0218
0219
0220 }
0221 }
0222
0223
0224
0225 template< typename View >
0226 void write_data( const View& view
0227 , std::size_t row_size_in_bytes
0228 , const std::true_type&
0229 )
0230 {
0231 using colour_space_t = typename color_space_type<typename View::value_type>::type;
0232 using has_alpha_t = mp11::mp_contains<colour_space_t, alpha_t>;
0233
0234 write_bit_aligned_view_to_dev(view, row_size_in_bytes, has_alpha_t());
0235 }
0236
0237 template< typename View>
0238 void write_tiled_data( const View& view
0239 , tiff_tile_width::type tw
0240 , tiff_tile_length::type th
0241 , const std::true_type&
0242 )
0243 {
0244 byte_vector_t row( this->_io_dev.get_tile_size() );
0245
0246 using x_it_t = typename View::x_iterator;
0247 x_it_t row_it = x_it_t( &(*row.begin()));
0248
0249 internal_write_tiled_data(view, tw, th, row, row_it);
0250 }
0251
0252 template< typename View >
0253 void write_data( const View& view
0254 , std::size_t
0255 , const std::false_type&
0256 )
0257 {
0258 std::vector< pixel< typename channel_type< View >::type
0259 , layout<typename color_space_type< View >::type >
0260 >
0261 > row( view.size() );
0262
0263 byte_t* row_addr = reinterpret_cast< byte_t* >( &row.front() );
0264
0265
0266
0267 auto pm_view = premultiply_view <typename View:: value_type> (view);
0268
0269 for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
0270 {
0271 std::copy( pm_view.row_begin( y )
0272 , pm_view.row_end( y )
0273 , row.begin()
0274 );
0275
0276 this->_io_dev.write_scaline( row_addr
0277 , static_cast<std::uint32_t>( y )
0278 , 0
0279 );
0280
0281
0282 }
0283 }
0284
0285 template< typename View >
0286 void write_tiled_data( const View& view
0287 , tiff_tile_width::type tw
0288 , tiff_tile_length::type th
0289 , const std::false_type&
0290 )
0291 {
0292 byte_vector_t row( this->_io_dev.get_tile_size() );
0293
0294 using x_iterator = typename detail::my_interleaved_pixel_iterator_type_from_pixel_reference<typename View::reference>::type;
0295 x_iterator row_it = x_iterator( &(*row.begin()));
0296
0297 internal_write_tiled_data(view, tw, th, row, row_it);
0298 }
0299
0300
0301
0302
0303 template< typename View
0304 , typename IteratorType
0305 >
0306 void write_tiled_view_to_dev( const View& view
0307 , IteratorType it
0308 , const std::true_type&
0309 )
0310 {
0311 auto pm_view = premultiply_view <typename View:: value_type>( view );
0312
0313 std::copy( pm_view.begin()
0314 , pm_view.end()
0315 , it
0316 );
0317 }
0318
0319
0320 template< typename View
0321 , typename IteratorType
0322 >
0323 void write_tiled_view_to_dev( const View& view
0324 , IteratorType it
0325 , const std::false_type&
0326 )
0327 {
0328 std::copy( view.begin()
0329 , view.end()
0330 , it
0331 );
0332 }
0333
0334
0335
0336
0337
0338 template< typename View,
0339 typename IteratorType
0340 >
0341 void internal_write_tiled_data( const View& view
0342 , tiff_tile_width::type tw
0343 , tiff_tile_length::type th
0344 , byte_vector_t& row
0345 , IteratorType it
0346 )
0347 {
0348 std::ptrdiff_t i = 0, j = 0;
0349 View tile_subimage_view;
0350 while( i < view.height() )
0351 {
0352 while( j < view.width() )
0353 {
0354 if( j + tw < view.width() && i + th < view.height() )
0355 {
0356
0357 tile_subimage_view = subimage_view( view
0358 , static_cast< int >( j )
0359 , static_cast< int >( i )
0360 , static_cast< int >( tw )
0361 , static_cast< int >( th )
0362 );
0363
0364 using colour_space_t = typename color_space_type<typename View::value_type>::type;
0365 using has_alpha_t = mp11::mp_contains<colour_space_t, alpha_t>;
0366
0367 write_tiled_view_to_dev(tile_subimage_view, it, has_alpha_t());
0368 }
0369 else
0370 {
0371 std::ptrdiff_t width = view.width();
0372 std::ptrdiff_t height = view.height();
0373
0374 std::ptrdiff_t current_tile_width = ( j + tw < width ) ? tw : width - j;
0375 std::ptrdiff_t current_tile_length = ( i + th < height) ? th : height - i;
0376
0377 tile_subimage_view = subimage_view( view
0378 , static_cast< int >( j )
0379 , static_cast< int >( i )
0380 , static_cast< int >( current_tile_width )
0381 , static_cast< int >( current_tile_length )
0382 );
0383
0384 for( typename View::y_coord_t y = 0; y < tile_subimage_view.height(); ++y )
0385 {
0386 std::copy( tile_subimage_view.row_begin( y )
0387 , tile_subimage_view.row_end( y )
0388 , it
0389 );
0390 std::advance(it, tw);
0391 }
0392
0393 it = IteratorType( &(*row.begin()));
0394 }
0395
0396 this->_io_dev.write_tile( row
0397 , static_cast< std::uint32_t >( j )
0398 , static_cast< std::uint32_t >( i )
0399 , 0
0400 , 0
0401 );
0402 j += tw;
0403 }
0404 j = 0;
0405 i += th;
0406 }
0407
0408 }
0409 };
0410
0411
0412
0413
0414 template< typename Device >
0415 class dynamic_image_writer< Device
0416 , tiff_tag
0417 >
0418 : public writer< Device
0419 , tiff_tag
0420 >
0421 {
0422 using parent_t = writer<Device, tiff_tag>;
0423
0424 public:
0425
0426 dynamic_image_writer( const Device& io_dev
0427 , const image_write_info< tiff_tag >& info
0428 )
0429 : parent_t( io_dev
0430 , info
0431 )
0432 {}
0433
0434 template< typename ...Views >
0435 void apply( const any_image_view< Views... >& views )
0436 {
0437 detail::dynamic_io_fnobj< detail::tiff_write_is_supported
0438 , parent_t
0439 > op( this );
0440
0441 variant2::visit( op, views );
0442 }
0443 };
0444
0445 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0446 #pragma warning(pop)
0447 #endif
0448
0449 }
0450 }
0451
0452 #endif