diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index d1d9fe9a5..c72f62daa 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -83,7 +83,7 @@ MAPNIK_DECL boost::optional comp_op_from_string(std::string co MAPNIK_DECL boost::optional comp_op_to_string(composite_mode_e comp_op); template -MAPNIK_DECL void composite(T & dst, T & src, +MAPNIK_DECL void composite(T & dst, T const& src, composite_mode_e mode, float opacity=1, int dx=0, diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 24d604c06..75e9884d2 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -122,8 +122,33 @@ For example, if you generate some pattern with AGG (premultiplied) and would lik */ +namespace detail { + +// non-mutable rendering_buffer implementation +template +struct rendering_buffer +{ + using image_data_type = T; + using pixel_type = typename image_data_type::pixel_type; + using row_data = agg::const_row_info; + + rendering_buffer(T const& data) + : data_(data) {} + + uint8_t const* buf() const { return data_.getBytes(); } + unsigned width() const { return data_.width();} + unsigned height() const { return data_.height();} + int stride() const { return data_.width() * sizeof(pixel_type);} + uint8_t const* row_ptr(int, int y, unsigned) {return row_ptr(y);} + uint8_t const* row_ptr(int y) const { return reinterpret_cast(data_.getRow(y)); } + row_data row (int y) const { return row_data(0, data_.width() - 1, row_ptr(y)); } + image_data_type const& data_; +}; + +} + template <> -MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 & src, composite_mode_e mode, +MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, composite_mode_e mode, float opacity, int dx, int dy, @@ -131,39 +156,39 @@ MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 & src, compo { using color = agg::rgba8; using order = agg::order_rgba; + using const_rendering_buffer = detail::rendering_buffer; using blender_type = agg::comp_op_adaptor_rgba_pre; using pixfmt_type = agg::pixfmt_custom_blend_rgba; using renderer_type = agg::renderer_base; agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.width() * 4); - agg::rendering_buffer src_buffer(src.getBytes(),src.width(),src.height(),src.width() * 4); - + const_rendering_buffer src_buffer(src); pixfmt_type pixf(dst_buffer); pixf.comp_op(static_cast(mode)); - - agg::pixfmt_rgba32 pixf_mask(src_buffer); + agg::pixfmt_alpha_blend_rgba pixf_mask(src_buffer); if (premultiply_src) pixf_mask.premultiply(); renderer_type ren(pixf); ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity)); } template <> -MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f & src, composite_mode_e mode, +MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f const& src, composite_mode_e mode, float opacity, int dx, int dy, bool premultiply_src) { - using pixfmt_type = agg::pixfmt_gray32; - using renderer_type = agg::renderer_base; + using const_rendering_buffer = detail::rendering_buffer; + using src_pixfmt_type = agg::pixfmt_alpha_blend_gray, const_rendering_buffer, 1, 0>; + using dst_pixfmt_type = agg::pixfmt_alpha_blend_gray, agg::rendering_buffer, 1, 0>; + using renderer_type = agg::renderer_base; agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.width()); - agg::rendering_buffer src_buffer(src.getBytes(),src.width(),src.height(),src.width()); - pixfmt_type pixf(dst_buffer); - - agg::pixfmt_gray32 pixf_mask(src_buffer); + const_rendering_buffer src_buffer(src); + dst_pixfmt_type pixf(dst_buffer); + src_pixfmt_type pixf_mask(src_buffer); renderer_type ren(pixf); - ren.copy_from(pixf_mask,0,dx,dy);; + ren.copy_from(pixf_mask,0,dx,dy); } }