read.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. //
  2. // Copyright 2007-2012 Christian Henning, Andreas Pokorny, Lubomir Bourdev
  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_PNG_DETAIL_READ_HPP
  9. #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_READ_HPP
  10. #include <boost/gil/extension/io/png/tags.hpp>
  11. #include <boost/gil/extension/io/png/detail/reader_backend.hpp>
  12. #include <boost/gil/extension/io/png/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/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. namespace boost { namespace gil {
  22. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  23. #pragma warning(push)
  24. #pragma warning(disable:4512) //assignment operator could not be generated
  25. #endif
  26. ///
  27. /// PNG Reader
  28. ///
  29. template< typename Device
  30. , typename ConversionPolicy
  31. >
  32. class reader< Device
  33. , png_tag
  34. , ConversionPolicy
  35. >
  36. : public reader_base< png_tag
  37. , ConversionPolicy >
  38. , public reader_backend< Device
  39. , png_tag
  40. >
  41. {
  42. private:
  43. using this_t = reader<Device, png_tag, ConversionPolicy>;
  44. using cc_t = typename ConversionPolicy::color_converter_type;
  45. public:
  46. using backend_t = reader_backend<Device, png_tag>;
  47. public:
  48. reader( const Device& io_dev
  49. , const image_read_settings< png_tag >& settings
  50. )
  51. : reader_base< png_tag
  52. , ConversionPolicy
  53. >()
  54. , backend_t( io_dev
  55. , settings
  56. )
  57. {}
  58. reader( const Device& io_dev
  59. , const typename ConversionPolicy::color_converter_type& cc
  60. , const image_read_settings< png_tag >& settings
  61. )
  62. : reader_base< png_tag
  63. , ConversionPolicy
  64. >( cc )
  65. , backend_t( io_dev
  66. , settings
  67. )
  68. {}
  69. template< typename View >
  70. void apply( const View& view )
  71. {
  72. // The info structures are filled at this point.
  73. // Now it's time for some transformations.
  74. if( little_endian() )
  75. {
  76. if( this->_info._bit_depth == 16 )
  77. {
  78. // Swap bytes of 16 bit files to least significant byte first.
  79. png_set_swap( this->get_struct() );
  80. }
  81. if( this->_info._bit_depth < 8 )
  82. {
  83. // swap bits of 1, 2, 4 bit packed pixel formats
  84. png_set_packswap( this->get_struct() );
  85. }
  86. }
  87. if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE )
  88. {
  89. png_set_palette_to_rgb( this->get_struct() );
  90. }
  91. if( png_get_valid( this->get_struct(), this->get_info(), PNG_INFO_tRNS ) )
  92. {
  93. png_set_tRNS_to_alpha( this->get_struct() );
  94. }
  95. // Tell libpng to handle the gamma conversion for you. The final call
  96. // is a good guess for PC generated images, but it should be configurable
  97. // by the user at run time by the user. It is strongly suggested that
  98. // your application support gamma correction.
  99. if( this->_settings._apply_screen_gamma )
  100. {
  101. // png_set_gamma will change the image data!
  102. #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  103. png_set_gamma( this->get_struct()
  104. , this->_settings._screen_gamma
  105. , this->_info._file_gamma
  106. );
  107. #else
  108. png_set_gamma( this->get_struct()
  109. , this->_settings._screen_gamma
  110. , this->_info._file_gamma
  111. );
  112. #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  113. }
  114. // Turn on interlace handling. REQUIRED if you are not using
  115. // png_read_image(). To see how to handle interlacing passes,
  116. // see the png_read_row() method below:
  117. this->_number_passes = png_set_interlace_handling( this->get_struct() );
  118. // The above transformation might have changed the bit_depth and color type.
  119. png_read_update_info( this->get_struct()
  120. , this->get_info()
  121. );
  122. this->_info._bit_depth = png_get_bit_depth( this->get_struct()
  123. , this->get_info()
  124. );
  125. this->_info._num_channels = png_get_channels( this->get_struct()
  126. , this->get_info()
  127. );
  128. this->_info._color_type = png_get_color_type( this->get_struct()
  129. , this->get_info()
  130. );
  131. this->_scanline_length = png_get_rowbytes( this->get_struct()
  132. , this->get_info()
  133. );
  134. switch( this->_info._color_type )
  135. {
  136. case PNG_COLOR_TYPE_GRAY:
  137. {
  138. switch( this->_info._bit_depth )
  139. {
  140. case 1: read_rows< gray1_image_t::view_t::reference >( view ); break;
  141. case 2: read_rows< gray2_image_t::view_t::reference >( view ); break;
  142. case 4: read_rows< gray4_image_t::view_t::reference >( view ); break;
  143. case 8: read_rows< gray8_pixel_t >( view ); break;
  144. case 16: read_rows< gray16_pixel_t >( view ); break;
  145. default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
  146. }
  147. break;
  148. }
  149. case PNG_COLOR_TYPE_GA:
  150. {
  151. #ifdef BOOST_GIL_IO_ENABLE_GRAY_ALPHA
  152. switch( this->_info._bit_depth )
  153. {
  154. case 8: read_rows< gray_alpha8_pixel_t > ( view ); break;
  155. case 16: read_rows< gray_alpha16_pixel_t >( view ); break;
  156. default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
  157. }
  158. #else
  159. io_error( "gray_alpha isn't enabled. Use ENABLE_GRAY_ALPHA when building application." );
  160. #endif // BOOST_GIL_IO_ENABLE_GRAY_ALPHA
  161. break;
  162. }
  163. case PNG_COLOR_TYPE_RGB:
  164. {
  165. switch( this->_info._bit_depth )
  166. {
  167. case 8: read_rows< rgb8_pixel_t > ( view ); break;
  168. case 16: read_rows< rgb16_pixel_t >( view ); break;
  169. default: io_error( "png_reader::read_data(): unknown combination of color type and bit depth" );
  170. }
  171. break;
  172. }
  173. case PNG_COLOR_TYPE_RGBA:
  174. {
  175. switch( this->_info._bit_depth )
  176. {
  177. case 8: read_rows< rgba8_pixel_t > ( view ); break;
  178. case 16: read_rows< rgba16_pixel_t >( view ); break;
  179. default: io_error( "png_reader_color_convert::read_data(): unknown combination of color type and bit depth" );
  180. }
  181. break;
  182. }
  183. default: io_error( "png_reader_color_convert::read_data(): unknown color type" );
  184. }
  185. // read rest of file, and get additional chunks in info_ptr
  186. png_read_end( this->get_struct()
  187. , nullptr
  188. );
  189. }
  190. private:
  191. template< typename ImagePixel
  192. , typename View
  193. >
  194. void read_rows( const View& view )
  195. {
  196. using row_buffer_helper_t = detail::row_buffer_helper_view<ImagePixel>;
  197. using it_t = typename row_buffer_helper_t::iterator_t;
  198. using is_read_and_convert_t = typename is_same
  199. <
  200. ConversionPolicy,
  201. detail::read_and_no_convert
  202. >::type;
  203. io_error_if( !detail::is_allowed< View >( this->_info
  204. , is_read_and_convert_t()
  205. )
  206. , "Image types aren't compatible."
  207. );
  208. std::size_t rowbytes = png_get_rowbytes( this->get_struct()
  209. , this->get_info()
  210. );
  211. row_buffer_helper_t buffer( rowbytes
  212. , true
  213. );
  214. png_bytep row_ptr = (png_bytep)( &( buffer.data()[0]));
  215. for( std::size_t pass = 0; pass < this->_number_passes; pass++ )
  216. {
  217. if( pass == this->_number_passes - 1 )
  218. {
  219. // skip lines if necessary
  220. for( std::ptrdiff_t y = 0; y < this->_settings._top_left.y; ++y )
  221. {
  222. // Read the image using the "sparkle" effect.
  223. png_read_rows( this->get_struct()
  224. , &row_ptr
  225. , nullptr
  226. , 1
  227. );
  228. }
  229. for( std::ptrdiff_t y = 0
  230. ; y < this->_settings._dim.y
  231. ; ++y
  232. )
  233. {
  234. // Read the image using the "sparkle" effect.
  235. png_read_rows( this->get_struct()
  236. , &row_ptr
  237. , nullptr
  238. , 1
  239. );
  240. it_t first = buffer.begin() + this->_settings._top_left.x;
  241. it_t last = first + this->_settings._dim.x; // one after last element
  242. this->_cc_policy.read( first
  243. , last
  244. , view.row_begin( y ));
  245. }
  246. // Read the rest of the image. libpng needs that.
  247. std::ptrdiff_t remaining_rows = static_cast< std::ptrdiff_t >( this->_info._height )
  248. - this->_settings._top_left.y
  249. - this->_settings._dim.y;
  250. for( std::ptrdiff_t y = 0
  251. ; y < remaining_rows
  252. ; ++y
  253. )
  254. {
  255. // Read the image using the "sparkle" effect.
  256. png_read_rows( this->get_struct()
  257. , &row_ptr
  258. , nullptr
  259. , 1
  260. );
  261. }
  262. }
  263. else
  264. {
  265. for( int y = 0; y < view.height(); ++y )
  266. {
  267. // Read the image using the "sparkle" effect.
  268. png_read_rows( this->get_struct()
  269. , &row_ptr
  270. , nullptr
  271. , 1
  272. );
  273. }
  274. }
  275. }
  276. }
  277. };
  278. namespace detail {
  279. struct png_type_format_checker
  280. {
  281. png_type_format_checker( png_bitdepth::type bit_depth
  282. , png_color_type::type color_type
  283. )
  284. : _bit_depth ( bit_depth )
  285. , _color_type( color_type )
  286. {}
  287. template< typename Image >
  288. bool apply()
  289. {
  290. using is_supported_t = is_read_supported
  291. <
  292. typename get_pixel_type<typename Image::view_t>::type,
  293. png_tag
  294. >;
  295. return is_supported_t::_bit_depth == _bit_depth
  296. && is_supported_t::_color_type == _color_type;
  297. }
  298. private:
  299. png_bitdepth::type _bit_depth;
  300. png_color_type::type _color_type;
  301. };
  302. struct png_read_is_supported
  303. {
  304. template< typename View >
  305. struct apply : public is_read_supported< typename get_pixel_type< View >::type
  306. , png_tag
  307. >
  308. {};
  309. };
  310. } // namespace detail
  311. ///
  312. /// PNG Dynamic Image Reader
  313. ///
  314. template< typename Device
  315. >
  316. class dynamic_image_reader< Device
  317. , png_tag
  318. >
  319. : public reader< Device
  320. , png_tag
  321. , detail::read_and_no_convert
  322. >
  323. {
  324. using parent_t = reader
  325. <
  326. Device,
  327. png_tag,
  328. detail::read_and_no_convert
  329. >;
  330. public:
  331. dynamic_image_reader( const Device& io_dev
  332. , const image_read_settings< png_tag >& settings
  333. )
  334. : parent_t( io_dev
  335. , settings
  336. )
  337. {}
  338. template< typename Images >
  339. void apply( any_image< Images >& images )
  340. {
  341. detail::png_type_format_checker format_checker( this->_info._bit_depth
  342. , this->_info._color_type
  343. );
  344. if( !construct_matched( images
  345. , format_checker
  346. ))
  347. {
  348. io_error( "No matching image type between those of the given any_image and that of the file" );
  349. }
  350. else
  351. {
  352. this->init_image( images
  353. , this->_settings
  354. );
  355. detail::dynamic_io_fnobj< detail::png_read_is_supported
  356. , parent_t
  357. > op( this );
  358. apply_operation( view( images )
  359. , op
  360. );
  361. }
  362. }
  363. };
  364. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  365. #pragma warning(pop)
  366. #endif
  367. } // namespace gil
  368. } // namespace boost
  369. #endif