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