• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
writer(const Device & io_dev,const image_write_info<png_tag> & info)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 >
apply(const View & 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>
write_view(const View & view,std::false_type)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>
write_view(const View & view,std::true_type)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>
set_swap(typename std::enable_if<is_less_than_eight<Info>::value>::type * =0)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>
set_swap(typename std::enable_if<is_equal_to_sixteen<Info>::value>::type * =0)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>
set_swap(typename std::enable_if<mp11::mp_and<mp11::mp_not<is_less_than_eight<Info>>,mp11::mp_not<is_equal_to_sixteen<Info>>>::value>::type * =nullptr)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 
dynamic_image_writer(const Device & io_dev,const image_write_info<png_tag> & info)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 >
apply(const any_image_view<Views...> & 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
249