reader_backend.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. //
  2. // Copyright 2012 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_DETAIL_READER_BACKEND_HPP
  9. #define BOOST_GIL_EXTENSION_IO_DETAIL_READER_BACKEND_HPP
  10. #include <boost/gil/extension/io/png/tags.hpp>
  11. #include <boost/gil/extension/io/png/detail/base.hpp>
  12. #include <boost/gil/extension/io/png/detail/supported_types.hpp>
  13. namespace boost { namespace gil {
  14. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  15. #pragma warning(push)
  16. #pragma warning(disable:4512) //assignment operator could not be generated
  17. #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
  18. #endif
  19. ///
  20. /// PNG Backend
  21. ///
  22. template<typename Device >
  23. struct reader_backend< Device
  24. , png_tag
  25. >
  26. : public detail::png_struct_info_wrapper
  27. {
  28. public:
  29. using format_tag_t = png_tag;
  30. using this_t = reader_backend<Device, png_tag>;
  31. public:
  32. reader_backend( const Device& io_dev
  33. , const image_read_settings< png_tag >& settings
  34. )
  35. : _io_dev( io_dev )
  36. , _settings( settings )
  37. , _info()
  38. , _scanline_length( 0 )
  39. , _number_passes( 0 )
  40. {
  41. read_header();
  42. if( _settings._dim.x == 0 )
  43. {
  44. _settings._dim.x = _info._width;
  45. }
  46. if( _settings._dim.y == 0 )
  47. {
  48. _settings._dim.y = _info._height;
  49. }
  50. }
  51. void read_header()
  52. {
  53. using boost::gil::detail::PNG_BYTES_TO_CHECK;
  54. // check the file's first few bytes
  55. byte_t buf[PNG_BYTES_TO_CHECK];
  56. io_error_if( _io_dev.read( buf
  57. , PNG_BYTES_TO_CHECK
  58. ) != PNG_BYTES_TO_CHECK
  59. , "png_check_validity: failed to read image"
  60. );
  61. io_error_if( png_sig_cmp( png_bytep(buf)
  62. , png_size_t(0)
  63. , PNG_BYTES_TO_CHECK
  64. ) != 0
  65. , "png_check_validity: invalid png image"
  66. );
  67. // Create and initialize the png_struct with the desired error handler
  68. // functions. If you want to use the default stderr and longjump method,
  69. // you can supply NULL for the last three parameters. We also supply the
  70. // the compiler header file version, so that we know if the application
  71. // was compiled with a compatible version of the library. REQUIRED
  72. get()->_struct = png_create_read_struct( PNG_LIBPNG_VER_STRING
  73. , nullptr // user_error_ptr
  74. , nullptr // user_error_fn
  75. , nullptr // user_warning_fn
  76. );
  77. io_error_if( get()->_struct == nullptr
  78. , "png_reader: fail to call png_create_write_struct()"
  79. );
  80. png_uint_32 user_chunk_data[4];
  81. user_chunk_data[0] = 0;
  82. user_chunk_data[1] = 0;
  83. user_chunk_data[2] = 0;
  84. user_chunk_data[3] = 0;
  85. png_set_read_user_chunk_fn( get_struct()
  86. , user_chunk_data
  87. , this_t::read_user_chunk_callback
  88. );
  89. // Allocate/initialize the memory for image information. REQUIRED.
  90. get()->_info = png_create_info_struct( get_struct() );
  91. if( get_info() == nullptr )
  92. {
  93. png_destroy_read_struct( &get()->_struct
  94. , nullptr
  95. , nullptr
  96. );
  97. io_error( "png_reader: fail to call png_create_info_struct()" );
  98. }
  99. // Set error handling if you are using the setjmp/longjmp method (this is
  100. // the normal method of doing things with libpng). REQUIRED unless you
  101. // set up your own error handlers in the png_create_read_struct() earlier.
  102. if( setjmp( png_jmpbuf( get_struct() )))
  103. {
  104. //free all of the memory associated with the png_ptr and info_ptr
  105. png_destroy_read_struct( &get()->_struct
  106. , &get()->_info
  107. , nullptr
  108. );
  109. io_error( "png is invalid" );
  110. }
  111. png_set_read_fn( get_struct()
  112. , static_cast< png_voidp >( &this->_io_dev )
  113. , this_t::read_data
  114. );
  115. // Set up a callback function that will be
  116. // called after each row has been read, which you can use to control
  117. // a progress meter or the like.
  118. png_set_read_status_fn( get_struct()
  119. , this_t::read_row_callback
  120. );
  121. // Set up a callback which implements user defined transformation.
  122. // @todo
  123. png_set_read_user_transform_fn( get_struct()
  124. , png_user_transform_ptr( nullptr )
  125. );
  126. png_set_keep_unknown_chunks( get_struct()
  127. , PNG_HANDLE_CHUNK_ALWAYS
  128. , nullptr
  129. , 0
  130. );
  131. // Make sure we read the signature.
  132. // @todo make it an option
  133. png_set_sig_bytes( get_struct()
  134. , PNG_BYTES_TO_CHECK
  135. );
  136. // The call to png_read_info() gives us all of the information from the
  137. // PNG file before the first IDAT (image data chunk). REQUIRED
  138. png_read_info( get_struct()
  139. , get_info()
  140. );
  141. ///
  142. /// Start reading the image information
  143. ///
  144. // get PNG_IHDR chunk information from png_info structure
  145. png_get_IHDR( get_struct()
  146. , get_info()
  147. , &this->_info._width
  148. , &this->_info._height
  149. , &this->_info._bit_depth
  150. , &this->_info._color_type
  151. , &this->_info._interlace_method
  152. , &this->_info._compression_method
  153. , &this->_info._filter_method
  154. );
  155. // get number of color channels in image
  156. this->_info._num_channels = png_get_channels( get_struct()
  157. , get_info()
  158. );
  159. #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  160. // Get CIE chromacities and referenced white point
  161. if( this->_settings._read_cie_chromacities )
  162. {
  163. this->_info._valid_cie_colors = png_get_cHRM( get_struct()
  164. , get_info()
  165. , &this->_info._white_x, &this->_info._white_y
  166. , &this->_info._red_x, &this->_info._red_y
  167. , &this->_info._green_x, &this->_info._green_y
  168. , &this->_info._blue_x, &this->_info._blue_y
  169. );
  170. }
  171. // get the gamma value
  172. if( this->_settings._read_file_gamma )
  173. {
  174. this->_info._valid_file_gamma = png_get_gAMA( get_struct()
  175. , get_info()
  176. , &this->_info._file_gamma
  177. );
  178. if( this->_info._valid_file_gamma == false )
  179. {
  180. this->_info._file_gamma = 1.0;
  181. }
  182. }
  183. #else
  184. // Get CIE chromacities and referenced white point
  185. if( this->_settings._read_cie_chromacities )
  186. {
  187. this->_info._valid_cie_colors = png_get_cHRM_fixed( get_struct()
  188. , get_info()
  189. , &this->_info._white_x, &this->_info._white_y
  190. , &this->_info._red_x, &this->_info._red_y
  191. , &this->_info._green_x, &this->_info._green_y
  192. , &this->_info._blue_x, &this->_info._blue_y
  193. );
  194. }
  195. // get the gamma value
  196. if( this->_settings._read_file_gamma )
  197. {
  198. this->_info._valid_file_gamma = png_get_gAMA_fixed( get_struct()
  199. , get_info()
  200. , &this->_info._file_gamma
  201. );
  202. if( this->_info._valid_file_gamma == false )
  203. {
  204. this->_info._file_gamma = 1;
  205. }
  206. }
  207. #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  208. // get the embedded ICC profile data
  209. if( this->_settings._read_icc_profile )
  210. {
  211. #if PNG_LIBPNG_VER_MINOR >= 5
  212. png_charp icc_name = png_charp( nullptr );
  213. png_bytep profile = png_bytep( nullptr );
  214. this->_info._valid_icc_profile = png_get_iCCP( get_struct()
  215. , get_info()
  216. , &icc_name
  217. , &this->_info._iccp_compression_type
  218. , &profile
  219. , &this->_info._profile_length
  220. );
  221. #else
  222. png_charp icc_name = png_charp( NULL );
  223. png_charp profile = png_charp( NULL );
  224. this->_info._valid_icc_profile = png_get_iCCP( get_struct()
  225. , get_info()
  226. , &icc_name
  227. , &this->_info._iccp_compression_type
  228. , &profile
  229. , &this->_info._profile_length
  230. );
  231. #endif
  232. if( icc_name )
  233. {
  234. this->_info._icc_name.append( icc_name
  235. , std::strlen( icc_name )
  236. );
  237. }
  238. if( this->_info._profile_length != 0 )
  239. {
  240. std:: copy_n (profile, this->_info._profile_length, std:: back_inserter (this->_info._profile));
  241. }
  242. }
  243. // get the rendering intent
  244. if( this->_settings._read_intent )
  245. {
  246. this->_info._valid_intent = png_get_sRGB( get_struct()
  247. , get_info()
  248. , &this->_info._intent
  249. );
  250. }
  251. // get image palette information from png_info structure
  252. if( this->_settings._read_palette )
  253. {
  254. png_colorp palette = png_colorp( nullptr );
  255. this->_info._valid_palette = png_get_PLTE( get_struct()
  256. , get_info()
  257. , &palette
  258. , &this->_info._num_palette
  259. );
  260. if( this->_info._num_palette > 0 )
  261. {
  262. this->_info._palette.resize( this->_info._num_palette );
  263. std::copy( palette
  264. , palette + this->_info._num_palette
  265. , &this->_info._palette.front()
  266. );
  267. }
  268. }
  269. // get background color
  270. if( this->_settings._read_background )
  271. {
  272. png_color_16p background = png_color_16p( nullptr );
  273. this->_info._valid_background = png_get_bKGD( get_struct()
  274. , get_info()
  275. , &background
  276. );
  277. if( background )
  278. {
  279. this->_info._background = *background;
  280. }
  281. }
  282. // get the histogram
  283. if( this->_settings._read_histogram )
  284. {
  285. png_uint_16p histogram = png_uint_16p( nullptr );
  286. this->_info._valid_histogram = png_get_hIST( get_struct()
  287. , get_info()
  288. , &histogram
  289. );
  290. if( histogram )
  291. {
  292. // the number of values is set by the number of colors inside
  293. // the palette.
  294. if( this->_settings._read_palette == false )
  295. {
  296. png_colorp palette = png_colorp( nullptr );
  297. png_get_PLTE( get_struct()
  298. , get_info()
  299. , &palette
  300. , &this->_info._num_palette
  301. );
  302. }
  303. std::copy( histogram
  304. , histogram + this->_info._num_palette
  305. , &this->_info._histogram.front()
  306. );
  307. }
  308. }
  309. // get screen offsets for the given image
  310. if( this->_settings._read_screen_offsets )
  311. {
  312. this->_info._valid_offset = png_get_oFFs( get_struct()
  313. , get_info()
  314. , &this->_info._offset_x
  315. , &this->_info._offset_y
  316. , &this->_info._off_unit_type
  317. );
  318. }
  319. // get pixel calibration settings
  320. if( this->_settings._read_pixel_calibration )
  321. {
  322. png_charp purpose = png_charp ( nullptr );
  323. png_charp units = png_charp ( nullptr );
  324. png_charpp params = png_charpp( nullptr );
  325. this->_info._valid_pixel_calibration = png_get_pCAL( get_struct()
  326. , get_info()
  327. , &purpose
  328. , &this->_info._X0
  329. , &this->_info._X1
  330. , &this->_info._cal_type
  331. , &this->_info._num_params
  332. , &units
  333. , &params
  334. );
  335. if( purpose )
  336. {
  337. this->_info._purpose.append( purpose
  338. , std::strlen( purpose )
  339. );
  340. }
  341. if( units )
  342. {
  343. this->_info._units.append( units
  344. , std::strlen( units )
  345. );
  346. }
  347. if( this->_info._num_params > 0 )
  348. {
  349. this->_info._params.resize( this->_info._num_params );
  350. for( png_CAL_nparam::type i = 0
  351. ; i < this->_info._num_params
  352. ; ++i
  353. )
  354. {
  355. this->_info._params[i].append( params[i]
  356. , std::strlen( params[i] )
  357. );
  358. }
  359. }
  360. }
  361. // get the physical resolution
  362. if( this->_settings._read_physical_resolution )
  363. {
  364. this->_info._valid_resolution = png_get_pHYs( get_struct()
  365. , get_info()
  366. , &this->_info._res_x
  367. , &this->_info._res_y
  368. , &this->_info._phy_unit_type
  369. );
  370. }
  371. // get the image resolution in pixels per meter.
  372. if( this->_settings._read_pixels_per_meter )
  373. {
  374. this->_info._pixels_per_meter = png_get_pixels_per_meter( get_struct()
  375. , get_info()
  376. );
  377. }
  378. // get number of significant bits for each color channel
  379. if( this->_settings._read_number_of_significant_bits )
  380. {
  381. png_color_8p sig_bits = png_color_8p( nullptr );
  382. this->_info._valid_significant_bits = png_get_sBIT( get_struct()
  383. , get_info()
  384. , &sig_bits
  385. );
  386. // @todo Is there one or more colors?
  387. if( sig_bits )
  388. {
  389. this->_info._sig_bits = *sig_bits;
  390. }
  391. }
  392. #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER
  393. #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  394. // get physical scale settings
  395. if( this->_settings._read_scale_factors )
  396. {
  397. this->_info._valid_scale_factors = png_get_sCAL( get_struct()
  398. , get_info()
  399. , &this->_info._scale_unit
  400. , &this->_info._scale_width
  401. , &this->_info._scale_height
  402. );
  403. }
  404. #else
  405. #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
  406. if( this->_settings._read_scale_factors )
  407. {
  408. this->_info._valid_scale_factors = png_get_sCAL_fixed( get_struct()
  409. , get_info()
  410. , &this->_info._scale_unit
  411. , &this->_info._scale_width
  412. , &this->_info._scale_height
  413. );
  414. }
  415. #else
  416. if( this->_settings._read_scale_factors )
  417. {
  418. png_charp scale_width = nullptr;
  419. png_charp scale_height = nullptr;
  420. this->_info._valid_scale_factors = png_get_sCAL_s(
  421. get_struct(), get_info(), &this->_info._scale_unit, &scale_width, &scale_height);
  422. if (this->_info._valid_scale_factors)
  423. {
  424. if( scale_width )
  425. {
  426. this->_info._scale_width.append( scale_width
  427. , std::strlen( scale_width )
  428. );
  429. }
  430. if( scale_height )
  431. {
  432. this->_info._scale_height.append( scale_height
  433. , std::strlen( scale_height )
  434. );
  435. }
  436. }
  437. }
  438. #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
  439. #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  440. #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER
  441. // get comments information from png_info structure
  442. if( this->_settings._read_comments )
  443. {
  444. png_textp text = png_textp( nullptr );
  445. this->_info._valid_text = png_get_text( get_struct()
  446. , get_info()
  447. , &text
  448. , &this->_info._num_text
  449. );
  450. if( this->_info._num_text > 0 )
  451. {
  452. this->_info._text.resize( this->_info._num_text );
  453. for( png_num_text::type i = 0
  454. ; i < this->_info._num_text
  455. ; ++i
  456. )
  457. {
  458. this->_info._text[i]._compression = text[i].compression;
  459. this->_info._text[i]._key.append( text[i].key
  460. , std::strlen( text[i].key )
  461. );
  462. this->_info._text[i]._text.append( text[i].text
  463. , std::strlen( text[i].text )
  464. );
  465. }
  466. }
  467. }
  468. // get last modification time
  469. if( this->_settings._read_last_modification_time )
  470. {
  471. png_timep mod_time = png_timep( nullptr );
  472. this->_info._valid_modification_time = png_get_tIME( get_struct()
  473. , get_info()
  474. , &mod_time
  475. );
  476. if( mod_time )
  477. {
  478. this->_info._mod_time = *mod_time;
  479. }
  480. }
  481. // get transparency data
  482. if( this->_settings._read_transparency_data )
  483. {
  484. png_bytep trans = png_bytep ( nullptr );
  485. png_color_16p trans_values = png_color_16p( nullptr );
  486. this->_info._valid_transparency_factors = png_get_tRNS( get_struct()
  487. , get_info()
  488. , &trans
  489. , &this->_info._num_trans
  490. , &trans_values
  491. );
  492. if( trans )
  493. {
  494. //@todo What to do, here? How do I know the length of the "trans" array?
  495. }
  496. if( this->_info._num_trans )
  497. {
  498. this->_info._trans_values.resize( this->_info._num_trans );
  499. std::copy( trans_values
  500. , trans_values + this->_info._num_trans
  501. , &this->_info._trans_values.front()
  502. );
  503. }
  504. }
  505. // @todo One day!
  506. /*
  507. if( false )
  508. {
  509. png_unknown_chunkp unknowns = png_unknown_chunkp( NULL );
  510. int num_unknowns = static_cast< int >( png_get_unknown_chunks( get_struct()
  511. , get_info()
  512. , &unknowns
  513. )
  514. );
  515. }
  516. */
  517. }
  518. /// Check if image is large enough.
  519. void check_image_size( const point_t& img_dim )
  520. {
  521. if( _settings._dim.x > 0 )
  522. {
  523. if( img_dim.x < _settings._dim.x ) { io_error( "Supplied image is too small" ); }
  524. }
  525. else
  526. {
  527. if( img_dim.x < _info._width ) { io_error( "Supplied image is too small" ); }
  528. }
  529. if( _settings._dim.y > 0 )
  530. {
  531. if( img_dim.y < _settings._dim.y ) { io_error( "Supplied image is too small" ); }
  532. }
  533. else
  534. {
  535. if( img_dim.y < _info._height ) { io_error( "Supplied image is too small" ); }
  536. }
  537. }
  538. protected:
  539. static void read_data( png_structp png_ptr
  540. , png_bytep data
  541. , png_size_t length
  542. )
  543. {
  544. static_cast<Device*>(png_get_io_ptr(png_ptr) )->read( data
  545. , length );
  546. }
  547. static void flush( png_structp png_ptr )
  548. {
  549. static_cast<Device*>(png_get_io_ptr(png_ptr) )->flush();
  550. }
  551. static int read_user_chunk_callback( png_struct* /* png_ptr */
  552. , png_unknown_chunkp /* chunk */
  553. )
  554. {
  555. // @todo
  556. return 0;
  557. }
  558. static void read_row_callback( png_structp /* png_ptr */
  559. , png_uint_32 /* row_number */
  560. , int /* pass */
  561. )
  562. {
  563. // @todo
  564. }
  565. public:
  566. Device _io_dev;
  567. image_read_settings< png_tag > _settings;
  568. image_read_info < png_tag > _info;
  569. std::size_t _scanline_length;
  570. std::size_t _number_passes;
  571. };
  572. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  573. #pragma warning(pop)
  574. #endif
  575. } // namespace gil
  576. } // namespace boost
  577. #endif