read.hpp 13 KB

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