]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/extension/io/tiff/detail/write.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / 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