File indexing completed on 2025-01-18 09:36:58
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITE_HPP
0009 #define BOOST_GIL_EXTENSION_IO_PNM_DETAIL_WRITE_HPP
0010
0011 #include <boost/gil/extension/io/pnm/tags.hpp>
0012 #include <boost/gil/extension/io/pnm/detail/writer_backend.hpp>
0013
0014 #include <boost/gil/io/base.hpp>
0015 #include <boost/gil/io/bit_operations.hpp>
0016 #include <boost/gil/io/device.hpp>
0017 #include <boost/gil/io/detail/dynamic.hpp>
0018 #include <boost/gil/detail/mp11.hpp>
0019
0020 #include <cstdlib>
0021 #include <string>
0022 #include <type_traits>
0023
0024 namespace boost { namespace gil {
0025
0026 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0027 #pragma warning(push)
0028 #pragma warning(disable:4512)
0029 #endif
0030
0031 namespace detail {
0032
0033 struct pnm_write_is_supported
0034 {
0035 template< typename View >
0036 struct apply
0037 : public is_write_supported< typename get_pixel_type< View >::type
0038 , pnm_tag
0039 >
0040 {};
0041 };
0042
0043 }
0044
0045
0046
0047
0048 template< typename Device >
0049 class writer< Device
0050 , pnm_tag
0051 >
0052 : public writer_backend< Device
0053 , pnm_tag
0054 >
0055 {
0056 private:
0057 using backend_t = writer_backend<Device, pnm_tag>;
0058
0059 public:
0060
0061 writer( const Device& io_dev
0062 , const image_write_info< pnm_tag >& info
0063 )
0064 : backend_t( io_dev
0065 , info
0066 )
0067 {}
0068
0069 template< typename View >
0070 void apply( const View& view )
0071 {
0072 using pixel_t = typename get_pixel_type<View>::type;
0073
0074 std::size_t width = view.width();
0075 std::size_t height = view.height();
0076
0077 std::size_t chn = num_channels< View >::value;
0078 std::size_t pitch = chn * width;
0079
0080 unsigned int type = get_type< num_channels< View >::value >( is_bit_aligned< pixel_t >() );
0081
0082
0083
0084
0085
0086 std::string str( "P" );
0087 str += std::to_string( type ) + std::string( " " );
0088 this->_io_dev.print_line( str );
0089
0090 str.clear();
0091 str += std::to_string( width ) + std::string( " " );
0092 this->_io_dev.print_line( str );
0093
0094 str.clear();
0095 str += std::to_string( height ) + std::string( " " );
0096 this->_io_dev.print_line( str );
0097
0098 if( type != pnm_image_type::mono_bin_t::value )
0099 {
0100 this->_io_dev.print_line( "255 ");
0101 }
0102
0103
0104 write_data( view
0105 , pitch
0106 , typename is_bit_aligned< pixel_t >::type()
0107 );
0108 }
0109
0110 private:
0111
0112 template< int Channels >
0113 unsigned int get_type( std::true_type )
0114 {
0115 return mp11::mp_if_c
0116 <
0117 Channels == 1,
0118 pnm_image_type::mono_bin_t,
0119 pnm_image_type::color_bin_t
0120 >::value;
0121 }
0122
0123 template< int Channels >
0124 unsigned int get_type( std::false_type )
0125 {
0126 return mp11::mp_if_c
0127 <
0128 Channels == 1,
0129 pnm_image_type::gray_bin_t,
0130 pnm_image_type::color_bin_t
0131 >::value;
0132 }
0133
0134 template< typename View >
0135 void write_data( const View& src
0136 , std::size_t pitch
0137 , const std::true_type&
0138 )
0139 {
0140 static_assert(std::is_same<View, typename gray1_image_t::view_t>::value, "");
0141
0142 byte_vector_t row( pitch / 8 );
0143
0144 using x_it_t = typename View::x_iterator;
0145 x_it_t row_it = x_it_t( &( *row.begin() ));
0146
0147 detail::negate_bits<byte_vector_t, std::true_type> negate;
0148 detail::mirror_bits<byte_vector_t, std::true_type> mirror;
0149 for (typename View::y_coord_t y = 0; y < src.height(); ++y)
0150 {
0151 std::copy(src.row_begin(y), src.row_end(y), row_it);
0152
0153 mirror(row);
0154 negate(row);
0155
0156 this->_io_dev.write(&row.front(), pitch / 8);
0157 }
0158 }
0159
0160 template< typename View >
0161 void write_data( const View& src
0162 , std::size_t pitch
0163 , const std::false_type&
0164 )
0165 {
0166 std::vector< pixel< typename channel_type< View >::type
0167 , layout<typename color_space_type< View >::type >
0168 >
0169 > buf( src.width() );
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 byte_t* row_addr = reinterpret_cast< byte_t* >( &buf.front() );
0181
0182 for( typename View::y_coord_t y = 0
0183 ; y < src.height()
0184 ; ++y
0185 )
0186 {
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196 std::copy( src.row_begin( y )
0197 , src.row_end ( y )
0198 , buf.begin()
0199 );
0200
0201 this->_io_dev.write( row_addr, pitch );
0202 }
0203 }
0204 };
0205
0206
0207
0208
0209 template< typename Device >
0210 class dynamic_image_writer< Device
0211 , pnm_tag
0212 >
0213 : public writer< Device
0214 , pnm_tag
0215 >
0216 {
0217 using parent_t = writer<Device, pnm_tag>;
0218
0219 public:
0220
0221 dynamic_image_writer( const Device& io_dev
0222 , const image_write_info< pnm_tag >& info
0223 )
0224 : parent_t( io_dev
0225 , info
0226 )
0227 {}
0228
0229 template< typename ...Views >
0230 void apply( const any_image_view< Views... >& views )
0231 {
0232 detail::dynamic_io_fnobj< detail::pnm_write_is_supported
0233 , parent_t
0234 > op( this );
0235
0236 variant2::visit( op, views );
0237 }
0238 };
0239
0240 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
0241 #pragma warning(pop)
0242 #endif
0243
0244 }
0245 }
0246
0247 #endif