write.hpp 15 KB

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