read.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. Copyright 2012 Kenneth Riddile, 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_TARGA_DETAIL_READ_HPP
  9. #define BOOST_GIL_EXTENSION_IO_TARGA_DETAIL_READ_HPP
  10. ////////////////////////////////////////////////////////////////////////////////////////
  11. /// \file
  12. /// \brief
  13. /// \author Kenneth Riddile, Christian Henning \n
  14. ///
  15. /// \date 2012 \n
  16. ///
  17. ////////////////////////////////////////////////////////////////////////////////////////
  18. #include <vector>
  19. #include <boost/gil/extension/io/targa/tags.hpp>
  20. #include <boost/gil/io/base.hpp>
  21. #include <boost/gil/io/bit_operations.hpp>
  22. #include <boost/gil/io/conversion_policies.hpp>
  23. #include <boost/gil/io/row_buffer_helper.hpp>
  24. #include <boost/gil/io/reader_base.hpp>
  25. #include <boost/gil/io/device.hpp>
  26. #include <boost/gil/io/typedefs.hpp>
  27. #include <boost/gil/extension/io/targa/detail/reader_backend.hpp>
  28. #include <boost/gil/extension/io/targa/detail/is_allowed.hpp>
  29. namespace boost { namespace gil {
  30. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  31. #pragma warning(push)
  32. #pragma warning(disable:4512) //assignment operator could not be generated
  33. #endif
  34. ///
  35. /// Targa Reader
  36. ///
  37. template< typename Device
  38. , typename ConversionPolicy
  39. >
  40. class reader< Device
  41. , targa_tag
  42. , ConversionPolicy
  43. >
  44. : public reader_base< targa_tag
  45. , ConversionPolicy
  46. >
  47. , public reader_backend< Device
  48. , targa_tag
  49. >
  50. {
  51. private:
  52. typedef reader< Device
  53. , targa_tag
  54. , ConversionPolicy
  55. > this_t;
  56. typedef typename ConversionPolicy::color_converter_type cc_t;
  57. public:
  58. typedef reader_backend< Device, targa_tag > backend_t;
  59. public:
  60. reader( const Device& io_dev
  61. , const image_read_settings< targa_tag >& settings
  62. )
  63. : reader_base< targa_tag
  64. , ConversionPolicy
  65. >()
  66. , backend_t( io_dev
  67. , settings
  68. )
  69. {}
  70. reader( const Device& io_dev
  71. , const cc_t& cc
  72. , const image_read_settings< targa_tag >& settings
  73. )
  74. : reader_base< targa_tag
  75. , ConversionPolicy
  76. >( cc )
  77. , backend_t( io_dev
  78. , settings
  79. )
  80. {}
  81. template< typename View >
  82. void apply( const View& dst_view )
  83. {
  84. typedef typename is_same< ConversionPolicy
  85. , detail::read_and_no_convert
  86. >::type is_read_and_convert_t;
  87. io_error_if( !detail::is_allowed< View >( this->_info, is_read_and_convert_t() )
  88. , "Image types aren't compatible."
  89. );
  90. switch( this->_info._image_type )
  91. {
  92. case targa_image_type::_rgb:
  93. {
  94. if( this->_info._color_map_type != targa_color_map_type::_rgb )
  95. {
  96. io_error( "Inconsistent color map type and image type in targa file." );
  97. }
  98. if( this->_info._color_map_length != 0 )
  99. {
  100. io_error( "Non-indexed targa files containing a palette are not supported." );
  101. }
  102. switch( this->_info._bits_per_pixel )
  103. {
  104. case 24:
  105. {
  106. this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 );
  107. if( this->_info._screen_origin_bit )
  108. {
  109. read_data< bgr8_view_t >( flipped_up_down_view( dst_view ) );
  110. }
  111. else
  112. {
  113. read_data< bgr8_view_t >( dst_view );
  114. }
  115. break;
  116. }
  117. case 32:
  118. {
  119. this->_scanline_length = this->_info._width * ( this->_info._bits_per_pixel / 8 );
  120. if( this->_info._screen_origin_bit )
  121. {
  122. read_data< bgra8_view_t >( flipped_up_down_view( dst_view ) );
  123. }
  124. else
  125. {
  126. read_data< bgra8_view_t >( dst_view );
  127. }
  128. break;
  129. }
  130. default:
  131. {
  132. io_error( "Unsupported bit depth in targa file." );
  133. break;
  134. }
  135. }
  136. break;
  137. }
  138. case targa_image_type::_rle_rgb:
  139. {
  140. if( this->_info._color_map_type != targa_color_map_type::_rgb )
  141. {
  142. io_error( "Inconsistent color map type and image type in targa file." );
  143. }
  144. if( this->_info._color_map_length != 0 )
  145. {
  146. io_error( "Non-indexed targa files containing a palette are not supported." );
  147. }
  148. switch( this->_info._bits_per_pixel )
  149. {
  150. case 24:
  151. {
  152. if( this->_info._screen_origin_bit )
  153. {
  154. read_rle_data< bgr8_view_t >( flipped_up_down_view( dst_view ) );
  155. }
  156. else
  157. {
  158. read_rle_data< bgr8_view_t >( dst_view );
  159. }
  160. break;
  161. }
  162. case 32:
  163. {
  164. if( this->_info._screen_origin_bit )
  165. {
  166. read_rle_data< bgra8_view_t >( flipped_up_down_view( dst_view ) );
  167. }
  168. else
  169. {
  170. read_rle_data< bgra8_view_t >( dst_view );
  171. }
  172. break;
  173. }
  174. default:
  175. {
  176. io_error( "Unsupported bit depth in targa file." );
  177. break;
  178. }
  179. }
  180. break;
  181. }
  182. default:
  183. {
  184. io_error( "Unsupported image type in targa file." );
  185. break;
  186. }
  187. }
  188. }
  189. private:
  190. // 8-8-8 BGR
  191. // 8-8-8-8 BGRA
  192. template< typename View_Src, typename View_Dst >
  193. void read_data( const View_Dst& view )
  194. {
  195. byte_vector_t row( this->_info._width * (this->_info._bits_per_pixel / 8) );
  196. // jump to first scanline
  197. this->_io_dev.seek( static_cast< long >( this->_info._offset ));
  198. View_Src v = interleaved_view( this->_info._width,
  199. 1,
  200. reinterpret_cast<typename View_Src::value_type*>( &row.front() ),
  201. this->_info._width * num_channels< View_Src >::value
  202. );
  203. typename View_Src::x_iterator beg = v.row_begin( 0 ) + this->_settings._top_left.x;
  204. typename View_Src::x_iterator end = beg + this->_settings._dim.x;
  205. // read bottom up since targa origin is bottom left
  206. for( std::ptrdiff_t y = this->_settings._dim.y - 1; y > -1; --y )
  207. {
  208. // @todo: For now we're reading the whole scanline which is
  209. // slightly inefficient. Later versions should try to read
  210. // only the bytes which are necessary.
  211. this->_io_dev.read( &row.front(), row.size() );
  212. this->_cc_policy.read( beg, end, view.row_begin(y) );
  213. }
  214. }
  215. // 8-8-8 BGR
  216. // 8-8-8-8 BGRA
  217. template< typename View_Src, typename View_Dst >
  218. void read_rle_data( const View_Dst& view )
  219. {
  220. targa_depth::type bytes_per_pixel = this->_info._bits_per_pixel / 8;
  221. size_t image_size = this->_info._width * this->_info._height * bytes_per_pixel;
  222. byte_vector_t image_data( image_size );
  223. this->_io_dev.seek( static_cast< long >( this->_info._offset ));
  224. for( size_t pixel = 0; pixel < image_size; )
  225. {
  226. targa_offset::type current_byte = this->_io_dev.read_uint8();
  227. if( current_byte & 0x80 ) // run length chunk (high bit = 1)
  228. {
  229. uint8_t chunk_length = current_byte - 127;
  230. uint8_t pixel_data[4];
  231. for( size_t channel = 0; channel < bytes_per_pixel; ++channel )
  232. {
  233. pixel_data[channel] = this->_io_dev.read_uint8();
  234. }
  235. // Repeat the next pixel chunk_length times
  236. for( uint8_t i = 0; i < chunk_length; ++i, pixel += bytes_per_pixel )
  237. {
  238. memcpy( &image_data[pixel], pixel_data, bytes_per_pixel );
  239. }
  240. }
  241. else // raw chunk
  242. {
  243. uint8_t chunk_length = current_byte + 1;
  244. // Write the next chunk_length pixels directly
  245. size_t pixels_written = chunk_length * bytes_per_pixel;
  246. this->_io_dev.read( &image_data[pixel], pixels_written );
  247. pixel += pixels_written;
  248. }
  249. }
  250. View_Src v = flipped_up_down_view( interleaved_view( this->_info._width,
  251. this->_info._height,
  252. reinterpret_cast<typename View_Src::value_type*>( &image_data.front() ),
  253. this->_info._width * num_channels< View_Src >::value ) );
  254. for( std::ptrdiff_t y = 0; y != this->_settings._dim.y; ++y )
  255. {
  256. typename View_Src::x_iterator beg = v.row_begin( y ) + this->_settings._top_left.x;
  257. typename View_Src::x_iterator end = beg + this->_settings._dim.x;
  258. this->_cc_policy.read( beg, end, view.row_begin(y) );
  259. }
  260. }
  261. };
  262. namespace detail {
  263. class targa_type_format_checker
  264. {
  265. public:
  266. targa_type_format_checker( const targa_depth::type& bpp )
  267. : _bpp( bpp )
  268. {}
  269. template< typename Image >
  270. bool apply()
  271. {
  272. if( _bpp < 32 )
  273. {
  274. return pixels_are_compatible< typename Image::value_type, rgb8_pixel_t >::value
  275. ? true
  276. : false;
  277. }
  278. else
  279. {
  280. return pixels_are_compatible< typename Image::value_type, rgba8_pixel_t >::value
  281. ? true
  282. : false;
  283. }
  284. }
  285. private:
  286. // to avoid C4512
  287. targa_type_format_checker& operator=( const targa_type_format_checker& ) { return *this; }
  288. private:
  289. const targa_depth::type _bpp;
  290. };
  291. struct targa_read_is_supported
  292. {
  293. template< typename View >
  294. struct apply : public is_read_supported< typename get_pixel_type< View >::type
  295. , targa_tag
  296. >
  297. {};
  298. };
  299. } // namespace detail
  300. ///
  301. /// Targa Dynamic Image Reader
  302. ///
  303. template< typename Device >
  304. class dynamic_image_reader< Device
  305. , targa_tag
  306. >
  307. : public reader< Device
  308. , targa_tag
  309. , detail::read_and_no_convert
  310. >
  311. {
  312. typedef reader< Device
  313. , targa_tag
  314. , detail::read_and_no_convert
  315. > parent_t;
  316. public:
  317. dynamic_image_reader( const Device& io_dev
  318. , const image_read_settings< targa_tag >& settings
  319. )
  320. : parent_t( io_dev
  321. , settings
  322. )
  323. {}
  324. template< typename Images >
  325. void apply( any_image< Images >& images )
  326. {
  327. detail::targa_type_format_checker format_checker( this->_info._bits_per_pixel );
  328. if( !construct_matched( images
  329. , format_checker
  330. ))
  331. {
  332. io_error( "No matching image type between those of the given any_image and that of the file" );
  333. }
  334. else
  335. {
  336. this->init_image( images
  337. , this->_settings
  338. );
  339. detail::dynamic_io_fnobj< detail::targa_read_is_supported
  340. , parent_t
  341. > op( this );
  342. apply_operation( view( images )
  343. , op
  344. );
  345. }
  346. }
  347. };
  348. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  349. #pragma warning(pop)
  350. #endif
  351. } // namespace gil
  352. } // namespace boost
  353. #endif