Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / io / tiff / detail / device.hpp
1 //
2 // Copyright 2007-2008 Andreas Pokorny, Christian Henning
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_DEVICE_HPP
9 #define BOOST_GIL_EXTENSION_IO_TIFF_DETAIL_DEVICE_HPP
10
11 #include <boost/gil/extension/io/tiff/tags.hpp>
12 #include <boost/gil/extension/io/tiff/detail/log.hpp>
13 #include <boost/gil/detail/mp11.hpp>
14 #include <boost/gil/io/base.hpp>
15 #include <boost/gil/io/device.hpp>
16
17 #include <algorithm>
18 #include <memory>
19 #include <sstream>
20 #include <type_traits>
21
22 // taken from jpegxx - https://bitbucket.org/edd/jpegxx/src/ea2492a1a4a6/src/ijg_headers.hpp
23 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
24     extern "C" {
25 #endif
26
27 #include <tiff.h>
28 #include <tiffio.h>
29
30 #ifndef BOOST_GIL_EXTENSION_IO_TIFF_C_LIB_COMPILED_AS_CPLUSPLUS
31     }
32 #endif
33
34 #include <tiffio.hxx>
35
36 namespace boost { namespace gil { namespace detail {
37
38 template <int n_args>
39 struct get_property_f {
40         template <typename Property>
41         bool call_me(typename Property:: type& value, std::shared_ptr<TIFF>& file);
42 };
43
44 template <int n_args>
45 struct set_property_f {
46         template <typename Property>
47         bool call_me(const typename Property:: type& value, std::shared_ptr<TIFF>& file) const;
48 };
49
50 template <> struct get_property_f <1>
51 {
52         // For single-valued properties
53         template <typename Property>
54         bool call_me(typename Property::type & value, std::shared_ptr<TIFF>& file) const
55         {
56                 // @todo: defaulted, really?
57                 return (1 == TIFFGetFieldDefaulted( file.get()
58                                 , Property:: tag
59                                 , & value));
60         }
61 };
62
63 template <> struct get_property_f <2>
64 {
65         // Specialisation for multi-valued properties. @todo: add one of
66         // these for the three-parameter fields too.
67         template <typename Property>
68         bool call_me(typename Property::type& vs, std::shared_ptr<TIFF>& file) const
69         {
70         mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 0>> length;
71         mp11::mp_at<typename Property::arg_types, std::integral_constant<int, 1>> pointer;
72                 if (1 == TIFFGetFieldDefaulted(file.get(), Property:: tag, & length, & pointer))
73         {
74                         std:: copy_n(static_cast<typename Property::type::const_pointer>(pointer), length, std:: back_inserter(vs));
75                         return true;
76                 } else
77                         return false;
78         }
79 };
80
81 template <> struct set_property_f <1>
82 {
83         // For single-valued properties
84         template <typename Property>
85         inline
86         bool call_me(typename Property:: type const & value, std::shared_ptr<TIFF>& file) const
87         {
88                 return (1 == TIFFSetField( file.get()
89                                 , Property:: tag
90                                 , value));
91         }
92 };
93
94 template <> struct set_property_f <2>
95 {
96         // Specialisation for multi-valued properties. @todo: add one
97         // of these for the three-parameter fields too. Actually we
98         // will need further templation / specialisation for the
99         // two-element fields which aren't a length and a data buffer
100         // (e.g. http://www.awaresystems.be/imaging/tiff/tifftags/dotrange.html
101         // )
102         template <typename Property>
103         inline
104         bool call_me(typename Property:: type const & values, std::shared_ptr<TIFF>& file) const
105         {
106         using length_t = mp11::mp_at_c<typename Property::arg_types, 0>;
107                 auto const length = static_cast<length_t>(values.size());
108
109         using pointer_t = mp11::mp_at_c<typename Property::arg_types, 1>;
110                 auto const pointer = static_cast<pointer_t>(&(values.front()));
111                 return (1 == TIFFSetField( file.get(), Property:: tag, length, pointer));
112         }
113 };
114
115 template< typename Log >
116 class tiff_device_base
117 {
118 public:
119     using tiff_file_t = std::shared_ptr<TIFF>;
120
121     tiff_device_base()
122     {}
123
124     tiff_device_base( TIFF* tiff_file )
125     : _tiff_file( tiff_file
126                 , TIFFClose )
127     {}
128
129         template <typename Property>
130     bool get_property( typename Property::type& value  )
131     {
132                 return get_property_f<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
133         }
134
135     template <typename Property>
136     inline
137     bool set_property( const typename Property::type& value )
138     {
139       // http://www.remotesensing.org/libtiff/man/TIFFSetField.3tiff.html
140       return set_property_f<mp11::mp_size<typename Property::arg_types>::value>().template call_me<Property>(value, _tiff_file);
141     }
142
143     // TIFFIsByteSwapped returns a non-zero value if the image data was in a different
144     // byte-order than the host machine. Zero is returned if the TIFF file and local
145     // host byte-orders are the same. Note that TIFFReadTile(), TIFFReadStrip() and TIFFReadScanline()
146     // functions already normally perform byte swapping to local host order if needed.
147     bool are_bytes_swapped()
148     {
149         return ( TIFFIsByteSwapped( _tiff_file.get() )) ? true : false;
150     }
151
152     bool is_tiled() const
153     {
154         return ( TIFFIsTiled( _tiff_file.get() )) ? true : false;
155     }
156
157     unsigned int get_default_strip_size()
158     {
159         return TIFFDefaultStripSize( _tiff_file.get()
160                                    , 0 );
161     }
162
163     std::size_t get_scanline_size()
164     {
165       return TIFFScanlineSize( _tiff_file.get() );
166     }
167
168     std::size_t get_tile_size()
169     {
170       return TIFFTileSize( _tiff_file.get() );
171     }
172
173
174     int get_field_defaulted( uint16_t*& red
175                            , uint16_t*& green
176                            , uint16_t*& blue
177                            )
178     {
179         return TIFFGetFieldDefaulted( _tiff_file.get()
180                                     , TIFFTAG_COLORMAP
181                                     , &red
182                                     , &green
183                                     , &blue
184                                     );
185     }
186
187     template< typename Buffer >
188     void read_scanline( Buffer&        buffer
189                       , std::ptrdiff_t row
190                       , tsample_t      plane
191                       )
192     {
193         io_error_if( TIFFReadScanline( _tiff_file.get()
194                                      , reinterpret_cast< tdata_t >( &buffer.front() )
195                                      , (uint32) row
196                                      , plane           ) == -1
197                    , "Read error."
198                    );
199     }
200
201     void read_scanline( byte_t*        buffer
202                       , std::ptrdiff_t row
203                       , tsample_t      plane
204                       )
205     {
206         io_error_if( TIFFReadScanline( _tiff_file.get()
207                                      , reinterpret_cast< tdata_t >( buffer )
208                                      , (uint32) row
209                                      , plane           ) == -1
210                    , "Read error."
211                    );
212     }
213
214     template< typename Buffer >
215     void read_tile( Buffer&        buffer
216                   , std::ptrdiff_t x
217                   , std::ptrdiff_t y
218                   , std::ptrdiff_t z
219                   , tsample_t      plane
220                   )
221     {
222         if( TIFFReadTile( _tiff_file.get()
223                         , reinterpret_cast< tdata_t >( &buffer.front() )
224                         , (uint32) x
225                         , (uint32) y
226                         , (uint32) z
227                         , plane
228                         ) == -1 )
229         {
230             std::ostringstream oss;
231             oss << "Read tile error (" << x << "," << y << "," << z << "," << plane << ").";
232             io_error(oss.str().c_str());
233         }
234     }
235
236     template< typename Buffer >
237     void write_scaline( Buffer&     buffer
238                       , uint32      row
239                       , tsample_t   plane
240                       )
241     {
242        io_error_if( TIFFWriteScanline( _tiff_file.get()
243                                      , &buffer.front()
244                                      , row
245                                      , plane
246                                      ) == -1
247                    , "Write error"
248                    );
249     }
250
251     void write_scaline( byte_t*     buffer
252                       , uint32      row
253                       , tsample_t   plane
254                       )
255     {
256        io_error_if( TIFFWriteScanline( _tiff_file.get()
257                                      , buffer
258                                      , row
259                                      , plane
260                                      ) == -1
261                    , "Write error"
262                    );
263     }
264
265     template< typename Buffer >
266     void write_tile( Buffer&     buffer
267                    , uint32      x
268                    , uint32      y
269                    , uint32      z
270                    , tsample_t   plane
271                    )
272     {
273        if( TIFFWriteTile( _tiff_file.get()
274                         , &buffer.front()
275                         , x
276                         , y
277                         , z
278                         , plane
279                         ) == -1 )
280            {
281                std::ostringstream oss;
282                oss << "Write tile error (" << x << "," << y << "," << z << "," << plane << ").";
283                io_error(oss.str().c_str());
284            }
285     }
286
287     void set_directory( tdir_t directory )
288     {
289         io_error_if( TIFFSetDirectory( _tiff_file.get()
290                                      , directory
291                                      ) != 1
292                    , "Failing to set directory"
293                    );
294     }
295
296     // return false if the given tile width or height is not TIFF compliant (multiple of 16) or larger than image size, true otherwise
297     bool check_tile_size( tiff_tile_width::type&  width
298                         , tiff_tile_length::type& height
299
300                         )
301     {
302         bool result = true;
303         uint32 tw = static_cast< uint32 >( width  );
304         uint32 th = static_cast< uint32 >( height );
305
306         TIFFDefaultTileSize( _tiff_file.get()
307                            , &tw
308                            , &th
309                            );
310
311         if(width==0 || width%16!=0)
312         {
313             width = tw;
314             result = false;
315         }
316         if(height==0 || height%16!=0)
317         {
318             height = th;
319             result = false;
320         }
321         return result;
322     }
323
324 protected:
325
326    tiff_file_t _tiff_file;
327
328     Log _log;
329 };
330
331 /*!
332  *
333  * file_stream_device specialization for tiff images, which are based on TIFF*.
334  */
335 template<>
336 class file_stream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
337 {
338 public:
339
340     struct read_tag {};
341     struct write_tag {};
342
343     file_stream_device( std::string const& file_name, read_tag )
344     {
345         TIFF* tiff;
346
347         io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "r" )) == nullptr
348                    , "file_stream_device: failed to open file" );
349
350         _tiff_file = tiff_file_t( tiff, TIFFClose );
351     }
352
353     file_stream_device( std::string const& file_name, write_tag )
354     {
355         TIFF* tiff;
356
357         io_error_if( ( tiff = TIFFOpen( file_name.c_str(), "w" )) == nullptr
358                    , "file_stream_device: failed to open file" );
359
360         _tiff_file = tiff_file_t( tiff, TIFFClose );
361     }
362
363     file_stream_device( TIFF* tiff_file )
364     : tiff_device_base( tiff_file )
365     {}
366 };
367
368 /*!
369  *
370  * ostream_device specialization for tiff images.
371  */
372 template<>
373 class ostream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
374 {
375 public:
376     ostream_device( std::ostream & out )
377     : _out( out )
378     {
379         TIFF* tiff;
380
381         io_error_if( ( tiff = TIFFStreamOpen( ""
382                                             , &_out
383                                             )
384                       ) == nullptr
385                    , "ostream_device: failed to stream"
386                    );
387
388         _tiff_file = tiff_file_t( tiff, TIFFClose );
389     }
390
391 private:
392     ostream_device& operator=( const ostream_device& ) { return *this; }
393
394 private:
395
396     std::ostream& _out;
397 };
398
399 /*!
400  *
401  * ostream_device specialization for tiff images.
402  */
403 template<>
404 class istream_device< tiff_tag > : public tiff_device_base< tiff_no_log >
405 {
406 public:
407     istream_device( std::istream & in )
408     : _in( in )
409     {
410         TIFF* tiff;
411
412         io_error_if( ( tiff = TIFFStreamOpen( ""
413                                             , &_in
414                                             )
415                      ) == nullptr
416                    , "istream_device: failed to stream"
417                    );
418
419         _tiff_file = tiff_file_t( tiff, TIFFClose );
420     }
421
422 private:
423     istream_device& operator=( const istream_device& ) { return *this; }
424
425 private:
426
427     std::istream& _in;
428 };
429
430 /*
431 template< typename T, typename D >
432 struct is_adaptable_input_device< tiff_tag, T, D > : std::false_type {};
433 */
434
435 template<typename FormatTag>
436 struct is_adaptable_input_device<FormatTag, TIFF*, void> : std::true_type
437 {
438     using device_type = file_stream_device<FormatTag>;
439 };
440
441 template<typename FormatTag>
442 struct is_adaptable_output_device<FormatTag, TIFF*, void> : std::true_type
443 {
444     using device_type = file_stream_device<FormatTag>;
445 };
446
447
448 template <typename Channel>
449 struct sample_format : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
450 template<>
451 struct sample_format<uint8_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
452 template<>
453 struct sample_format<uint16_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
454 template<>
455 struct sample_format<uint32_t> : std::integral_constant<int, SAMPLEFORMAT_UINT> {};
456 template<>
457 struct sample_format<float32_t> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
458 template<>
459 struct sample_format<double> : std::integral_constant<int, SAMPLEFORMAT_IEEEFP> {};
460 template<>
461 struct sample_format<int8_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
462 template<>
463 struct sample_format<int16_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
464 template<>
465 struct sample_format<int32_t> : std::integral_constant<int, SAMPLEFORMAT_INT> {};
466
467 template <typename Channel>
468 struct photometric_interpretation {};
469 template<>
470 struct photometric_interpretation<gray_t>
471     : std::integral_constant<int, PHOTOMETRIC_MINISBLACK> {};
472 template<>
473 struct photometric_interpretation<rgb_t>
474     : std::integral_constant<int, PHOTOMETRIC_RGB> {};
475 template<>
476 struct photometric_interpretation<rgba_t>
477     : std::integral_constant<int, PHOTOMETRIC_RGB> {};
478 template<>
479 struct photometric_interpretation<cmyk_t>
480     : std::integral_constant<int, PHOTOMETRIC_SEPARATED> {};
481
482 } // namespace detail
483 } // namespace gil
484 } // namespace boost
485
486 #endif