scanline_read.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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_SCANLINE_READ_HPP
  9. #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_SCANLINE_READ_HPP
  10. #include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
  11. #include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
  12. #include <boost/gil.hpp> // FIXME: Include what you use!
  13. #include <boost/gil/io/base.hpp>
  14. #include <boost/gil/io/bit_operations.hpp>
  15. #include <boost/gil/io/conversion_policies.hpp>
  16. #include <boost/gil/io/device.hpp>
  17. #include <boost/gil/io/reader_base.hpp>
  18. #include <boost/gil/io/row_buffer_helper.hpp>
  19. #include <boost/gil/io/scanline_read_iterator.hpp>
  20. #include <boost/gil/io/typedefs.hpp>
  21. #include <functional>
  22. #include <type_traits>
  23. #include <vector>
  24. namespace boost { namespace gil {
  25. ///
  26. /// PNM Reader
  27. ///
  28. template< typename Device >
  29. class scanline_reader< Device
  30. , pnm_tag
  31. >
  32. : public reader_backend< Device
  33. , pnm_tag
  34. >
  35. {
  36. public:
  37. using tag_t = pnm_tag;
  38. using backend_t = reader_backend<Device, tag_t>;
  39. using this_t = scanline_reader<Device, tag_t>;
  40. using iterator_t = scanline_read_iterator<this_t>;
  41. public:
  42. scanline_reader( Device& device
  43. , const image_read_settings< pnm_tag >& settings
  44. )
  45. : backend_t( device
  46. , settings
  47. )
  48. {
  49. initialize();
  50. }
  51. /// Read part of image defined by View and return the data.
  52. void read( byte_t* dst
  53. , int
  54. )
  55. {
  56. _read_function( this, dst );
  57. }
  58. /// Skip over a scanline.
  59. void skip( byte_t*, int )
  60. {
  61. _skip_function( this );
  62. }
  63. iterator_t begin() { return iterator_t( *this ); }
  64. iterator_t end() { return iterator_t( *this, this->_info._height ); }
  65. private:
  66. void initialize()
  67. {
  68. switch( this->_info._type )
  69. {
  70. // reading mono text is reading grayscale but with only two values
  71. case pnm_image_type::mono_asc_t::value:
  72. case pnm_image_type::gray_asc_t::value:
  73. {
  74. this->_scanline_length = this->_info._width;
  75. _read_function = std::mem_fn(&this_t::read_text_row);
  76. _skip_function = std::mem_fn(&this_t::skip_text_row);
  77. break;
  78. }
  79. case pnm_image_type::color_asc_t::value:
  80. {
  81. this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
  82. _read_function = std::mem_fn(&this_t::read_text_row);
  83. _skip_function = std::mem_fn(&this_t::skip_text_row);
  84. break;
  85. }
  86. case pnm_image_type::mono_bin_t::value:
  87. {
  88. //gray1_image_t
  89. this->_scanline_length = ( this->_info._width + 7 ) >> 3;
  90. _read_function = std::mem_fn(&this_t::read_binary_bit_row);
  91. _skip_function = std::mem_fn(&this_t::skip_binary_row);
  92. break;
  93. }
  94. case pnm_image_type::gray_bin_t::value:
  95. {
  96. // gray8_image_t
  97. this->_scanline_length = this->_info._width;
  98. _read_function = std::mem_fn(&this_t::read_binary_byte_row);
  99. _skip_function = std::mem_fn(&this_t::skip_binary_row);
  100. break;
  101. }
  102. case pnm_image_type::color_bin_t::value:
  103. {
  104. // rgb8_image_t
  105. this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
  106. _read_function = std::mem_fn(&this_t::read_binary_byte_row);
  107. _skip_function = std::mem_fn(&this_t::skip_binary_row);
  108. break;
  109. }
  110. default: { io_error( "Unsupported pnm file." ); break; }
  111. }
  112. }
  113. void read_text_row( byte_t* dst )
  114. {
  115. for( std::size_t x = 0; x < this->_scanline_length; ++x )
  116. {
  117. for( uint32_t k = 0; ; )
  118. {
  119. int ch = this->_io_dev.getc_unchecked();
  120. if( isdigit( ch ))
  121. {
  122. _text_buffer[ k++ ] = static_cast< char >( ch );
  123. }
  124. else if( k )
  125. {
  126. _text_buffer[ k ] = 0;
  127. break;
  128. }
  129. else if( ch == EOF || !isspace( ch ))
  130. {
  131. return;
  132. }
  133. }
  134. int value = atoi( _text_buffer );
  135. if( this->_info._max_value == 1 )
  136. {
  137. // for pnm format 0 is white
  138. dst[x] = ( value != 0 )
  139. ? 0
  140. : 255;
  141. }
  142. else
  143. {
  144. dst[x] = static_cast< byte_t >( value );
  145. }
  146. }
  147. }
  148. void skip_text_row()
  149. {
  150. for( std::size_t x = 0; x < this->_scanline_length; ++x )
  151. {
  152. for( uint32_t k = 0; ; )
  153. {
  154. int ch = this->_io_dev.getc_unchecked();
  155. if( isdigit( ch ))
  156. {
  157. k++;
  158. }
  159. else if( k )
  160. {
  161. break;
  162. }
  163. else if( ch == EOF || !isspace( ch ))
  164. {
  165. return;
  166. }
  167. }
  168. }
  169. }
  170. void read_binary_bit_row( byte_t* dst )
  171. {
  172. this->_io_dev.read( dst
  173. , this->_scanline_length
  174. );
  175. _negate_bits ( dst, this->_scanline_length );
  176. _swap_half_bytes( dst, this->_scanline_length );
  177. }
  178. void read_binary_byte_row( byte_t* dst )
  179. {
  180. this->_io_dev.read( dst
  181. , this->_scanline_length
  182. );
  183. }
  184. void skip_binary_row()
  185. {
  186. this->_io_dev.seek( static_cast<long>( this->_scanline_length ), SEEK_CUR );
  187. }
  188. private:
  189. char _text_buffer[16];
  190. // For bit_aligned images we need to negate all bytes in the row_buffer
  191. // to make sure that 0 is black and 255 is white.
  192. detail::negate_bits<std::vector<byte_t>, std::true_type> _negate_bits;
  193. detail::swap_half_bytes<std::vector<byte_t>, std::true_type> _swap_half_bytes;
  194. std::function<void(this_t*, byte_t*)> _read_function;
  195. std::function<void(this_t*)> _skip_function;
  196. };
  197. } // namespace gil
  198. } // namespace boost
  199. #endif