From 271f5fdf3c4d04ca502b20768ac3a4b342b121fe Mon Sep 17 00:00:00 2001 From: William Gallafent Date: Wed, 21 May 2014 21:40:15 +0100 Subject: [PATCH] Initial implementation of premultiplier, which is used when saving TIFF (since by convention this uses premultiplied alpha) --- .../gil/extension/io/formats/tiff/write.hpp | 36 ++++++--- include/boost/gil/premultiply.hpp | 77 +++++++++++++++++++ 2 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 include/boost/gil/premultiply.hpp diff --git a/include/boost/gil/extension/io/formats/tiff/write.hpp b/include/boost/gil/extension/io/formats/tiff/write.hpp index 21b8fb7d0..1a821bee6 100644 --- a/include/boost/gil/extension/io/formats/tiff/write.hpp +++ b/include/boost/gil/extension/io/formats/tiff/write.hpp @@ -30,6 +30,8 @@ extern "C" { #include #include +#include + #include #include @@ -177,12 +179,17 @@ private: typedef typename View::x_iterator x_it_t; x_it_t row_it = x_it_t( &(*row.begin())); - for( typename View::y_coord_t y = 0; y < view.height(); ++y ) + // @todo: is there an overhead to doing this when there's no + // alpha to premultiply by? I'd hope it's optimised out. + auto pm_view = premultiply_view (view); + + for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y ) { - std::copy( view.row_begin( y ) - , view.row_end( y ) - , row_it - ); + std::copy( pm_view.row_begin( y ) + , pm_view.row_end( y ) + , row_it + ); + this->_io_dev.write_scaline( row , (uint32) y @@ -192,8 +199,8 @@ private: // @todo: do optional bit swapping here if you need to... } } - - template< typename View > + + template< typename View> void write_tiled_data( const View& view , tiff_tile_width::type tw , tiff_tile_length::type th @@ -221,12 +228,16 @@ private: byte_t* row_addr = reinterpret_cast< byte_t* >( &row.front() ); - for( typename View::y_coord_t y = 0; y < view.height(); ++y ) + // @todo: is there an overhead to doing this when there's no + // alpha to premultiply by? I'd hope it's optimised out. + auto pm_view = premultiply_view (view); + + for( typename View::y_coord_t y = 0; y < pm_view.height(); ++y ) { - std::copy( view.row_begin( y ) - , view.row_end ( y ) - , row.begin() - ); + std::copy( pm_view.row_begin( y ) + , pm_view.row_end( y ) + , row.begin() + ); this->_io_dev.write_scaline( row_addr , (uint32) y @@ -253,6 +264,7 @@ private: internal_write_tiled_data(view, tw, th, row, row_it); } + // @todo: premultiply template< typename View, typename IteratorType > diff --git a/include/boost/gil/premultiply.hpp b/include/boost/gil/premultiply.hpp new file mode 100644 index 000000000..c6eb157fe --- /dev/null +++ b/include/boost/gil/premultiply.hpp @@ -0,0 +1,77 @@ +#ifndef PREMULTIPLY_HPP +#define PREMULTIPLY_HPP + +#include + +#include +#include + +namespace boost { namespace gil { + +template +struct channel_premultiply { + channel_premultiply (SrcP const & src, DstP & dst) + : src_ (src), dst_ (dst) + {} + + template + void operator () (Channel c) const { + // @todo: need to do a “channel_convert” too, in case the channel types aren't the same? + get_color (dst_, Channel()) = channel_multiply(get_color(src_,Channel()), alpha_or_max(src_)); + } + SrcP const & src_; + DstP & dst_; +}; + +struct premultiply { + template + void operator()(const SrcP& src, DstP& dst) const { + typedef typename color_space_type::type src_colour_space_t; + typedef typename color_space_type::type dst_colour_space_t; + typedef typename mpl:: remove :: type src_colour_channels; + mpl:: for_each ( channel_premultiply (src, dst) ); + if (mpl:: contains :: value) + get_color (dst,alpha_t()) = alpha_or_max (src); + } +}; + +template // Destination pixel value (models PixelValueConcept) +class premultiply_deref_fn { +public: + typedef premultiply_deref_fn const_t; + typedef DstP value_type; + typedef value_type reference; // read-only dereferencing + typedef const value_type& const_reference; + typedef SrcConstRefP argument_type; + typedef reference result_type; + BOOST_STATIC_CONSTANT(bool, is_mutable=false); + + result_type operator()(argument_type srcP) const { + result_type dstP; + premultiply () (srcP,dstP); + return dstP; + } +}; + +template +struct premultiplied_view_type { +private: + typedef typename SrcView::const_t::reference src_pix_ref; // const reference to pixel in SrcView + typedef premultiply_deref_fn deref_t; // the dereference adaptor that performs color conversion + typedef typename SrcView::template add_deref add_ref_t; +public: + typedef typename add_ref_t::type type; // the color converted view type + static type make(const SrcView& sv) { return add_ref_t::make(sv, deref_t()); } +}; + +template inline +typename premultiplied_view_type::type premultiply_view(const View& src) { + return premultiplied_view_type::make(src); +} + + } +} + + +#endif