Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / io / tiff / detail / write.hpp
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
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>
114     void apply( const View& view )
115     {
116         write_view( view );
117     }
118
119 private:
120
121     template< typename 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>
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>
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 >
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>
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 >
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 >
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             >
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             >
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             >
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
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 >
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