File indexing completed on 2025-01-18 09:36:58
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SCANLINE_READ_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SCANLINE_READ_HPP
0010
0011 #include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
0012 #include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
0013
0014 #include <boost/gil.hpp> // FIXME: Include what you use!
0015 #include <boost/gil/io/base.hpp>
0016 #include <boost/gil/io/bit_operations.hpp>
0017 #include <boost/gil/io/conversion_policies.hpp>
0018 #include <boost/gil/io/device.hpp>
0019 #include <boost/gil/io/reader_base.hpp>
0020 #include <boost/gil/io/row_buffer_helper.hpp>
0021 #include <boost/gil/io/scanline_read_iterator.hpp>
0022 #include <boost/gil/io/typedefs.hpp>
0023
0024 #include <functional>
0025 #include <type_traits>
0026 #include <vector>
0027
0028 namespace boost { namespace gil {
0029
0030
0031
0032
0033 template< typename Device >
0034 class scanline_reader< Device
0035 , pnm_tag
0036 >
0037 : public reader_backend< Device
0038 , pnm_tag
0039 >
0040 {
0041 public:
0042
0043 using tag_t = pnm_tag;
0044 using backend_t = reader_backend<Device, tag_t>;
0045 using this_t = scanline_reader<Device, tag_t>;
0046 using iterator_t = scanline_read_iterator<this_t>;
0047
0048 public:
0049 scanline_reader( Device& device
0050 , const image_read_settings< pnm_tag >& settings
0051 )
0052 : backend_t( device
0053 , settings
0054 )
0055 {
0056 initialize();
0057 }
0058
0059
0060 void read( byte_t* dst
0061 , int
0062 )
0063 {
0064 _read_function( this, dst );
0065 }
0066
0067
0068 void skip( byte_t*, int )
0069 {
0070 _skip_function( this );
0071 }
0072
0073 iterator_t begin() { return iterator_t( *this ); }
0074 iterator_t end() { return iterator_t( *this, this->_info._height ); }
0075
0076 private:
0077
0078 void initialize()
0079 {
0080 switch( this->_info._type )
0081 {
0082
0083 case pnm_image_type::mono_asc_t::value:
0084 case pnm_image_type::gray_asc_t::value:
0085 {
0086 this->_scanline_length = this->_info._width;
0087
0088 _read_function = std::mem_fn(&this_t::read_text_row);
0089 _skip_function = std::mem_fn(&this_t::skip_text_row);
0090
0091 break;
0092 }
0093
0094 case pnm_image_type::color_asc_t::value:
0095 {
0096 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
0097
0098 _read_function = std::mem_fn(&this_t::read_text_row);
0099 _skip_function = std::mem_fn(&this_t::skip_text_row);
0100
0101 break;
0102 }
0103
0104
0105 case pnm_image_type::mono_bin_t::value:
0106 {
0107
0108 this->_scanline_length = ( this->_info._width + 7 ) >> 3;
0109
0110 _read_function = std::mem_fn(&this_t::read_binary_bit_row);
0111 _skip_function = std::mem_fn(&this_t::skip_binary_row);
0112
0113 break;
0114 }
0115
0116 case pnm_image_type::gray_bin_t::value:
0117 {
0118
0119 this->_scanline_length = this->_info._width;
0120
0121 _read_function = std::mem_fn(&this_t::read_binary_byte_row);
0122 _skip_function = std::mem_fn(&this_t::skip_binary_row);
0123
0124 break;
0125 }
0126
0127 case pnm_image_type::color_bin_t::value:
0128 {
0129
0130 this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
0131
0132 _read_function = std::mem_fn(&this_t::read_binary_byte_row);
0133 _skip_function = std::mem_fn(&this_t::skip_binary_row);
0134
0135 break;
0136 }
0137
0138 default: { io_error( "Unsupported pnm file." ); break; }
0139 }
0140 }
0141
0142 void read_text_row( byte_t* dst )
0143 {
0144 for( std::size_t x = 0; x < this->_scanline_length; ++x )
0145 {
0146 for( uint32_t k = 0; ; )
0147 {
0148 int ch = this->_io_dev.getc_unchecked();
0149
0150 if( isdigit( ch ))
0151 {
0152 _text_buffer[ k++ ] = static_cast< char >( ch );
0153 }
0154 else if( k )
0155 {
0156 _text_buffer[ k ] = 0;
0157 break;
0158 }
0159 else if( ch == EOF || !isspace( ch ))
0160 {
0161 return;
0162 }
0163 }
0164
0165 int value = atoi( _text_buffer );
0166
0167 if( this->_info._max_value == 1 )
0168 {
0169
0170 dst[x] = ( value != 0 )
0171 ? 0
0172 : 255;
0173 }
0174 else
0175 {
0176 dst[x] = static_cast< byte_t >( value );
0177 }
0178 }
0179 }
0180
0181 void skip_text_row()
0182 {
0183 for( std::size_t x = 0; x < this->_scanline_length; ++x )
0184 {
0185 for( uint32_t k = 0; ; )
0186 {
0187 int ch = this->_io_dev.getc_unchecked();
0188
0189 if( isdigit( ch ))
0190 {
0191 k++;
0192 }
0193 else if( k )
0194 {
0195 break;
0196 }
0197 else if( ch == EOF || !isspace( ch ))
0198 {
0199 return;
0200 }
0201 }
0202 }
0203 }
0204
0205
0206 void read_binary_bit_row( byte_t* dst )
0207 {
0208 this->_io_dev.read( dst
0209 , this->_scanline_length
0210 );
0211
0212 _negate_bits ( dst, this->_scanline_length );
0213 _swap_half_bytes( dst, this->_scanline_length );
0214
0215 }
0216
0217 void read_binary_byte_row( byte_t* dst )
0218 {
0219 this->_io_dev.read( dst
0220 , this->_scanline_length
0221 );
0222 }
0223
0224 void skip_binary_row()
0225 {
0226 this->_io_dev.seek( static_cast<long>( this->_scanline_length ), SEEK_CUR );
0227 }
0228
0229 private:
0230
0231 char _text_buffer[16];
0232
0233
0234
0235 detail::negate_bits<std::vector<byte_t>, std::true_type> _negate_bits;
0236 detail::swap_half_bytes<std::vector<byte_t>, std::true_type> _swap_half_bytes;
0237
0238 std::function<void(this_t*, byte_t*)> _read_function;
0239 std::function<void(this_t*)> _skip_function;
0240 };
0241
0242
0243 }
0244 }
0245
0246 #endif