write.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. //
  2. // Copyright 2007-2012 Christian Henning, 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_TIFF_DETAIL_WRITE_HPP
  9. #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_WRITE_HPP
  10. #include <boost/gil/extension/io/tiff/tags.hpp>
  11. #include <boost/gil/extension/io/tiff/detail/writer_backend.hpp>
  12. #include <boost/gil/extension/io/tiff/detail/device.hpp>
  13. #include <boost/gil/premultiply.hpp>
  14. #include <boost/gil/io/base.hpp>
  15. #include <boost/gil/io/device.hpp>
  16. #include <boost/gil/io/detail/dynamic.hpp>
  17. #include <algorithm>
  18. #include <cstdint>
  19. #include <string>
  20. #include <type_traits>
  21. #include <vector>
  22. extern "C" {
  23. #include "tiff.h"
  24. #include "tiffio.h"
  25. }
  26. namespace boost { namespace gil {
  27. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  28. #pragma warning(push)
  29. #pragma warning(disable:4512) //assignment operator could not be generated
  30. #endif
  31. namespace detail {
  32. template <typename PixelReference>
  33. struct my_interleaved_pixel_iterator_type_from_pixel_reference
  34. {
  35. private:
  36. using pixel_t = typename std::remove_reference<PixelReference>::type::value_type;
  37. public:
  38. using type = typename iterator_type_from_pixel
  39. <
  40. pixel_t,
  41. false,
  42. false,
  43. true
  44. >::type;
  45. };
  46. template< typename Channel
  47. , typename Layout
  48. , bool Mutable
  49. >
  50. struct my_interleaved_pixel_iterator_type_from_pixel_reference< const bit_aligned_pixel_reference< byte_t
  51. , Channel
  52. , Layout
  53. , Mutable
  54. >
  55. >
  56. : public iterator_type_from_pixel< const bit_aligned_pixel_reference< uint8_t
  57. , Channel
  58. , Layout
  59. , Mutable
  60. >
  61. ,false
  62. ,false
  63. ,true
  64. > {};
  65. struct tiff_write_is_supported
  66. {
  67. template< typename View >
  68. struct apply
  69. : public is_write_supported< typename get_pixel_type< View >::type
  70. , tiff_tag
  71. >
  72. {};
  73. };
  74. } // namespace detail
  75. ///
  76. /// TIFF Writer
  77. ///
  78. template < typename Device, typename Log >
  79. class writer< Device
  80. , tiff_tag
  81. , Log
  82. >
  83. : public writer_backend< Device
  84. , tiff_tag
  85. >
  86. {
  87. private:
  88. using backend_t = writer_backend<Device, tiff_tag>;
  89. public:
  90. writer( const Device& io_dev
  91. , const image_write_info< tiff_tag >& info
  92. )
  93. : backend_t( io_dev
  94. , info
  95. )
  96. {}
  97. template<typename View>
  98. void apply( const View& view )
  99. {
  100. write_view( view );
  101. }
  102. private:
  103. template< typename View >
  104. void write_view( const View& view )
  105. {
  106. using pixel_t = typename View::value_type;
  107. // get the type of the first channel (heterogeneous pixels might be broken for now!)
  108. using channel_t = typename channel_traits<typename element_type<pixel_t>::type>::value_type;
  109. tiff_bits_per_sample::type bits_per_sample = detail::unsigned_integral_num_bits< channel_t >::value;
  110. tiff_samples_per_pixel::type samples_per_pixel = num_channels< pixel_t >::value;
  111. this->write_header( view );
  112. if( this->_info._is_tiled == false )
  113. {
  114. write_data( view
  115. , (view.width() * samples_per_pixel * bits_per_sample + 7) / 8
  116. , typename is_bit_aligned< pixel_t >::type()
  117. );
  118. }
  119. else
  120. {
  121. tiff_tile_width::type tw = this->_info._tile_width;
  122. tiff_tile_length::type th = this->_info._tile_length;
  123. if(!this->_io_dev.check_tile_size( tw, th ))
  124. {
  125. io_error( "Tile sizes need to be multiples of 16." );
  126. }
  127. // tile related tags
  128. this->_io_dev.template set_property<tiff_tile_width> ( tw );
  129. this->_io_dev.template set_property<tiff_tile_length>( th );
  130. write_tiled_data( view
  131. , tw
  132. , th
  133. , typename is_bit_aligned< pixel_t >::type()
  134. );
  135. }
  136. }
  137. //////////////////////////////
  138. template<typename View>
  139. void write_bit_aligned_view_to_dev( const View& view
  140. , const std::size_t row_size_in_bytes
  141. , const std::true_type& // has_alpha
  142. )
  143. {
  144. byte_vector_t row( row_size_in_bytes );
  145. using x_it_t = typename View::x_iterator;
  146. x_it_t row_it = x_it_t( &(*row.begin()));
  147. auto pm_view = premultiply_view <typename View:: value_type> (view);
  148. for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
  149. {
  150. std::copy( pm_view.row_begin( y )
  151. , pm_view.row_end( y )
  152. , row_it
  153. );
  154. this->_io_dev.write_scaline( row
  155. , static_cast<std::uint32_t>( y )
  156. , 0
  157. );
  158. // @todo: do optional bit swapping here if you need to...
  159. }
  160. }
  161. template<typename View>
  162. void write_bit_aligned_view_to_dev( const View& view
  163. , const std::size_t row_size_in_bytes
  164. , const std::false_type& // has_alpha
  165. )
  166. {
  167. byte_vector_t row( row_size_in_bytes );
  168. using x_it_t = typename View::x_iterator;
  169. x_it_t row_it = x_it_t( &(*row.begin()));
  170. for( typename View::y_coord_t y = 0; y < view.height(); ++y )
  171. {
  172. std::copy( view.row_begin( y )
  173. , view.row_end( y )
  174. , row_it
  175. );
  176. this->_io_dev.write_scaline( row
  177. , static_cast<std::uint32_t>( y )
  178. , 0
  179. );
  180. // @todo: do optional bit swapping here if you need to...
  181. }
  182. }
  183. /////////////////////////////
  184. template< typename View >
  185. void write_data( const View& view
  186. , std::size_t row_size_in_bytes
  187. , const std::true_type& // bit_aligned
  188. )
  189. {
  190. using colour_space_t = typename color_space_type<typename View::value_type>::type;
  191. using has_alpha_t = mp11::mp_contains<colour_space_t, alpha_t>;
  192. write_bit_aligned_view_to_dev(view, row_size_in_bytes, has_alpha_t());
  193. }
  194. template< typename View>
  195. void write_tiled_data( const View& view
  196. , tiff_tile_width::type tw
  197. , tiff_tile_length::type th
  198. , const std::true_type& // bit_aligned
  199. )
  200. {
  201. byte_vector_t row( this->_io_dev.get_tile_size() );
  202. using x_it_t = typename View::x_iterator;
  203. x_it_t row_it = x_it_t( &(*row.begin()));
  204. internal_write_tiled_data(view, tw, th, row, row_it);
  205. }
  206. template< typename View >
  207. void write_data( const View& view
  208. , std::size_t
  209. , const std::false_type& // bit_aligned
  210. )
  211. {
  212. std::vector< pixel< typename channel_type< View >::type
  213. , layout<typename color_space_type< View >::type >
  214. >
  215. > row( view.size() );
  216. byte_t* row_addr = reinterpret_cast< byte_t* >( &row.front() );
  217. // @todo: is there an overhead to doing this when there's no
  218. // alpha to premultiply by? I'd hope it's optimised out.
  219. auto pm_view = premultiply_view <typename View:: value_type> (view);
  220. for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y )
  221. {
  222. std::copy( pm_view.row_begin( y )
  223. , pm_view.row_end( y )
  224. , row.begin()
  225. );
  226. this->_io_dev.write_scaline( row_addr
  227. , static_cast<std::uint32_t>( y )
  228. , 0
  229. );
  230. // @todo: do optional bit swapping here if you need to...
  231. }
  232. }
  233. template< typename View >
  234. void write_tiled_data( const View& view
  235. , tiff_tile_width::type tw
  236. , tiff_tile_length::type th
  237. , const std::false_type& // bit_aligned
  238. )
  239. {
  240. byte_vector_t row( this->_io_dev.get_tile_size() );
  241. using x_iterator = typename detail::my_interleaved_pixel_iterator_type_from_pixel_reference<typename View::reference>::type;
  242. x_iterator row_it = x_iterator( &(*row.begin()));
  243. internal_write_tiled_data(view, tw, th, row, row_it);
  244. }
  245. //////////////////////////////
  246. template< typename View
  247. , typename IteratorType
  248. >
  249. void write_tiled_view_to_dev( const View& view
  250. , IteratorType it
  251. , const std::true_type& // has_alpha
  252. )
  253. {
  254. auto pm_view = premultiply_view <typename View:: value_type>( view );
  255. std::copy( pm_view.begin()
  256. , pm_view.end()
  257. , it
  258. );
  259. }
  260. template< typename View
  261. , typename IteratorType
  262. >
  263. void write_tiled_view_to_dev( const View& view
  264. , IteratorType it
  265. , const std::false_type& // has_alpha
  266. )
  267. {
  268. std::copy( view.begin()
  269. , view.end()
  270. , it
  271. );
  272. }
  273. /////////////////////////////
  274. template< typename View,
  275. typename IteratorType
  276. >
  277. void internal_write_tiled_data( const View& view
  278. , tiff_tile_width::type tw
  279. , tiff_tile_length::type th
  280. , byte_vector_t& row
  281. , IteratorType it
  282. )
  283. {
  284. std::ptrdiff_t i = 0, j = 0;
  285. View tile_subimage_view;
  286. while( i < view.height() )
  287. {
  288. while( j < view.width() )
  289. {
  290. if( j + tw < view.width() && i + th < view.height() )
  291. {
  292. // a tile is fully included in the image: just copy values
  293. tile_subimage_view = subimage_view( view
  294. , static_cast< int >( j )
  295. , static_cast< int >( i )
  296. , static_cast< int >( tw )
  297. , static_cast< int >( th )
  298. );
  299. using colour_space_t = typename color_space_type<typename View::value_type>::type;
  300. using has_alpha_t = mp11::mp_contains<colour_space_t, alpha_t>;
  301. write_tiled_view_to_dev(tile_subimage_view, it, has_alpha_t());
  302. }
  303. else
  304. {
  305. std::ptrdiff_t width = view.width();
  306. std::ptrdiff_t height = view.height();
  307. std::ptrdiff_t current_tile_width = ( j + tw < width ) ? tw : width - j;
  308. std::ptrdiff_t current_tile_length = ( i + th < height) ? th : height - i;
  309. tile_subimage_view = subimage_view( view
  310. , static_cast< int >( j )
  311. , static_cast< int >( i )
  312. , static_cast< int >( current_tile_width )
  313. , static_cast< int >( current_tile_length )
  314. );
  315. for( typename View::y_coord_t y = 0; y < tile_subimage_view.height(); ++y )
  316. {
  317. std::copy( tile_subimage_view.row_begin( y )
  318. , tile_subimage_view.row_end( y )
  319. , it
  320. );
  321. std::advance(it, tw);
  322. }
  323. it = IteratorType( &(*row.begin()));
  324. }
  325. this->_io_dev.write_tile( row
  326. , static_cast< std::uint32_t >( j )
  327. , static_cast< std::uint32_t >( i )
  328. , 0
  329. , 0
  330. );
  331. j += tw;
  332. }
  333. j = 0;
  334. i += th;
  335. }
  336. // @todo: do optional bit swapping here if you need to...
  337. }
  338. };
  339. ///
  340. /// TIFF Dynamic Image Writer
  341. ///
  342. template< typename Device >
  343. class dynamic_image_writer< Device
  344. , tiff_tag
  345. >
  346. : public writer< Device
  347. , tiff_tag
  348. >
  349. {
  350. using parent_t = writer<Device, tiff_tag>;
  351. public:
  352. dynamic_image_writer( const Device& io_dev
  353. , const image_write_info< tiff_tag >& info
  354. )
  355. : parent_t( io_dev
  356. , info
  357. )
  358. {}
  359. template< typename ...Views >
  360. void apply( const any_image_view< Views... >& views )
  361. {
  362. detail::dynamic_io_fnobj< detail::tiff_write_is_supported
  363. , parent_t
  364. > op( this );
  365. variant2::visit( op, views );
  366. }
  367. };
  368. #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
  369. #pragma warning(pop)
  370. #endif
  371. } // namespace gil
  372. } // namespace boost
  373. #endif