123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- //
- // Copyright 2007-2012 Christian Henning, Lubomir Bourdev
- //
- // Distributed under the Boost Software License, Version 1.0
- // See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt
- //
- #ifndef BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
- #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
- #include <boost/gil/extension/io/tiff/tags.hpp>
- #include <boost/gil/extension/io/tiff/detail/writer_backend.hpp>
- #include <boost/gil/extension/io/tiff/detail/device.hpp>
- #include <boost/gil/premultiply.hpp>
- #include <boost/gil/io/base.hpp>
- #include <boost/gil/io/device.hpp>
- #include <boost/gil/io/detail/dynamic.hpp>
- #include <algorithm>
- #include <cstdint>
- #include <string>
- #include <type_traits>
- #include <vector>
- extern "C" {
- #include "tiff.h"
- #include "tiffio.h"
- }
- namespace boost { namespace gil {
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(push)
- #pragma warning(disable:4512) //assignment operator could not be generated
- #endif
- namespace detail {
- template <typename PixelReference>
- struct my_interleaved_pixel_iterator_type_from_pixel_reference
- {
- private:
- using pixel_t = typename std::remove_reference<PixelReference>::type::value_type;
- public:
- using type = typename iterator_type_from_pixel
- <
- pixel_t,
- false,
- false,
- true
- >::type;
- };
- template< typename Channel
- , typename Layout
- , bool Mutable
- >
- struct my_interleaved_pixel_iterator_type_from_pixel_reference< const bit_aligned_pixel_reference< byte_t
- , Channel
- , Layout
- , Mutable
- >
- >
- : public iterator_type_from_pixel< const bit_aligned_pixel_reference< uint8_t
- , Channel
- , Layout
- , Mutable
- >
- ,false
- ,false
- ,true
- > {};
- struct tiff_write_is_supported
- {
- template< typename View >
- struct apply
- : public is_write_supported< typename get_pixel_type< View >::type
- , tiff_tag
- >
- {};
- };
- } // namespace detail
- ///
- /// TIFF Writer
- ///
- template < typename Device, typename Log >
- class writer< Device
- , tiff_tag
- , Log
- >
- : public writer_backend< Device
- , tiff_tag
- >
- {
- private:
- using backend_t = writer_backend<Device, tiff_tag>;
- public:
- writer( const Device& io_dev
- , const image_write_info< tiff_tag >& info
- )
- : backend_t( io_dev
- , info
- )
- {}
- template<typename View>
- void apply( const View& view )
- {
- write_view( view );
- }
- private:
- template< typename View >
- void write_view( const View& view )
- {
- using pixel_t = typename View::value_type;
- // get the type of the first channel (heterogeneous pixels might be broken for now!)
- using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
- tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
- tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
- this->write_header( view );
- if( this->_info._is_tiled == false )
- {
- write_data( view
- , (view.width() * samples_per_pixel * bits_per_sample + 7) / 8
- , typename is_bit_aligned< pixel_t >::type()
- );
- }
- else
- {
- tiff_tile_width::type tw = this->_info._tile_width;
- tiff_tile_length::type th = this->_info._tile_length;
- if(!this->_io_dev.check_tile_size( tw, th ))
- {
- io_error( "Tile sizes need to be multiples of 16." );
- }
- // tile related tags
- this->_io_dev.template set_property<tiff_tile_width> ( tw );
- this->_io_dev.template set_property<tiff_tile_length>( th );
- write_tiled_data( view
- , tw
- , th
- , typename is_bit_aligned< pixel_t >::type()
- );
- }
- }
- //////////////////////////////
- template<typename View>
- void write_bit_aligned_view_to_dev( const View& view
- , const std::size_t row_size_in_bytes
- , const std::true_type& // has_alpha
- )
- {
- byte_vector_t row( row_size_in_bytes );
- using x_it_t = typename View::x_iterator;
- x_it_t row_it = x_it_t( &(*row.begin()));
- auto pm_view = premultiply_view <typename View:: value_type> (view);
- for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
- {
- std::copy( pm_view.row_begin( y )
- , pm_view.row_end( y )
- , row_it
- );
- this->_io_dev.write_scaline( row
- , static_cast<std::uint32_t>( y )
- , 0
- );
- // @todo: do optional bit swapping here if you need to...
- }
- }
- template<typename View>
- void write_bit_aligned_view_to_dev( const View& view
- , const std::size_t row_size_in_bytes
- , const std::false_type& // has_alpha
- )
- {
- byte_vector_t row( row_size_in_bytes );
- using x_it_t = typename View::x_iterator;
- x_it_t row_it = x_it_t( &(*row.begin()));
- for( typename View::y_coord_t y = 0; y < view.height(); ++y )
- {
- std::copy( view.row_begin( y )
- , view.row_end( y )
- , row_it
- );
- this->_io_dev.write_scaline( row
- , static_cast<std::uint32_t>( y )
- , 0
- );
- // @todo: do optional bit swapping here if you need to...
- }
- }
- /////////////////////////////
- template< typename View >
- void write_data( const View& view
- , std::size_t row_size_in_bytes
- , const std::true_type& // bit_aligned
- )
- {
- using colour_space_t = typename color_space_type<typename View::value_type>::type;
- using has_alpha_t = mp11::mp_contains<colour_space_t, alpha_t>;
- write_bit_aligned_view_to_dev(view, row_size_in_bytes, has_alpha_t());
- }
- template< typename View>
- void write_tiled_data( const View& view
- , tiff_tile_width::type tw
- , tiff_tile_length::type th
- , const std::true_type& // bit_aligned
- )
- {
- byte_vector_t row( this->_io_dev.get_tile_size() );
- using x_it_t = typename View::x_iterator;
- x_it_t row_it = x_it_t( &(*row.begin()));
- internal_write_tiled_data(view, tw, th, row, row_it);
- }
- template< typename View >
- void write_data( const View& view
- , std::size_t
- , const std::false_type& // bit_aligned
- )
- {
- std::vector< pixel< typename channel_type< View >::type
- , layout<typename color_space_type< View >::type >
- >
- > row( view.size() );
- byte_t* row_addr = reinterpret_cast< byte_t* >( &row.front() );
- // @todo: is there an overhead to doing this when there's no
- // alpha to premultiply by? I'd hope it's optimised out.
- auto pm_view = premultiply_view <typename View:: value_type> (view);
- for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
- {
- std::copy( pm_view.row_begin( y )
- , pm_view.row_end( y )
- , row.begin()
- );
- this->_io_dev.write_scaline( row_addr
- , static_cast<std::uint32_t>( y )
- , 0
- );
- // @todo: do optional bit swapping here if you need to...
- }
- }
- template< typename View >
- void write_tiled_data( const View& view
- , tiff_tile_width::type tw
- , tiff_tile_length::type th
- , const std::false_type& // bit_aligned
- )
- {
- byte_vector_t row( this->_io_dev.get_tile_size() );
- using x_iterator = typename detail::my_interleaved_pixel_iterator_type_from_pixel_reference<typename View::reference>::type;
- x_iterator row_it = x_iterator( &(*row.begin()));
- internal_write_tiled_data(view, tw, th, row, row_it);
- }
- //////////////////////////////
- template< typename View
- , typename IteratorType
- >
- void write_tiled_view_to_dev( const View& view
- , IteratorType it
- , const std::true_type& // has_alpha
- )
- {
- auto pm_view = premultiply_view <typename View:: value_type>( view );
- std::copy( pm_view.begin()
- , pm_view.end()
- , it
- );
- }
- template< typename View
- , typename IteratorType
- >
- void write_tiled_view_to_dev( const View& view
- , IteratorType it
- , const std::false_type& // has_alpha
- )
- {
- std::copy( view.begin()
- , view.end()
- , it
- );
- }
- /////////////////////////////
- template< typename View,
- typename IteratorType
- >
- void internal_write_tiled_data( const View& view
- , tiff_tile_width::type tw
- , tiff_tile_length::type th
- , byte_vector_t& row
- , IteratorType it
- )
- {
- std::ptrdiff_t i = 0, j = 0;
- View tile_subimage_view;
- while( i < view.height() )
- {
- while( j < view.width() )
- {
- if( j + tw < view.width() && i + th < view.height() )
- {
- // a tile is fully included in the image: just copy values
- tile_subimage_view = subimage_view( view
- , static_cast< int >( j )
- , static_cast< int >( i )
- , static_cast< int >( tw )
- , static_cast< int >( th )
- );
- using colour_space_t = typename color_space_type<typename View::value_type>::type;
- using has_alpha_t = mp11::mp_contains<colour_space_t, alpha_t>;
- write_tiled_view_to_dev(tile_subimage_view, it, has_alpha_t());
- }
- else
- {
- std::ptrdiff_t width = view.width();
- std::ptrdiff_t height = view.height();
- std::ptrdiff_t current_tile_width = ( j + tw < width ) ? tw : width - j;
- std::ptrdiff_t current_tile_length = ( i + th < height) ? th : height - i;
- tile_subimage_view = subimage_view( view
- , static_cast< int >( j )
- , static_cast< int >( i )
- , static_cast< int >( current_tile_width )
- , static_cast< int >( current_tile_length )
- );
- for( typename View::y_coord_t y = 0; y < tile_subimage_view.height(); ++y )
- {
- std::copy( tile_subimage_view.row_begin( y )
- , tile_subimage_view.row_end( y )
- , it
- );
- std::advance(it, tw);
- }
- it = IteratorType( &(*row.begin()));
- }
- this->_io_dev.write_tile( row
- , static_cast< std::uint32_t >( j )
- , static_cast< std::uint32_t >( i )
- , 0
- , 0
- );
- j += tw;
- }
- j = 0;
- i += th;
- }
- // @todo: do optional bit swapping here if you need to...
- }
- };
- ///
- /// TIFF Dynamic Image Writer
- ///
- template< typename Device >
- class dynamic_image_writer< Device
- , tiff_tag
- >
- : public writer< Device
- , tiff_tag
- >
- {
- using parent_t = writer<Device, tiff_tag>;
- public:
- dynamic_image_writer( const Device& io_dev
- , const image_write_info< tiff_tag >& info
- )
- : parent_t( io_dev
- , info
- )
- {}
- template< typename ...Views >
- void apply( const any_image_view< Views... >& views )
- {
- detail::dynamic_io_fnobj< detail::tiff_write_is_supported
- , parent_t
- > op( this );
- variant2::visit( op, views );
- }
- };
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(pop)
- #endif
- } // namespace gil
- } // namespace boost
- #endif
|