1 // 2 // Copyright 2012 Christian Henning 3 // 4 // Distributed under the Boost Software License, Version 1.0 5 // See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt 7 // 8 #ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READER_BACKEND_HPP 9 #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READER_BACKEND_HPP 10 11 #include <boost/gil/extension/io/pnm/tags.hpp> 12 13 namespace boost { namespace gil { 14 15 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 16 #pragma warning(push) 17 #pragma warning(disable:4512) //assignment operator could not be generated 18 #endif 19 20 /// 21 /// PNM Backend 22 /// 23 template< typename Device > 24 struct reader_backend< Device 25 , pnm_tag 26 > 27 { 28 public: 29 30 using format_tag_t = pnm_tag; 31 32 public: 33 reader_backendboost::gil::reader_backend34 reader_backend( const Device& io_dev 35 , const image_read_settings< pnm_tag >& settings 36 ) 37 : _io_dev ( io_dev ) 38 , _settings( settings ) 39 , _info() 40 41 , _scanline_length( 0 ) 42 { 43 read_header(); 44 45 if( _settings._dim.x == 0 ) 46 { 47 _settings._dim.x = _info._width; 48 } 49 50 if( _settings._dim.y == 0 ) 51 { 52 _settings._dim.y = _info._height; 53 } 54 } 55 read_headerboost::gil::reader_backend56 void read_header() 57 { 58 // read signature 59 io_error_if( read_char() != 'P', "Invalid PNM signature" ); 60 61 _info._type = read_char() - '0'; 62 63 io_error_if( _info._type < pnm_image_type::mono_asc_t::value || _info._type > pnm_image_type::color_bin_t::value 64 , "Invalid PNM file (supports P1 to P6)" 65 ); 66 67 _info._width = read_int(); 68 _info._height = read_int(); 69 70 if( _info._type == pnm_image_type::mono_asc_t::value || _info._type == pnm_image_type::mono_bin_t::value ) 71 { 72 _info._max_value = 1; 73 } 74 else 75 { 76 _info._max_value = read_int(); 77 78 io_error_if( _info._max_value > 255 79 , "Unsupported PNM format (supports maximum value 255)" 80 ); 81 } 82 } 83 84 /// Check if image is large enough. check_image_sizeboost::gil::reader_backend85 void check_image_size( const point_t& img_dim ) 86 { 87 if( _settings._dim.x > 0 ) 88 { 89 if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); } 90 } 91 else 92 { 93 if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); } 94 } 95 96 97 if( _settings._dim.y > 0 ) 98 { 99 if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); } 100 } 101 else 102 { 103 if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); } 104 } 105 } 106 107 private: 108 109 // Read a character and skip a comment if necessary. read_charboost::gil::reader_backend110 char read_char() 111 { 112 char ch; 113 114 if(( ch = _io_dev.getc() ) == '#' ) 115 { 116 // skip comment to EOL 117 do 118 { 119 ch = _io_dev.getc(); 120 } 121 while (ch != '\n' && ch != '\r'); 122 } 123 124 return ch; 125 } 126 read_intboost::gil::reader_backend127 unsigned int read_int() 128 { 129 char ch; 130 131 // skip whitespaces, tabs, and new lines 132 do 133 { 134 ch = read_char(); 135 } 136 while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); 137 138 if( ch < '0' || ch > '9' ) 139 { 140 io_error( "Unexpected characters reading decimal digits" ); 141 } 142 143 unsigned val = 0; 144 145 do 146 { 147 unsigned dig = ch - '0'; 148 149 if( val > INT_MAX / 10 - dig ) 150 { 151 io_error( "Integer too large" ); 152 } 153 154 val = val * 10 + dig; 155 156 ch = read_char(); 157 } 158 while( '0' <= ch && ch <= '9' ); 159 160 return val; 161 } 162 163 164 public: 165 166 Device _io_dev; 167 168 image_read_settings< pnm_tag > _settings; 169 image_read_info< pnm_tag > _info; 170 171 std::size_t _scanline_length; 172 }; 173 174 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) 175 #pragma warning(pop) 176 #endif 177 178 } // namespace gil 179 } // namespace boost 180 181 #endif 182