writer_backend.hpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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_PNG_DETAIL_WRITER_BACKEND_HPP
  9. #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_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. #include <boost/gil/io/base.hpp>
  14. #include <boost/gil/io/typedefs.hpp>
  15. namespace boost { namespace gil {
  16. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  17. #pragma warning(push)
  18. #pragma warning(disable:4512) //assignment operator could not be generated
  19. #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
  20. #endif
  21. ///
  22. /// PNG Writer Backend
  23. ///
  24. template< typename Device >
  25. struct writer_backend< Device
  26. , png_tag
  27. >
  28. : public detail::png_struct_info_wrapper
  29. {
  30. private:
  31. using this_t = writer_backend<Device, png_tag>;
  32. public:
  33. using format_tag_t = png_tag;
  34. ///
  35. /// Constructor
  36. ///
  37. writer_backend( const Device& io_dev
  38. , const image_write_info< png_tag >& info
  39. )
  40. : png_struct_info_wrapper( false )
  41. , _io_dev( io_dev )
  42. , _info( info )
  43. {
  44. // Create and initialize the png_struct with the desired error handler
  45. // functions. If you want to use the default stderr and longjump method,
  46. // you can supply NULL for the last three parameters. We also check that
  47. // the library version is compatible with the one used at compile time,
  48. // in case we are using dynamically linked libraries. REQUIRED.
  49. get()->_struct = png_create_write_struct( PNG_LIBPNG_VER_STRING
  50. , nullptr // user_error_ptr
  51. , nullptr // user_error_fn
  52. , nullptr // user_warning_fn
  53. );
  54. io_error_if( get_struct() == nullptr
  55. , "png_writer: fail to call png_create_write_struct()"
  56. );
  57. // Allocate/initialize the image information data. REQUIRED
  58. get()->_info = png_create_info_struct( get_struct() );
  59. if( get_info() == nullptr )
  60. {
  61. png_destroy_write_struct( &get()->_struct
  62. , nullptr
  63. );
  64. io_error( "png_writer: fail to call png_create_info_struct()" );
  65. }
  66. // Set error handling. REQUIRED if you aren't supplying your own
  67. // error handling functions in the png_create_write_struct() call.
  68. if( setjmp( png_jmpbuf( get_struct() )))
  69. {
  70. //free all of the memory associated with the png_ptr and info_ptr
  71. png_destroy_write_struct( &get()->_struct
  72. , &get()->_info
  73. );
  74. io_error( "png_writer: fail to call setjmp()" );
  75. }
  76. init_io( get_struct() );
  77. }
  78. protected:
  79. template< typename View >
  80. void write_header( const View& view )
  81. {
  82. using png_rw_info_t = detail::png_write_support
  83. <
  84. typename channel_type<typename get_pixel_type<View>::type>::type,
  85. typename color_space_type<View>::type
  86. >;
  87. // Set the image information here. Width and height are up to 2^31,
  88. // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
  89. // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
  90. // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
  91. // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
  92. // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
  93. // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
  94. png_set_IHDR( get_struct()
  95. , get_info()
  96. , static_cast< png_image_width::type >( view.width() )
  97. , static_cast< png_image_height::type >( view.height() )
  98. , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth )
  99. , static_cast< png_color_type::type >( png_rw_info_t::_color_type )
  100. , _info._interlace_method
  101. , _info._compression_type
  102. , _info._filter_method
  103. );
  104. #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  105. if( _info._valid_cie_colors )
  106. {
  107. png_set_cHRM( get_struct()
  108. , get_info()
  109. , _info._white_x
  110. , _info._white_y
  111. , _info._red_x
  112. , _info._red_y
  113. , _info._green_x
  114. , _info._green_y
  115. , _info._blue_x
  116. , _info._blue_y
  117. );
  118. }
  119. if( _info._valid_file_gamma )
  120. {
  121. png_set_gAMA( get_struct()
  122. , get_info()
  123. , _info._file_gamma
  124. );
  125. }
  126. #else
  127. if( _info._valid_cie_colors )
  128. {
  129. png_set_cHRM_fixed( get_struct()
  130. , get_info()
  131. , _info._white_x
  132. , _info._white_y
  133. , _info._red_x
  134. , _info._red_y
  135. , _info._green_x
  136. , _info._green_y
  137. , _info._blue_x
  138. , _info._blue_y
  139. );
  140. }
  141. if( _info._valid_file_gamma )
  142. {
  143. png_set_gAMA_fixed( get_struct()
  144. , get_info()
  145. , _info._file_gamma
  146. );
  147. }
  148. #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  149. if( _info._valid_icc_profile )
  150. {
  151. #if PNG_LIBPNG_VER_MINOR >= 5
  152. png_set_iCCP( get_struct()
  153. , get_info()
  154. , const_cast< png_charp >( _info._icc_name.c_str() )
  155. , _info._iccp_compression_type
  156. , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) )
  157. , _info._profile_length
  158. );
  159. #else
  160. png_set_iCCP( get_struct()
  161. , get_info()
  162. , const_cast< png_charp >( _info._icc_name.c_str() )
  163. , _info._iccp_compression_type
  164. , const_cast< png_charp >( & (_info._profile.front()) )
  165. , _info._profile_length
  166. );
  167. #endif
  168. }
  169. if( _info._valid_intent )
  170. {
  171. png_set_sRGB( get_struct()
  172. , get_info()
  173. , _info._intent
  174. );
  175. }
  176. if( _info._valid_palette )
  177. {
  178. png_set_PLTE( get_struct()
  179. , get_info()
  180. , const_cast< png_colorp >( &_info._palette.front() )
  181. , _info._num_palette
  182. );
  183. }
  184. if( _info._valid_background )
  185. {
  186. png_set_bKGD( get_struct()
  187. , get_info()
  188. , const_cast< png_color_16p >( &_info._background )
  189. );
  190. }
  191. if( _info._valid_histogram )
  192. {
  193. png_set_hIST( get_struct()
  194. , get_info()
  195. , const_cast< png_uint_16p >( &_info._histogram.front() )
  196. );
  197. }
  198. if( _info._valid_offset )
  199. {
  200. png_set_oFFs( get_struct()
  201. , get_info()
  202. , _info._offset_x
  203. , _info._offset_y
  204. , _info._off_unit_type
  205. );
  206. }
  207. if( _info._valid_pixel_calibration )
  208. {
  209. std::vector< const char* > params( _info._num_params );
  210. for( std::size_t i = 0; i < params.size(); ++i )
  211. {
  212. params[i] = _info._params[ i ].c_str();
  213. }
  214. png_set_pCAL( get_struct()
  215. , get_info()
  216. , const_cast< png_charp >( _info._purpose.c_str() )
  217. , _info._X0
  218. , _info._X1
  219. , _info._cal_type
  220. , _info._num_params
  221. , const_cast< png_charp >( _info._units.c_str() )
  222. , const_cast< png_charpp >( &params.front() )
  223. );
  224. }
  225. if( _info._valid_resolution )
  226. {
  227. png_set_pHYs( get_struct()
  228. , get_info()
  229. , _info._res_x
  230. , _info._res_y
  231. , _info._phy_unit_type
  232. );
  233. }
  234. if( _info._valid_significant_bits )
  235. {
  236. png_set_sBIT( get_struct()
  237. , get_info()
  238. , const_cast< png_color_8p >( &_info._sig_bits )
  239. );
  240. }
  241. #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER
  242. #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  243. if( _info._valid_scale_factors )
  244. {
  245. png_set_sCAL( get_struct()
  246. , get_info()
  247. , this->_info._scale_unit
  248. , this->_info._scale_width
  249. , this->_info._scale_height
  250. );
  251. }
  252. #else
  253. #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
  254. if( _info._valid_scale_factors )
  255. {
  256. png_set_sCAL_fixed( get_struct()
  257. , get_info()
  258. , this->_info._scale_unit
  259. , this->_info._scale_width
  260. , this->_info._scale_height
  261. );
  262. }
  263. #else
  264. if( _info._valid_scale_factors )
  265. {
  266. png_set_sCAL_s( get_struct()
  267. , get_info()
  268. , this->_info._scale_unit
  269. , const_cast< png_charp >( this->_info._scale_width.c_str() )
  270. , const_cast< png_charp >( this->_info._scale_height.c_str() )
  271. );
  272. }
  273. #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
  274. #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
  275. #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER
  276. if( _info._valid_text )
  277. {
  278. std::vector< png_text > texts( _info._num_text );
  279. for( std::size_t i = 0; i < texts.size(); ++i )
  280. {
  281. png_text pt;
  282. pt.compression = _info._text[i]._compression;
  283. pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() );
  284. pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() );
  285. pt.text_length = _info._text[i]._text.length();
  286. texts[i] = pt;
  287. }
  288. png_set_text( get_struct()
  289. , get_info()
  290. , &texts.front()
  291. , _info._num_text
  292. );
  293. }
  294. if( _info._valid_modification_time )
  295. {
  296. png_set_tIME( get_struct()
  297. , get_info()
  298. , const_cast< png_timep >( &_info._mod_time )
  299. );
  300. }
  301. if( _info._valid_transparency_factors )
  302. {
  303. int sample_max = ( 1u << _info._bit_depth );
  304. /* libpng doesn't reject a tRNS chunk with out-of-range samples */
  305. if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY
  306. && (int) _info._trans_values[0].gray > sample_max
  307. )
  308. || ( _info._color_type == PNG_COLOR_TYPE_RGB
  309. &&( (int) _info._trans_values[0].red > sample_max
  310. || (int) _info._trans_values[0].green > sample_max
  311. || (int) _info._trans_values[0].blue > sample_max
  312. )
  313. )
  314. )
  315. )
  316. {
  317. //@todo Fix that once reading transparency values works
  318. /*
  319. png_set_tRNS( get_struct()
  320. , get_info()
  321. , trans
  322. , num_trans
  323. , trans_values
  324. );
  325. */
  326. }
  327. }
  328. // Compression Levels - valid values are [0,9]
  329. png_set_compression_level( get_struct()
  330. , _info._compression_level
  331. );
  332. png_set_compression_mem_level( get_struct()
  333. , _info._compression_mem_level
  334. );
  335. png_set_compression_strategy( get_struct()
  336. , _info._compression_strategy
  337. );
  338. png_set_compression_window_bits( get_struct()
  339. , _info._compression_window_bits
  340. );
  341. png_set_compression_method( get_struct()
  342. , _info._compression_method
  343. );
  344. png_set_compression_buffer_size( get_struct()
  345. , _info._compression_buffer_size
  346. );
  347. #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
  348. // Dithering
  349. if( _info._set_dithering )
  350. {
  351. png_set_dither( get_struct()
  352. , &_info._dithering_palette.front()
  353. , _info._dithering_num_palette
  354. , _info._dithering_maximum_colors
  355. , &_info._dithering_histogram.front()
  356. , _info._full_dither
  357. );
  358. }
  359. #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
  360. // Filter
  361. if( _info._set_filter )
  362. {
  363. png_set_filter( get_struct()
  364. , 0
  365. , _info._filter
  366. );
  367. }
  368. // Invert Mono
  369. if( _info._invert_mono )
  370. {
  371. png_set_invert_mono( get_struct() );
  372. }
  373. // True Bits
  374. if( _info._set_true_bits )
  375. {
  376. png_set_sBIT( get_struct()
  377. , get_info()
  378. , &_info._true_bits.front()
  379. );
  380. }
  381. // sRGB Intent
  382. if( _info._set_srgb_intent )
  383. {
  384. png_set_sRGB( get_struct()
  385. , get_info()
  386. , _info._srgb_intent
  387. );
  388. }
  389. // Strip Alpha
  390. if( _info._strip_alpha )
  391. {
  392. png_set_strip_alpha( get_struct() );
  393. }
  394. // Swap Alpha
  395. if( _info._swap_alpha )
  396. {
  397. png_set_swap_alpha( get_struct() );
  398. }
  399. png_write_info( get_struct()
  400. , get_info()
  401. );
  402. }
  403. protected:
  404. static void write_data( png_structp png_ptr
  405. , png_bytep data
  406. , png_size_t length
  407. )
  408. {
  409. static_cast< Device* >( png_get_io_ptr( png_ptr ))->write( data
  410. , length );
  411. }
  412. static void flush( png_structp png_ptr )
  413. {
  414. static_cast< Device* >(png_get_io_ptr(png_ptr) )->flush();
  415. }
  416. private:
  417. void init_io( png_structp png_ptr )
  418. {
  419. png_set_write_fn( png_ptr
  420. , static_cast< void* > ( &this->_io_dev )
  421. , static_cast< png_rw_ptr > ( &this_t::write_data )
  422. , static_cast< png_flush_ptr >( &this_t::flush )
  423. );
  424. }
  425. public:
  426. Device _io_dev;
  427. image_write_info< png_tag > _info;
  428. };
  429. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  430. #pragma warning(pop)
  431. #endif
  432. } // namespace gil
  433. } // namespace boost
  434. #endif