read.hpp 14 KB

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