Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:00

0001 //
0002 // Copyright 2007-2012 Christian Henning, Lubomir Bourdev
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
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) //assignment operator could not be generated
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 } // namespace detail
0088 
0089 ///
0090 /// TIFF Writer
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         // get the type of the first channel (heterogeneous pixels might be broken for now!)
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             // tile related tags
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&    // has_alpha
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             // @todo: do optional bit swapping here if you need to...
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&    // has_alpha
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             // @todo: do optional bit swapping here if you need to...
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&    // bit_aligned
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&    // bit_aligned
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&    // bit_aligned
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                 // @todo: is there an overhead to doing this when there's no
0266                 // alpha to premultiply by? I'd hope it's optimised out.
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             // @todo: do optional bit swapping here if you need to...
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&    // bit_aligned
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& // has_alpha
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& // has_alpha
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                     // a tile is fully included in the image: just copy values
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         // @todo: do optional bit swapping here if you need to...
0408     }
0409 };
0410 
0411 ///
0412 /// TIFF Dynamic Image Writer
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 } // namespace gil
0450 } // namespace boost
0451 
0452 #endif