reader_backend.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. #include <boost/gil/extension/io/pnm/tags.hpp>
  11. namespace boost { namespace gil {
  12. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  13. #pragma warning(push)
  14. #pragma warning(disable:4512) //assignment operator could not be generated
  15. #endif
  16. ///
  17. /// PNM Backend
  18. ///
  19. template< typename Device >
  20. struct reader_backend< Device
  21. , pnm_tag
  22. >
  23. {
  24. public:
  25. using format_tag_t = pnm_tag;
  26. public:
  27. reader_backend( const Device& io_dev
  28. , const image_read_settings< pnm_tag >& settings
  29. )
  30. : _io_dev ( io_dev )
  31. , _settings( settings )
  32. , _info()
  33. , _scanline_length( 0 )
  34. {
  35. read_header();
  36. if( _settings._dim.x == 0 )
  37. {
  38. _settings._dim.x = _info._width;
  39. }
  40. if( _settings._dim.y == 0 )
  41. {
  42. _settings._dim.y = _info._height;
  43. }
  44. }
  45. void read_header()
  46. {
  47. // read signature
  48. io_error_if( read_char() != 'P', "Invalid PNM signature" );
  49. _info._type = read_char() - '0';
  50. io_error_if( _info._type < pnm_image_type::mono_asc_t::value || _info._type > pnm_image_type::color_bin_t::value
  51. , "Invalid PNM file (supports P1 to P6)"
  52. );
  53. _info._width = read_int();
  54. _info._height = read_int();
  55. if( _info._type == pnm_image_type::mono_asc_t::value || _info._type == pnm_image_type::mono_bin_t::value )
  56. {
  57. _info._max_value = 1;
  58. }
  59. else
  60. {
  61. _info._max_value = read_int();
  62. io_error_if( _info._max_value > 255
  63. , "Unsupported PNM format (supports maximum value 255)"
  64. );
  65. }
  66. }
  67. /// Check if image is large enough.
  68. void check_image_size( point_t const& img_dim )
  69. {
  70. if( _settings._dim.x > 0 )
  71. {
  72. if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
  73. }
  74. else
  75. {
  76. if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
  77. }
  78. if( _settings._dim.y > 0 )
  79. {
  80. if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
  81. }
  82. else
  83. {
  84. if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
  85. }
  86. }
  87. private:
  88. // Read a character and skip a comment if necessary.
  89. char read_char()
  90. {
  91. char ch;
  92. if(( ch = _io_dev.getc() ) == '#' )
  93. {
  94. // skip comment to EOL
  95. do
  96. {
  97. ch = _io_dev.getc();
  98. }
  99. while (ch != '\n' && ch != '\r');
  100. }
  101. return ch;
  102. }
  103. unsigned int read_int()
  104. {
  105. char ch;
  106. // skip whitespaces, tabs, and new lines
  107. do
  108. {
  109. ch = read_char();
  110. }
  111. while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
  112. if( ch < '0' || ch > '9' )
  113. {
  114. io_error( "Unexpected characters reading decimal digits" );
  115. }
  116. unsigned val = 0;
  117. do
  118. {
  119. unsigned dig = ch - '0';
  120. if( val > INT_MAX / 10 - dig )
  121. {
  122. io_error( "Integer too large" );
  123. }
  124. val = val * 10 + dig;
  125. ch = read_char();
  126. }
  127. while( '0' <= ch && ch <= '9' );
  128. return val;
  129. }
  130. public:
  131. Device _io_dev;
  132. image_read_settings< pnm_tag > _settings;
  133. image_read_info< pnm_tag > _info;
  134. std::size_t _scanline_length;
  135. };
  136. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  137. #pragma warning(pop)
  138. #endif
  139. } // namespace gil
  140. } // namespace boost
  141. #endif