123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- //
- // Copyright 2012 Christian Henning
- //
- // 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_PNM_DETAIL_READ_HPP
- #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
- #include <boost/gil/extension/io/pnm/tags.hpp>
- #include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
- #include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
- #include <boost/gil.hpp> // FIXME: Include what you use!
- #include <boost/gil/io/detail/dynamic.hpp>
- #include <boost/gil/io/base.hpp>
- #include <boost/gil/io/bit_operations.hpp>
- #include <boost/gil/io/conversion_policies.hpp>
- #include <boost/gil/io/device.hpp>
- #include <boost/gil/io/reader_base.hpp>
- #include <boost/gil/io/row_buffer_helper.hpp>
- #include <boost/gil/io/typedefs.hpp>
- #include <type_traits>
- #include <vector>
- namespace boost { namespace gil {
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(push)
- #pragma warning(disable:4512) //assignment operator could not be generated
- #endif
- ///
- /// PNM Reader
- ///
- template< typename Device
- , typename ConversionPolicy
- >
- class reader< Device
- , pnm_tag
- , ConversionPolicy
- >
- : public reader_base< pnm_tag
- , ConversionPolicy
- >
- , public reader_backend< Device
- , pnm_tag
- >
- {
- private:
- using this_t = reader<Device, pnm_tag, ConversionPolicy>;
- using cc_t = typename ConversionPolicy::color_converter_type;
- public:
- using backend_t = reader_backend<Device, pnm_tag>;
- reader( const Device& io_dev
- , const image_read_settings< pnm_tag >& settings
- )
- : reader_base< pnm_tag
- , ConversionPolicy
- >()
- , backend_t( io_dev
- , settings
- )
- {}
- reader( const Device& io_dev
- , const cc_t& cc
- , const image_read_settings< pnm_tag >& settings
- )
- : reader_base< pnm_tag
- , ConversionPolicy
- >( cc )
- , backend_t( io_dev
- , settings
- )
- {}
- template<typename View>
- void apply( const View& view )
- {
- using is_read_and_convert_t = typename std::is_same
- <
- ConversionPolicy,
- detail::read_and_no_convert
- >::type;
- io_error_if( !detail::is_allowed< View >( this->_info
- , is_read_and_convert_t()
- )
- , "Image types aren't compatible."
- );
- switch( this->_info._type )
- {
- // reading mono text is reading grayscale but with only two values
- case pnm_image_type::mono_asc_t::value:
- case pnm_image_type::gray_asc_t::value:
- {
- this->_scanline_length = this->_info._width;
- read_text_data< gray8_view_t >( view );
- break;
- }
- case pnm_image_type::color_asc_t::value:
- {
- this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
- read_text_data< rgb8_view_t >( view );
- break;
- }
- case pnm_image_type::mono_bin_t::value:
- {
- //gray1_image_t
- this->_scanline_length = ( this->_info._width + 7 ) >> 3;
- read_bin_data< gray1_image_t::view_t >( view );
- break;
- }
- case pnm_image_type::gray_bin_t::value:
- {
- // gray8_image_t
- this->_scanline_length = this->_info._width;
- read_bin_data< gray8_view_t >( view );
- break;
- }
- case pnm_image_type::color_bin_t::value:
- {
- // rgb8_image_t
- this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
- read_bin_data< rgb8_view_t >( view );
- break;
- }
- }
- }
- private:
- template< typename View_Src
- , typename View_Dst
- >
- void read_text_data( const View_Dst& dst )
- {
- using y_t = typename View_Dst::y_coord_t;
- byte_vector_t row( this->_scanline_length );
- //Skip scanlines if necessary.
- for( int y = 0; y < this->_settings._top_left.y; ++y )
- {
- read_text_row< View_Src >( dst, row, y, false );
- }
- for( y_t y = 0; y < dst.height(); ++y )
- {
- read_text_row< View_Src >( dst, row, y, true );
- }
- }
- template< typename View_Src
- , typename View_Dst
- >
- void read_text_row( const View_Dst& dst
- , byte_vector_t& row
- , typename View_Dst::y_coord_t y
- , bool process
- )
- {
- View_Src src = interleaved_view( this->_info._width
- , 1
- , (typename View_Src::value_type*) &row.front()
- , this->_scanline_length
- );
- for( uint32_t x = 0; x < this->_scanline_length; ++x )
- {
- for( uint32_t k = 0; ; )
- {
- int ch = this->_io_dev.getc_unchecked();
- if( isdigit( ch ))
- {
- buf[ k++ ] = static_cast< char >( ch );
- }
- else if( k )
- {
- buf[ k ] = 0;
- break;
- }
- else if( ch == EOF || !isspace( ch ))
- {
- return;
- }
- }
- if( process )
- {
- int value = atoi( buf );
- if( this->_info._max_value == 1 )
- {
- using channel_t = typename channel_type<typename get_pixel_type<View_Dst>::type>::type;
- // for pnm format 0 is white
- row[x] = ( value != 0 )
- ? typename channel_traits< channel_t >::value_type( 0 )
- : channel_traits< channel_t >::max_value();
- }
- else
- {
- row[x] = static_cast< byte_t >( value );
- }
- }
- }
- if( process )
- {
- // We are reading a gray1_image like a gray8_image but the two pixel_t
- // aren't compatible. Though, read_and_no_convert::read(...) wont work.
- copy_data< View_Dst
- , View_Src >( dst
- , src
- , y
- , typename std::is_same< View_Dst
- , gray1_image_t::view_t
- >::type()
- );
- }
- }
- template< typename View_Dst
- , typename View_Src
- >
- void copy_data( const View_Dst& dst
- , const View_Src& src
- , typename View_Dst::y_coord_t y
- , std::true_type // is gray1_view
- )
- {
- if( this->_info._max_value == 1 )
- {
- typename View_Dst::x_iterator it = dst.row_begin( y );
- for( typename View_Dst::x_coord_t x = 0
- ; x < dst.width()
- ; ++x
- )
- {
- it[x] = src[x];
- }
- }
- else
- {
- copy_data(dst, src, y, std::false_type{});
- }
- }
- template< typename View_Dst
- , typename View_Src
- >
- void copy_data( const View_Dst& view
- , const View_Src& src
- , typename View_Dst::y_coord_t y
- , std::false_type // is gray1_view
- )
- {
- typename View_Src::x_iterator beg = src.row_begin( 0 ) + this->_settings._top_left.x;
- typename View_Src::x_iterator end = beg + this->_settings._dim.x;
- this->_cc_policy.read( beg
- , end
- , view.row_begin( y )
- );
- }
- template< typename View_Src
- , typename View_Dst
- >
- void read_bin_data( const View_Dst& view )
- {
- using y_t = typename View_Dst::y_coord_t;
- using is_bit_aligned_t = typename is_bit_aligned<typename View_Src::value_type>::type;
- using rh_t = detail::row_buffer_helper_view<View_Src>;
- rh_t rh( this->_scanline_length, true );
- typename rh_t::iterator_t beg = rh.begin() + this->_settings._top_left.x;
- typename rh_t::iterator_t end = beg + this->_settings._dim.x;
- // For bit_aligned images we need to negate all bytes in the row_buffer
- // to make sure that 0 is black and 255 is white.
- detail::negate_bits
- <
- typename rh_t::buffer_t,
- std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
- > neg;
- detail::swap_half_bytes
- <
- typename rh_t::buffer_t,
- std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
- > swhb;
- //Skip scanlines if necessary.
- for( y_t y = 0; y < this->_settings._top_left.y; ++y )
- {
- this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
- , this->_scanline_length
- );
- }
- for( y_t y = 0; y < view.height(); ++y )
- {
- this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
- , this->_scanline_length
- );
- neg( rh.buffer() );
- swhb( rh.buffer() );
- this->_cc_policy.read( beg
- , end
- , view.row_begin( y )
- );
- }
- }
- private:
- char buf[16];
- };
- namespace detail {
- struct pnm_type_format_checker
- {
- pnm_type_format_checker( pnm_image_type::type type )
- : _type( type )
- {}
- template< typename Image >
- bool apply()
- {
- using is_supported_t = is_read_supported
- <
- typename get_pixel_type<typename Image::view_t>::type,
- pnm_tag
- >;
- return is_supported_t::_asc_type == _type
- || is_supported_t::_bin_type == _type;
- }
- private:
- pnm_image_type::type _type;
- };
- struct pnm_read_is_supported
- {
- template< typename View >
- struct apply : public is_read_supported< typename get_pixel_type< View >::type
- , pnm_tag
- >
- {};
- };
- } // namespace detail
- ///
- /// PNM Dynamic Image Reader
- ///
- template< typename Device
- >
- class dynamic_image_reader< Device
- , pnm_tag
- >
- : public reader< Device
- , pnm_tag
- , detail::read_and_no_convert
- >
- {
- using parent_t = reader
- <
- Device,
- pnm_tag,
- detail::read_and_no_convert
- >;
- public:
- dynamic_image_reader( const Device& io_dev
- , const image_read_settings< pnm_tag >& settings
- )
- : parent_t( io_dev
- , settings
- )
- {}
- template< typename ...Images >
- void apply( any_image< Images... >& images )
- {
- detail::pnm_type_format_checker format_checker( this->_info._type );
- if( !detail::construct_matched( images
- , format_checker
- ))
- {
- io_error( "No matching image type between those of the given any_image and that of the file" );
- }
- else
- {
- this->init_image( images
- , this->_settings
- );
- detail::dynamic_io_fnobj< detail::pnm_read_is_supported
- , parent_t
- > op( this );
- variant2::visit( op
- ,view( images )
- );
- }
- }
- };
- #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
- #pragma warning(pop)
- #endif
- } // gil
- } // boost
- #endif
|