Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / io / png / detail / write.hpp
1 //
2 // Copyright 2007-2012 Christian Henning, Andreas Pokorny, 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_PNG_DETAIL_WRITE_HPP
9 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITE_HPP
10
11 #include <boost/gil/extension/io/png/detail/writer_backend.hpp>
12
13 #include <boost/gil/io/device.hpp>
14 #include <boost/gil/io/dynamic_io_new.hpp>
15 #include <boost/gil/io/row_buffer_helper.hpp>
16 #include <boost/gil/detail/mp11.hpp>
17
18 #include <type_traits>
19
20 namespace boost { namespace gil {
21
22 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
23 #pragma warning(push)
24 #pragma warning(disable:4512) //assignment operator could not be generated
25 #endif
26
27 namespace detail {
28
29 struct png_write_is_supported
30 {
31     template< typename View >
32     struct apply
33         : public is_write_supported< typename get_pixel_type< View >::type
34                                    , png_tag
35                                    >
36     {};
37 };
38
39 } // namespace detail
40
41 ///
42 /// PNG Writer
43 ///
44 template< typename Device >
45 class writer< Device
46             , png_tag
47             >
48     : public writer_backend< Device
49                            , png_tag
50                            >
51 {
52
53 public:
54
55     using backend_t = writer_backend<Device, png_tag>;
56
57     writer( const Device&                      io_dev
58           , const image_write_info< png_tag >& info
59           )
60     : backend_t( io_dev
61                , info
62                )
63     {}
64
65
66     template< typename View >
67     void apply( const View& view )
68     {
69         io_error_if( view.width() == 0 && view.height() == 0
70                    , "png format cannot handle empty views."
71                    );
72
73         this->write_header( view );
74
75         write_view( view
76                   , typename is_bit_aligned< typename View::value_type >::type()
77                   );
78     }
79
80 private:
81
82     template<typename View>
83     void write_view( const View& view
84                    ,  std::false_type       // is bit aligned
85                    )
86     {
87         using pixel_t = typename get_pixel_type<View>::type;
88
89         using png_rw_info = detail::png_write_support
90             <
91                 typename channel_type<pixel_t>::type,
92                 typename color_space_type<pixel_t>::type
93             >;
94
95         if( little_endian() )
96         {
97             set_swap< png_rw_info >();
98         }
99
100         std::vector< pixel< typename channel_type< View >::type
101                           , layout<typename color_space_type< View >::type >
102                           >
103                    > row_buffer( view.width() );
104
105         for( int y = 0; y != view.height(); ++ y)
106         {
107             std::copy( view.row_begin( y )
108                      , view.row_end  ( y )
109                      , row_buffer.begin()
110                      );
111
112             png_write_row( this->get_struct()
113                          , reinterpret_cast< png_bytep >( row_buffer.data() )
114                          );
115         }
116
117         png_write_end( this->get_struct()
118                      , this->get_info()
119                      );
120     }
121
122     template<typename View>
123     void write_view( const View& view
124                    , std::true_type         // is bit aligned
125                    )
126     {
127         using png_rw_info = detail::png_write_support
128             <
129                 typename kth_semantic_element_type<typename View::value_type, 0>::type,
130                 typename color_space_type<View>::type
131             >;
132
133         if (little_endian() )
134         {
135             set_swap< png_rw_info >();
136         }
137
138         detail::row_buffer_helper_view< View > row_buffer( view.width()
139                                                          , false
140                                                          );
141
142         for( int y = 0; y != view.height(); ++y )
143         {
144             std::copy( view.row_begin( y )
145                      , view.row_end  ( y )
146                      , row_buffer.begin()
147                      );
148
149             png_write_row( this->get_struct()
150                          , reinterpret_cast< png_bytep >( row_buffer.data() )
151                          );
152         }
153
154         png_free_data( this->get_struct()
155                      , this->get_info()
156                      , PNG_FREE_UNKN
157                      , -1
158                      );
159
160         png_write_end( this->get_struct()
161                      , this->get_info()
162                      );
163     }
164
165     template<typename Info>
166     struct is_less_than_eight : mp11::mp_less
167         <
168             std::integral_constant<int, Info::_bit_depth>,
169             std::integral_constant<int, 8>
170         >
171     {};
172
173     template<typename Info>
174     struct is_equal_to_sixteen : mp11::mp_less
175         <
176             std::integral_constant<int, Info::_bit_depth>,
177             std::integral_constant<int, 16>
178         >
179     {};
180
181     template <typename Info>
182     void set_swap(typename std::enable_if<is_less_than_eight<Info>::value>::type* /*ptr*/ = 0)
183     {
184         png_set_packswap(this->get_struct());
185     }
186
187     template <typename Info>
188     void set_swap(typename std::enable_if<is_equal_to_sixteen<Info>::value>::type* /*ptr*/ = 0)
189     {
190         png_set_swap(this->get_struct());
191     }
192
193     template <typename Info>
194     void set_swap(
195         typename std::enable_if
196         <
197             mp11::mp_and
198             <
199                 mp11::mp_not<is_less_than_eight<Info>>,
200                 mp11::mp_not<is_equal_to_sixteen<Info>>
201             >::value
202         >::type* /*ptr*/ = nullptr)
203     {
204     }
205 };
206
207 ///
208 /// PNG Dynamic Image Writer
209 ///
210 template< typename Device >
211 class dynamic_image_writer< Device
212                           , png_tag
213                           >
214     : public writer< Device
215                    , png_tag
216                    >
217 {
218     using parent_t = writer<Device, png_tag>;
219
220 public:
221
222     dynamic_image_writer( const Device&                      io_dev
223                         , const image_write_info< png_tag >& info
224 )
225     : parent_t( io_dev
226               , info
227               )
228     {}
229
230     template< typename Views >
231     void apply( const any_image_view< Views >& views )
232     {
233         detail::dynamic_io_fnobj< detail::png_write_is_supported
234                                 , parent_t
235                                 > op( this );
236
237         apply_operation( views, op );
238     }
239 };
240
241 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
242 #pragma warning(pop)
243 #endif
244
245 } // namespace gil
246 } // namespace boost
247
248 #endif