Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:36:58

0001 //
0002 // Copyright 2012 Christian Henning
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_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 /// PNM Reader
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     /// Read part of image defined by View and return the data.
0060     void read( byte_t* dst
0061              , int
0062              )
0063     {
0064         _read_function( this, dst );
0065     }
0066 
0067     /// Skip over a scanline.
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             // reading mono text is reading grayscale but with only two values
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                 //gray1_image_t
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                 // gray8_image_t
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                 // rgb8_image_t
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                 // for pnm format 0 is white
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     // For bit_aligned images we need to negate all bytes in the row_buffer
0234     // to make sure that 0 is black and 255 is white.
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 } // namespace gil
0244 } // namespace boost
0245 
0246 #endif