Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / io / pnm / detail / write.hpp
1 //
2 // Copyright 2012 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_PNM_DETAIL_WRITE_HPP
9 #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITE_HPP
10
11 #include <boost/gil/extension/io/pnm/tags.hpp>
12 #include <boost/gil/extension/io/pnm/detail/writer_backend.hpp>
13
14 #include <boost/gil/io/base.hpp>
15 #include <boost/gil/io/bit_operations.hpp>
16 #include <boost/gil/io/device.hpp>
17 #include <boost/gil/io/dynamic_io_new.hpp>
18 #include <boost/gil/detail/mp11.hpp>
19
20 #include <cstdlib>
21 #include <string>
22 #include <type_traits>
23
24 namespace boost { namespace gil {
25
26 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
27 #pragma warning(push)
28 #pragma warning(disable:4512) //assignment operator could not be generated
29 #endif
30
31 namespace detail {
32
33 struct pnm_write_is_supported
34 {
35     template< typename View >
36     struct apply
37         : public is_write_supported< typename get_pixel_type< View >::type
38                                    , pnm_tag
39                                    >
40     {};
41 };
42
43 } // namespace detail
44
45 ///
46 /// PNM Writer
47 ///
48 template< typename Device >
49 class writer< Device
50             , pnm_tag
51             >
52     : public writer_backend< Device
53                            , pnm_tag
54                            >
55 {
56 private:
57     using backend_t = writer_backend<Device, pnm_tag>;
58
59 public:
60
61     writer( const Device&                      io_dev
62           , const image_write_info< pnm_tag >& info
63           )
64     : backend_t( io_dev
65                 , info
66                 )
67     {}
68
69     template< typename View >
70     void apply( const View& view )
71     {
72         using pixel_t = typename get_pixel_type<View>::type;
73
74         std::size_t width  = view.width();
75         std::size_t height = view.height();
76
77         std::size_t chn    = num_channels< View >::value;
78         std::size_t pitch  = chn * width;
79
80         unsigned int type = get_type< num_channels< View >::value >( is_bit_aligned< pixel_t >() );
81
82         // write header
83
84         // Add a white space at each string so read_int() can decide when a numbers ends.
85
86         std::string str( "P" );
87         str += std::to_string( type ) + std::string( " " );
88         this->_io_dev.print_line( str );
89
90         str.clear();
91         str += std::to_string( width ) + std::string( " " );
92         this->_io_dev.print_line( str );
93
94         str.clear();
95         str += std::to_string( height ) + std::string( " " );
96         this->_io_dev.print_line( str );
97
98         if( type != pnm_image_type::mono_bin_t::value )
99         {
100             this->_io_dev.print_line( "255 ");
101         }
102
103         // write data
104         write_data( view
105                   , pitch
106                   , typename is_bit_aligned< pixel_t >::type()
107                   );
108     }
109
110 private:
111
112     template< int Channels >
113     unsigned int get_type( std::true_type  /* is_bit_aligned */ )
114     {
115         return mp11::mp_if_c
116             <
117                 Channels == 1,
118                 pnm_image_type::mono_bin_t,
119                 pnm_image_type::color_bin_t
120             >::value;
121     }
122
123     template< int Channels >
124     unsigned int get_type( std::false_type /* is_bit_aligned */ )
125     {
126         return mp11::mp_if_c
127             <
128                 Channels == 1,
129                 pnm_image_type::gray_bin_t,
130                 pnm_image_type::color_bin_t
131             >::value;
132     }
133
134     template< typename View >
135     void write_data( const View&   src
136                    , std::size_t   pitch
137                    , const std::true_type&    // bit_aligned
138                    )
139     {
140         static_assert(std::is_same<View, typename gray1_image_t::view_t>::value, "");
141
142         byte_vector_t row( pitch / 8 );
143
144         using x_it_t = typename View::x_iterator;
145         x_it_t row_it = x_it_t( &( *row.begin() ));
146
147         detail::negate_bits<byte_vector_t, std::true_type> negate;
148         detail::mirror_bits<byte_vector_t, std::true_type> mirror;
149         for (typename View::y_coord_t y = 0; y < src.height(); ++y)
150         {
151             std::copy(src.row_begin(y), src.row_end(y), row_it);
152
153             mirror(row);
154             negate(row);
155
156             this->_io_dev.write(&row.front(), pitch / 8);
157         }
158     }
159
160     template< typename View >
161     void write_data( const View&   src
162                    , std::size_t   pitch
163                    , const std::false_type&    // bit_aligned
164                    )
165     {
166         std::vector< pixel< typename channel_type< View >::type
167                           , layout<typename color_space_type< View >::type >
168                           >
169                    > buf( src.width() );
170
171         // using pixel_t = typename View::value_type;
172         // using view_t = typename view_type_from_pixel< pixel_t >::type;
173
174         //view_t row = interleaved_view( src.width()
175         //                             , 1
176         //                             , reinterpret_cast< pixel_t* >( &buf.front() )
177         //                             , pitch
178         //                             );
179
180         byte_t* row_addr = reinterpret_cast< byte_t* >( &buf.front() );
181
182         for( typename View::y_coord_t y = 0
183            ; y < src.height()
184            ; ++y
185            )
186         {
187             //copy_pixels( subimage_view( src
188             //                          , 0
189             //                          , (int) y
190             //                          , (int) src.width()
191             //                          , 1
192             //                          )
193             //           , row
194             //           );
195
196             std::copy( src.row_begin( y )
197                      , src.row_end  ( y )
198                      , buf.begin()
199                      );
200
201             this->_io_dev.write( row_addr, pitch );
202         }
203     }
204 };
205
206 ///
207 /// PNM Writer
208 ///
209 template< typename Device >
210 class dynamic_image_writer< Device
211                           , pnm_tag
212                           >
213     : public writer< Device
214                    , pnm_tag
215                    >
216 {
217     using parent_t = writer<Device, pnm_tag>;
218
219 public:
220
221     dynamic_image_writer( const Device&                      io_dev
222                         , const image_write_info< pnm_tag >& info
223                         )
224     : parent_t( io_dev
225               , info
226               )
227     {}
228
229     template< typename Views >
230     void apply( const any_image_view< Views >& views )
231     {
232         detail::dynamic_io_fnobj< detail::pnm_write_is_supported
233                                 , parent_t
234                                 > op( this );
235
236         apply_operation( views, op );
237     }
238 };
239
240 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
241 #pragma warning(pop)
242 #endif
243
244 } // gil
245 } // boost
246
247 #endif