write.hpp 15 KB

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