38 bool is_space(
char c )
40 return c ==
'\n' || c ==
'\r' || c ==
' ' || c ==
'\t' ;
43 bool is_digit(
char c )
45 return c >=
'0' && c <=
'9' ;
48 unsigned int value256(
unsigned int maxval ,
unsigned int n )
53 n =
static_cast<unsigned int>(x) ;
54 return n > 255U ? 255U : n ;
58 T skip( T in , T end ,
size_t & offset )
60 bool in_comment = false ;
63 if( *in ==
'#' ) in_comment = true ;
64 if( in_comment && *in ==
'\n' ) in_comment = false ;
65 if( !in_comment && !is_space(*in) ) break ;
72 T skip_eol( T in , T end ,
size_t & offset )
74 if( in != end && *in ==
'\r' ) ++in , offset++ ;
75 if( in != end ) ++in , offset++ ;
80 int get_n( T & in , T end ,
size_t & offset )
82 if( in == end )
return 0 ;
84 while( in != end && is_digit(*in) )
87 char c = *in++ ; offset++ ;
94 bool readInfoImp( T & in , T end ,
Gr::PnmInfo & info )
103 if( in == end )
return false ;
104 char p = *in++ ; offset++ ;
105 if( in == end || p !=
'P' )
return false ;
106 char n = *in++ ; offset++ ;
107 if( ! ( n >=
'1' && n <=
'6' ) )
return false ;
108 pn =
static_cast<int>( n -
'0' ) ;
110 bool with_maxval = ! ( pn == 1 || pn == 4 ) ;
111 bool binary = pn >= 4 ;
112 if( in == end )
return false ;
115 in = skip( in , end , offset ) ;
116 if( in == end )
return false ;
117 dx = get_n( in , end , offset ) ;
120 in = skip( in , end , offset ) ;
121 if( in == end )
return false ;
122 dy = get_n( in , end , offset ) ;
128 in = skip( in , end , offset ) ;
129 if( in == end )
return false ;
130 maxval = get_n( in , end , offset ) ;
133 in = binary ? skip_eol(in,end,offset) : skip(in,end,offset) ;
134 if( in == end )
return false ;
136 info =
Gr::PnmInfo( pn , dx , dy , maxval , offset ) ;
137 return dx > 0 && dy > 0 && (!with_maxval||maxval>0) ;
140 template <
typename T>
144 if( !readInfoImp( in , end , info ) )
149 template <
typename T>
150 struct ScalingAdaptor
152 ScalingAdaptor( T & t ,
const Gr::PnmInfo & info ,
int scale ) :
164 void operator()(
int x ,
int y ,
unsigned int r ,
unsigned int g ,
unsigned int b )
166 if( y == m_y_in && x == m_x_in )
168 m_x_out_max = m_x_out ;
169 m_y_out_max = m_y_out ;
170 m_t( m_x_out , m_y_out , r , g , b ) ;
173 if( m_x_in >= m_info.dx() )
184 G_ASSERT( Gr::scaled(m_info.dx(),m_scale) == (m_x_out_max+1) ) ;
185 return m_x_out_max + 1 ;
189 G_ASSERT( Gr::scaled(m_info.dy(),m_scale) == (m_y_out_max+1) ) ;
190 return m_y_out_max + 1 ;
204 struct ImageDataAdaptor
209 G_ASSERT( data.
dx() > 0 ) ;
211 void operator()(
int x ,
int y ,
unsigned int r ,
unsigned int g ,
unsigned int b )
213 m_data.rgb( x , y , r , g , b ) ;
220 RawAdaptor( std::vector<char> & out ,
const Gr::PnmInfo & info ) :
222 m_channels(info.channels())
224 G_ASSERT( !out.empty() ) ;
225 m_out_p = m_out.begin() ;
227 void operator()(
int ,
int ,
unsigned int r ,
unsigned int g ,
unsigned int b )
229 if( m_channels == 1 )
241 std::vector<char> & m_out ;
242 std::vector<char>::iterator m_out_p ;
246 template <
typename Tout>
247 void readBodyImp( Tout & out , std::istream & in ,
const Gr::PnmInfo & info )
249 const bool is_binary = info.
binary() ;
250 const bool is_boolean = info.
pn() == 1 || info.
pn() == 4 ;
251 if( is_binary && is_boolean )
253 const int dx_in = (1 + (info.
dx()-1)/8) ;
254 const int info_dx = info.
dx() ;
255 for(
int y = 0 ; y < info.
dy() ; y++ )
258 for(
int x_in = 0 ; x_in < dx_in ; x_in++ )
260 unsigned int n = in.get() ;
261 for(
unsigned mask = 0x80 ; mask != 0U && x_out < info_dx ; mask >>= 1 )
262 out( x_out++ , y , (n & mask)?0U:255U , (n & mask)?0U:255U , (n & mask)?0U:255U ) ;
268 const int channels_in = ( info.
pn() == 3 || info.
pn() == 6 ) ? 3 : 1 ;
269 for(
int y = 0 ; y < info.
dy() ; y++ )
271 for(
int x = 0 ; x < info.
dx() ; x++ )
273 unsigned int r = 0U ;
274 unsigned int g = 0U ;
275 unsigned int b = 0U ;
276 for(
int c = 0 ; c < channels_in ; c++ )
278 unsigned int n = 0U ;
290 n = value256( info.
maxval() , n ) ;
300 out( x , y , r , g , b ) ;
314 if( pn == 1 || pn == 4 )
320 std::ios::fmtflags ff = in.flags() ;
321 in.unsetf( std::ios::skipws ) ;
323 std::istream_iterator<char> p = std::istream_iterator<char>(in) ;
324 std::istream_iterator<char> end ;
325 PnmInfo info = readInfoImp( p , end ) ;
332 in.setstate( std::ios_base::failbit ) ;
339 std::vector<char>::const_iterator p = buffer.begin() ;
340 PnmInfo info = readInfoImp( p , buffer.end() ) ;
346 const char * p = buffer ;
347 PnmInfo info = readInfoImp( p , buffer+buffer_size ) ;
353 const unsigned char * p = buffer ;
354 PnmInfo info = readInfoImp( p , buffer+buffer_size ) ;
361 const_byte_iterator p = imagebuffer::bytes_begin( image_buffer ) ;
362 PnmInfo info = readInfoImp( p , imagebuffer::bytes_end(image_buffer) ) ;
368 return static_cast<size_t>( dx() * channels() ) ;
373 m_monochrome_out(monochrome_out)
380 m_monochrome_out = monochrome_out ;
388 in.open( path.
str().c_str() ) ;
391 if( !m_info.valid() )
392 throw std::runtime_error(
"failed to read pnm file format: [" + path.
str() +
"]" ) ;
393 if( !readBody(in,m_info,out,m_scale,m_monochrome_out) )
394 throw std::runtime_error(
"failed to read pnm file: [" + path.
str() +
"]" ) ;
400 if( !m_info.valid() || !readBody(in,m_info,out,m_scale,m_monochrome_out) )
401 throw std::runtime_error(
"failed to read pnm data" ) ;
406 std::istringstream in ;
407 in.rdbuf()->pubsetbuf( const_cast<char*>(p) , n ) ;
410 if( !m_info.valid() || !readBody(in,m_info,out,m_scale,m_monochrome_out) )
411 throw std::runtime_error(
"failed to read pnm data" ) ;
417 imagebuf inbuf( image_buffer ) ;
418 std::istream in( &inbuf ) ;
420 if( !m_info.valid() || !readBody(in,m_info,out,m_scale,m_monochrome_out) )
421 throw std::runtime_error(
"failed to read pnm data" ) ;
424 bool Gr::PnmReader::readBody( std::istream & in ,
const PnmInfo & info ,
ImageData & data ,
int scale ,
bool monochrome_out )
426 G_ASSERT( info.
valid() ) ;
427 G_ASSERT( info.
dy() >= 1 ) ;
428 G_ASSERT( scale >= 1 ) ;
429 if( !info.
valid() || info.
dy() < 1 || scale < 1 )
435 data.
resize( scaled(info.
dx(),scale) , scaled(info.
dy(),scale) , monochrome_out ? 1 : info.
channels() ) ;
439 std::vector<char> buffer( info.
rowsize() ) ;
440 unsigned char * buffer_p =
reinterpret_cast<unsigned char*
>(&buffer[0]) ;
441 const int data_dy = data.
dy() ;
442 for(
int y = 0 ; y < data_dy ; y++ )
444 in.read( &buffer[0] , buffer.size() ) ;
445 data.
copyRowIn( y , buffer_p , buffer.size() , info.
channels() , true , scale ) ;
446 for(
int i = 0 ; (y+1) < data_dy && i < (scale-1) ; i++ )
447 in.ignore( buffer.size() ) ;
452 ImageDataAdaptor out( data ) ;
453 ScalingAdaptor<ImageDataAdaptor> out_scaled( out , info , scale ) ;
454 readBodyImp( out_scaled , in , info ) ;
456 bool ok = !in.fail() ;
std::string str() const
Returns the path string.
int dx() const
Returns the width.
bool valid() const
Returns true if successfully constructed.
int dx() const
Returns the image width.
A traits class that can be specialised for Gr::ImageBuffer candidates.
A holder for image data, having eight bits per sample and one or three channels.
PnmReader(int scale=1, bool monochrome_out=false)
Constructor.
void resize(int dx, int dy, int channels)
Resizes the image data.
int maxval() const
Returns the maximum value, or zero for bitmap formats (p1/p4).
int pn() const
Returns the p-number.
A class which acquires the process's special privileges on construction and releases them on destruct...
Vectors ImageBuffer
An ImageBuffer is used to hold raw image data, typically in more than one chunk.
int dy() const
Returns the image height.
bool binary() const
Returns true if a binary format.
void decode(ImageData &out, const G::Path &in)
Decodes a pnm file into an image. Throws on error.
void copyRowIn(int y, const unsigned char *row_buffer_in, size_t row_buffer_in_size, int channels_in, bool use_colourspace=false, int scale=1)
Sets a row of pixels by copying, with channel-count adjustment and optional scaling.
int channels() const
Returns the number of channels.
void setup(int scale, bool monochrome_out=false)
Sets the decoding scale factor.
A structure holding portable-anymap metadata.
PnmInfo()
Default constructor for an invalid structure.
int dy() const
Returns the height.
A Path object represents a file system path.
size_t rowsize() const
Returns dx() * channels().