write.hpp 15 KB

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