read.hpp 13 KB

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