read.hpp 15 KB

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