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