read.hpp 15 KB

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