read.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  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_READ_HPP
  9. #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_READ_HPP
  10. #include <boost/gil/extension/io/pnm/tags.hpp>
  11. #include <boost/gil/extension/io/pnm/detail/reader_backend.hpp>
  12. #include <boost/gil/extension/io/pnm/detail/is_allowed.hpp>
  13. #include <boost/gil.hpp> // FIXME: Include what you use!
  14. #include <boost/gil/io/base.hpp>
  15. #include <boost/gil/io/bit_operations.hpp>
  16. #include <boost/gil/io/conversion_policies.hpp>
  17. #include <boost/gil/io/device.hpp>
  18. #include <boost/gil/io/dynamic_io_new.hpp>
  19. #include <boost/gil/io/reader_base.hpp>
  20. #include <boost/gil/io/row_buffer_helper.hpp>
  21. #include <boost/gil/io/typedefs.hpp>
  22. #include <type_traits>
  23. #include <vector>
  24. namespace boost { namespace gil {
  25. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  26. #pragma warning(push)
  27. #pragma warning(disable:4512) //assignment operator could not be generated
  28. #endif
  29. ///
  30. /// PNM Reader
  31. ///
  32. template< typename Device
  33. , typename ConversionPolicy
  34. >
  35. class reader< Device
  36. , pnm_tag
  37. , ConversionPolicy
  38. >
  39. : public reader_base< pnm_tag
  40. , ConversionPolicy
  41. >
  42. , public reader_backend< Device
  43. , pnm_tag
  44. >
  45. {
  46. private:
  47. using this_t = reader<Device, pnm_tag, ConversionPolicy>;
  48. using cc_t = typename ConversionPolicy::color_converter_type;
  49. public:
  50. using backend_t = reader_backend<Device, pnm_tag>;
  51. reader( const Device& io_dev
  52. , const image_read_settings< pnm_tag >& settings
  53. )
  54. : reader_base< pnm_tag
  55. , ConversionPolicy
  56. >()
  57. , backend_t( io_dev
  58. , settings
  59. )
  60. {}
  61. reader( const Device& io_dev
  62. , const cc_t& cc
  63. , const image_read_settings< pnm_tag >& settings
  64. )
  65. : reader_base< pnm_tag
  66. , ConversionPolicy
  67. >( cc )
  68. , backend_t( io_dev
  69. , settings
  70. )
  71. {}
  72. template<typename View>
  73. void apply( const View& view )
  74. {
  75. using is_read_and_convert_t = typename is_same
  76. <
  77. ConversionPolicy,
  78. detail::read_and_no_convert
  79. >::type;
  80. io_error_if( !detail::is_allowed< View >( this->_info
  81. , is_read_and_convert_t()
  82. )
  83. , "Image types aren't compatible."
  84. );
  85. switch( this->_info._type )
  86. {
  87. // reading mono text is reading grayscale but with only two values
  88. case pnm_image_type::mono_asc_t::value:
  89. case pnm_image_type::gray_asc_t::value:
  90. {
  91. this->_scanline_length = this->_info._width;
  92. read_text_data< gray8_view_t >( view );
  93. break;
  94. }
  95. case pnm_image_type::color_asc_t::value:
  96. {
  97. this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
  98. read_text_data< rgb8_view_t >( view );
  99. break;
  100. }
  101. case pnm_image_type::mono_bin_t::value:
  102. {
  103. //gray1_image_t
  104. this->_scanline_length = ( this->_info._width + 7 ) >> 3;
  105. read_bin_data< gray1_image_t::view_t >( view );
  106. break;
  107. }
  108. case pnm_image_type::gray_bin_t::value:
  109. {
  110. // gray8_image_t
  111. this->_scanline_length = this->_info._width;
  112. read_bin_data< gray8_view_t >( view );
  113. break;
  114. }
  115. case pnm_image_type::color_bin_t::value:
  116. {
  117. // rgb8_image_t
  118. this->_scanline_length = this->_info._width * num_channels< rgb8_view_t >::value;
  119. read_bin_data< rgb8_view_t >( view );
  120. break;
  121. }
  122. }
  123. }
  124. private:
  125. template< typename View_Src
  126. , typename View_Dst
  127. >
  128. void read_text_data( const View_Dst& dst )
  129. {
  130. using y_t = typename View_Dst::y_coord_t;
  131. byte_vector_t row( this->_scanline_length );
  132. //Skip scanlines if necessary.
  133. for( int y = 0; y < this->_settings._top_left.y; ++y )
  134. {
  135. read_text_row< View_Src >( dst, row, y, false );
  136. }
  137. for( y_t y = 0; y < dst.height(); ++y )
  138. {
  139. read_text_row< View_Src >( dst, row, y, true );
  140. }
  141. }
  142. template< typename View_Src
  143. , typename View_Dst
  144. >
  145. void read_text_row( const View_Dst& dst
  146. , byte_vector_t& row
  147. , typename View_Dst::y_coord_t y
  148. , bool process
  149. )
  150. {
  151. View_Src src = interleaved_view( this->_info._width
  152. , 1
  153. , (typename View_Src::value_type*) &row.front()
  154. , this->_scanline_length
  155. );
  156. for( uint32_t x = 0; x < this->_scanline_length; ++x )
  157. {
  158. for( uint32_t k = 0; ; )
  159. {
  160. int ch = this->_io_dev.getc_unchecked();
  161. if( isdigit( ch ))
  162. {
  163. buf[ k++ ] = static_cast< char >( ch );
  164. }
  165. else if( k )
  166. {
  167. buf[ k ] = 0;
  168. break;
  169. }
  170. else if( ch == EOF || !isspace( ch ))
  171. {
  172. return;
  173. }
  174. }
  175. if( process )
  176. {
  177. int value = atoi( buf );
  178. if( this->_info._max_value == 1 )
  179. {
  180. using channel_t = typename channel_type<typename get_pixel_type<View_Dst>::type>::type;
  181. // for pnm format 0 is white
  182. row[x] = ( value != 0 )
  183. ? typename channel_traits< channel_t >::value_type( 0 )
  184. : channel_traits< channel_t >::max_value();
  185. }
  186. else
  187. {
  188. row[x] = static_cast< byte_t >( value );
  189. }
  190. }
  191. }
  192. if( process )
  193. {
  194. // We are reading a gray1_image like a gray8_image but the two pixel_t
  195. // aren't compatible. Though, read_and_no_convert::read(...) wont work.
  196. copy_data< View_Dst
  197. , View_Src >( dst
  198. , src
  199. , y
  200. , typename is_same< View_Dst
  201. , gray1_image_t::view_t
  202. >::type()
  203. );
  204. }
  205. }
  206. template< typename View_Dst
  207. , typename View_Src
  208. >
  209. void copy_data( const View_Dst& dst
  210. , const View_Src& src
  211. , typename View_Dst::y_coord_t y
  212. , mpl::true_ // is gray1_view
  213. )
  214. {
  215. if( this->_info._max_value == 1 )
  216. {
  217. typename View_Dst::x_iterator it = dst.row_begin( y );
  218. for( typename View_Dst::x_coord_t x = 0
  219. ; x < dst.width()
  220. ; ++x
  221. )
  222. {
  223. it[x] = src[x];
  224. }
  225. }
  226. else
  227. {
  228. copy_data( dst
  229. , src
  230. , y
  231. , mpl::false_()
  232. );
  233. }
  234. }
  235. template< typename View_Dst
  236. , typename View_Src
  237. >
  238. void copy_data( const View_Dst& view
  239. , const View_Src& src
  240. , typename View_Dst::y_coord_t y
  241. , mpl::false_ // is gray1_view
  242. )
  243. {
  244. typename View_Src::x_iterator beg = src.row_begin( 0 ) + this->_settings._top_left.x;
  245. typename View_Src::x_iterator end = beg + this->_settings._dim.x;
  246. this->_cc_policy.read( beg
  247. , end
  248. , view.row_begin( y )
  249. );
  250. }
  251. template< typename View_Src
  252. , typename View_Dst
  253. >
  254. void read_bin_data( const View_Dst& view )
  255. {
  256. using y_t = typename View_Dst::y_coord_t;
  257. using is_bit_aligned_t = typename is_bit_aligned<typename View_Src::value_type>::type;
  258. using rh_t = detail::row_buffer_helper_view<View_Src>;
  259. rh_t rh( this->_scanline_length, true );
  260. typename rh_t::iterator_t beg = rh.begin() + this->_settings._top_left.x;
  261. typename rh_t::iterator_t end = beg + this->_settings._dim.x;
  262. // For bit_aligned images we need to negate all bytes in the row_buffer
  263. // to make sure that 0 is black and 255 is white.
  264. detail::negate_bits
  265. <
  266. typename rh_t::buffer_t,
  267. std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
  268. > neg;
  269. detail::swap_half_bytes
  270. <
  271. typename rh_t::buffer_t,
  272. std::integral_constant<bool, is_bit_aligned_t::value> // TODO: Simplify after MPL removal
  273. > swhb;
  274. //Skip scanlines if necessary.
  275. for( y_t y = 0; y < this->_settings._top_left.y; ++y )
  276. {
  277. this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
  278. , this->_scanline_length
  279. );
  280. }
  281. for( y_t y = 0; y < view.height(); ++y )
  282. {
  283. this->_io_dev.read( reinterpret_cast< byte_t* >( rh.data() )
  284. , this->_scanline_length
  285. );
  286. neg( rh.buffer() );
  287. swhb( rh.buffer() );
  288. this->_cc_policy.read( beg
  289. , end
  290. , view.row_begin( y )
  291. );
  292. }
  293. }
  294. private:
  295. char buf[16];
  296. };
  297. namespace detail {
  298. struct pnm_type_format_checker
  299. {
  300. pnm_type_format_checker( pnm_image_type::type type )
  301. : _type( type )
  302. {}
  303. template< typename Image >
  304. bool apply()
  305. {
  306. using is_supported_t = is_read_supported
  307. <
  308. typename get_pixel_type<typename Image::view_t>::type,
  309. pnm_tag
  310. >;
  311. return is_supported_t::_asc_type == _type
  312. || is_supported_t::_bin_type == _type;
  313. }
  314. private:
  315. pnm_image_type::type _type;
  316. };
  317. struct pnm_read_is_supported
  318. {
  319. template< typename View >
  320. struct apply : public is_read_supported< typename get_pixel_type< View >::type
  321. , pnm_tag
  322. >
  323. {};
  324. };
  325. } // namespace detail
  326. ///
  327. /// PNM Dynamic Image Reader
  328. ///
  329. template< typename Device
  330. >
  331. class dynamic_image_reader< Device
  332. , pnm_tag
  333. >
  334. : public reader< Device
  335. , pnm_tag
  336. , detail::read_and_no_convert
  337. >
  338. {
  339. using parent_t = reader
  340. <
  341. Device,
  342. pnm_tag,
  343. detail::read_and_no_convert
  344. >;
  345. public:
  346. dynamic_image_reader( const Device& io_dev
  347. , const image_read_settings< pnm_tag >& settings
  348. )
  349. : parent_t( io_dev
  350. , settings
  351. )
  352. {}
  353. template< typename Images >
  354. void apply( any_image< Images >& images )
  355. {
  356. detail::pnm_type_format_checker format_checker( this->_info._type );
  357. if( !construct_matched( images
  358. , format_checker
  359. ))
  360. {
  361. io_error( "No matching image type between those of the given any_image and that of the file" );
  362. }
  363. else
  364. {
  365. this->init_image( images
  366. , this->_settings
  367. );
  368. detail::dynamic_io_fnobj< detail::pnm_read_is_supported
  369. , parent_t
  370. > op( this );
  371. apply_operation( view( images )
  372. , op
  373. );
  374. }
  375. }
  376. };
  377. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  378. #pragma warning(pop)
  379. #endif
  380. } // gil
  381. } // boost
  382. #endif