summaryrefslogtreecommitdiff
path: root/boost/gil/extension/io/pnm/detail/read.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/gil/extension/io/pnm/detail/read.hpp')
-rw-r--r--boost/gil/extension/io/pnm/detail/read.hpp465
1 files changed, 465 insertions, 0 deletions
diff --git a/boost/gil/extension/io/pnm/detail/read.hpp b/boost/gil/extension/io/pnm/detail/read.hpp
new file mode 100644
index 0000000000..5f267ada5e
--- /dev/null
+++ b/boost/gil/extension/io/pnm/detail/read.hpp
@@ -0,0 +1,465 @@
+/*
+ Copyright 2012 Christian Henning
+ Use, modification and distribution are subject to 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
+
+////////////////////////////////////////////////////////////////////////////////////////
+/// \file
+/// \brief
+/// \author Christian Henning \n
+///
+/// \date 2012 \n
+///
+////////////////////////////////////////////////////////////////////////////////////////
+
+#include <vector>
+#include <boost/bind.hpp>
+#include <boost/gil.hpp>
+#include <boost/gil/extension/io/pnm/tags.hpp>
+
+#include <boost/gil/io/base.hpp>
+#include <boost/gil/io/conversion_policies.hpp>
+#include <boost/gil/io/row_buffer_helper.hpp>
+#include <boost/gil/io/bit_operations.hpp>
+#include <boost/gil/io/reader_base.hpp>
+#include <boost/gil/io/device.hpp>
+#include <boost/gil/io/typedefs.hpp>
+
+#include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
+#include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
+
+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:
+
+ typedef reader< Device
+ , pnm_tag
+ , ConversionPolicy
+ > this_t;
+
+ typedef typename ConversionPolicy::color_converter_type cc_t;
+
+public:
+
+ typedef reader_backend< Device, pnm_tag > backend_t;
+
+public:
+
+ 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 )
+ {
+ typedef typename is_same< ConversionPolicy
+ , detail::read_and_no_convert
+ >::type is_read_and_convert_t;
+
+ 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 )
+ {
+ typedef typename View_Dst::y_coord_t y_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 )
+ {
+ typedef typename channel_type< typename get_pixel_type< View_Dst >::type >::type channel_t;
+
+ // 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 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
+ , mpl::true_ // 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
+ , mpl::false_()
+ );
+ }
+ }
+
+ 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
+ , mpl::false_ // 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 )
+ {
+ typedef typename View_Dst::y_coord_t y_t;
+ typedef typename is_bit_aligned<
+ typename View_Src::value_type >::type is_bit_aligned_t;
+
+ typedef detail::row_buffer_helper_view< View_Src > rh_t;
+ 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
+ , is_bit_aligned_t
+ > neg;
+
+ detail::swap_half_bytes< typename rh_t::buffer_t
+ , is_bit_aligned_t
+ > 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()
+ {
+ typedef is_read_supported< typename get_pixel_type< typename Image::view_t >::type
+ , pnm_tag
+ > is_supported_t;
+
+ 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
+ >
+{
+ typedef reader< Device
+ , pnm_tag
+ , detail::read_and_no_convert
+ > parent_t;
+
+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( !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 );
+
+ apply_operation( view( images )
+ , op
+ );
+ }
+ }
+};
+
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
+#pragma warning(pop)
+#endif
+
+} // gil
+} // boost
+
+#endif