diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp index c3ae15129..0c36e396e 100644 --- a/include/mapnik/image_scaling.hpp +++ b/include/mapnik/image_scaling.hpp @@ -60,42 +60,13 @@ enum scaling_method_e MAPNIK_DECL boost::optional scaling_method_from_string(std::string const& name); MAPNIK_DECL boost::optional scaling_method_to_string(scaling_method_e scaling_method); -MAPNIK_DECL void scale_image_agg(image_data_gray8 & target, - image_data_gray8 const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor); - -MAPNIK_DECL void scale_image_agg(image_data_gray32f & target, - image_data_gray32f const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor); - -MAPNIK_DECL void scale_image_agg(image_data_gray16 & target, - image_data_gray16 const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor); - -MAPNIK_DECL void scale_image_agg(image_data_rgba8 & target, - image_data_rgba8 const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor); - - +template MAPNIK_DECL void scale_image_agg(T & target, T const& source, + scaling_method_e scaling_method, + double image_ratio_x, + double image_ratio_y, + double x_off_f, + double y_off_f, + double filter_factor); } + #endif // MAPNIK_IMAGE_SCALING_HPP diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index 9d717ea81..ea5d0bd01 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -96,36 +96,89 @@ boost::optional scaling_method_to_string(scaling_method_e scaling_m return mode; } -void scale_image_agg(image_data_rgba8 & target, - image_data_rgba8 const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, + +namespace detail { + +template +struct agg_scaling_traits {}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_rgba32_pre; + using color_type = agg::rgba8; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_rgba_nn; + using span_image_resample_affine = agg::span_image_resample_rgba_affine; + +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray8_pre; + using color_type = agg::gray8; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray16_pre; + using color_type = agg::gray16; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray32_pre; + using color_type = agg::gray32; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +} +template +void scale_image_agg(T & target, T const& source, scaling_method_e scaling_method, + double image_ratio_x, double image_ratio_y, double x_off_f, double y_off_f, double filter_factor) { // "the image filters should work namely in the premultiplied color space" // http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html // "Yes, you need to use premultiplied images only. Only in this case the simple weighted averaging works correctly in the image fitering." // http://permalink.gmane.org/gmane.comp.graphics.agg/3443 - using pixfmt_pre = agg::pixfmt_rgba32_pre; + using image_data_type = T; + using pixel_type = typename image_data_type::pixel_type; + using pixfmt_pre = typename detail::agg_scaling_traits::pixfmt_pre; + using color_type = typename detail::agg_scaling_traits::color_type; + using img_src_type = typename detail::agg_scaling_traits::img_src_type; + using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; using renderer_base_pre = agg::renderer_base; // define some stuff we'll use soon agg::rasterizer_scanline_aa<> ras; agg::scanline_u8 sl; - agg::span_allocator sa; + agg::span_allocator sa; agg::image_filter_lut filter; // initialize source AGG buffer - agg::rendering_buffer rbuf_src(const_cast(source.getBytes()), source.width(), source.height(), source.width() * 4); + agg::rendering_buffer rbuf_src(const_cast(source.getBytes()), source.width(), source.height(), source.width() * sizeof(pixel_type)); pixfmt_pre pixf_src(rbuf_src); - using img_src_type = agg::image_accessor_clone; + img_src_type img_src(pixf_src); // initialize destination AGG buffer (with transparency) - agg::rendering_buffer rbuf_dst(target.getBytes(), target.width(), target.height(), target.width() * 4); + agg::rendering_buffer rbuf_dst(target.getBytes(), target.width(), target.height(), target.width() * sizeof(pixel_type)); pixfmt_pre pixf_dst(rbuf_dst); renderer_base_pre rb_dst_pre(pixf_dst); @@ -134,7 +187,7 @@ void scale_image_agg(image_data_rgba8 & target, img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y); // create a linear interpolator for our scaling matrix - using interpolator_type = agg::span_interpolator_linear<>; + interpolator_type interpolator(img_mtx); // draw an anticlockwise polygon to render our image into @@ -150,7 +203,7 @@ void scale_image_agg(image_data_rgba8 & target, { case SCALING_NEAR: { - using span_gen_type = agg::span_image_filter_rgba_nn; + using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; span_gen_type sg(img_src, interpolator); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); return; @@ -192,7 +245,7 @@ void scale_image_agg(image_data_rgba8 & target, // http://old.nabble.com/Re%3A-Newbie---texture-p5057255.html // high quality resampler - using span_gen_type = agg::span_image_resample_rgba_affine; + using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; // faster, lower quality //using span_gen_type = agg::span_image_filter_rgba; @@ -204,204 +257,19 @@ void scale_image_agg(image_data_rgba8 & target, //using span_gen_type = mapnik::span_image_resample_rgba_affine; span_gen_type sg(img_src, interpolator, filter); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); -} - -void scale_image_agg(image_data_gray8 & target, - image_data_gray8 const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor) -{ - // TODO -} - -void scale_image_agg(image_data_gray32f & target, - image_data_gray32f const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor) -{ - using pixfmt_pre = agg::pixfmt_gray32_pre; - using renderer_base_pre = agg::renderer_base; - - // define some stuff we'll use soon - agg::rasterizer_scanline_aa<> ras; - agg::scanline_u8 sl; - agg::span_allocator sa; - agg::image_filter_lut filter; - - // initialize source AGG buffer - agg::rendering_buffer rbuf_src(const_cast(source.getBytes()), source.width(), source.height(), source.width() * 4); - pixfmt_pre pixf_src(rbuf_src); - using img_src_type = agg::image_accessor_clone; - img_src_type img_src(pixf_src); - - // initialize destination AGG buffer (with transparency) - agg::rendering_buffer rbuf_dst(target.getBytes(), target.width(), target.height(), target.width() * 4); - pixfmt_pre pixf_dst(rbuf_dst); - renderer_base_pre rb_dst_pre(pixf_dst); - - // create a scaling matrix - agg::trans_affine img_mtx; - img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y); - - // create a linear interpolator for our scaling matrix - using interpolator_type = agg::span_interpolator_linear<>; - interpolator_type interpolator(img_mtx); - - // draw an anticlockwise polygon to render our image into - double scaled_width = target.width(); - double scaled_height = target.height(); - ras.reset(); - ras.move_to_d(x_off_f, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); - ras.line_to_d(x_off_f, y_off_f + scaled_height); - - switch(scaling_method) - { - case SCALING_NEAR: - { - using span_gen_type = agg::span_image_filter_gray_nn; - span_gen_type sg(img_src, interpolator); - agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); - return; - } - case SCALING_BILINEAR: - filter.calculate(agg::image_filter_bilinear(), true); break; - case SCALING_BICUBIC: - filter.calculate(agg::image_filter_bicubic(), true); break; - case SCALING_SPLINE16: - filter.calculate(agg::image_filter_spline16(), true); break; - case SCALING_SPLINE36: - filter.calculate(agg::image_filter_spline36(), true); break; - case SCALING_HANNING: - filter.calculate(agg::image_filter_hanning(), true); break; - case SCALING_HAMMING: - filter.calculate(agg::image_filter_hamming(), true); break; - case SCALING_HERMITE: - filter.calculate(agg::image_filter_hermite(), true); break; - case SCALING_KAISER: - filter.calculate(agg::image_filter_kaiser(), true); break; - case SCALING_QUADRIC: - filter.calculate(agg::image_filter_quadric(), true); break; - case SCALING_CATROM: - filter.calculate(agg::image_filter_catrom(), true); break; - case SCALING_GAUSSIAN: - filter.calculate(agg::image_filter_gaussian(), true); break; - case SCALING_BESSEL: - filter.calculate(agg::image_filter_bessel(), true); break; - case SCALING_MITCHELL: - filter.calculate(agg::image_filter_mitchell(), true); break; - case SCALING_SINC: - filter.calculate(agg::image_filter_sinc(filter_factor), true); break; - case SCALING_LANCZOS: - filter.calculate(agg::image_filter_lanczos(filter_factor), true); break; - case SCALING_BLACKMAN: - filter.calculate(agg::image_filter_blackman(filter_factor), true); break; - } - using span_gen_type = agg::span_image_resample_gray_affine; - span_gen_type sg(img_src, interpolator, filter); - agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); -} - -void scale_image_agg(image_data_gray16 & target, - image_data_gray16 const& source, - scaling_method_e scaling_method, - double image_ratio_x, - double image_ratio_y, - double x_off_f, - double y_off_f, - double filter_factor) -{ - using pixfmt_pre = agg::pixfmt_gray16_pre; - using renderer_base_pre = agg::renderer_base; - - // define some stuff we'll use soon - agg::rasterizer_scanline_aa<> ras; - agg::scanline_u8 sl; - agg::span_allocator sa; - agg::image_filter_lut filter; - - // initialize source AGG buffer - agg::rendering_buffer rbuf_src(const_cast(source.getBytes()), source.width(), source.height(), source.width() * 2); - pixfmt_pre pixf_src(rbuf_src); - using img_src_type = agg::image_accessor_clone; - img_src_type img_src(pixf_src); - - // initialize destination AGG buffer (with transparency) - agg::rendering_buffer rbuf_dst(target.getBytes(), target.width(), target.height(), target.width() * 2); - pixfmt_pre pixf_dst(rbuf_dst); - renderer_base_pre rb_dst_pre(pixf_dst); - - // create a scaling matrix - agg::trans_affine img_mtx; - img_mtx /= agg::trans_affine_scaling(image_ratio_x, image_ratio_y); - - // create a linear interpolator for our scaling matrix - using interpolator_type = agg::span_interpolator_linear<>; - interpolator_type interpolator(img_mtx); - - // draw an anticlockwise polygon to render our image into - double scaled_width = target.width(); - double scaled_height = target.height(); - ras.reset(); - ras.move_to_d(x_off_f, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); - ras.line_to_d(x_off_f, y_off_f + scaled_height); - - switch(scaling_method) - { - case SCALING_NEAR: - { - using span_gen_type = agg::span_image_filter_gray_nn; - span_gen_type sg(img_src, interpolator); - agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); - return; - } - case SCALING_BILINEAR: - filter.calculate(agg::image_filter_bilinear(), true); break; - case SCALING_BICUBIC: - filter.calculate(agg::image_filter_bicubic(), true); break; - case SCALING_SPLINE16: - filter.calculate(agg::image_filter_spline16(), true); break; - case SCALING_SPLINE36: - filter.calculate(agg::image_filter_spline36(), true); break; - case SCALING_HANNING: - filter.calculate(agg::image_filter_hanning(), true); break; - case SCALING_HAMMING: - filter.calculate(agg::image_filter_hamming(), true); break; - case SCALING_HERMITE: - filter.calculate(agg::image_filter_hermite(), true); break; - case SCALING_KAISER: - filter.calculate(agg::image_filter_kaiser(), true); break; - case SCALING_QUADRIC: - filter.calculate(agg::image_filter_quadric(), true); break; - case SCALING_CATROM: - filter.calculate(agg::image_filter_catrom(), true); break; - case SCALING_GAUSSIAN: - filter.calculate(agg::image_filter_gaussian(), true); break; - case SCALING_BESSEL: - filter.calculate(agg::image_filter_bessel(), true); break; - case SCALING_MITCHELL: - filter.calculate(agg::image_filter_mitchell(), true); break; - case SCALING_SINC: - filter.calculate(agg::image_filter_sinc(filter_factor), true); break; - case SCALING_LANCZOS: - filter.calculate(agg::image_filter_lanczos(filter_factor), true); break; - case SCALING_BLACKMAN: - filter.calculate(agg::image_filter_blackman(filter_factor), true); break; - } - using span_gen_type = agg::span_image_resample_gray_affine; - span_gen_type sg(img_src, interpolator, filter); - agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); -} + +} + +template void scale_image_agg(image_data_rgba8 &, image_data_rgba8 const&, scaling_method_e, + double, double , double, double , double); + +template void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e, + double, double , double, double , double); + +template void scale_image_agg(image_data_gray16 &, image_data_gray16 const&, scaling_method_e, + double, double , double, double , double); + +template void scale_image_agg(image_data_gray32f &, image_data_gray32f const&, scaling_method_e, + double, double , double, double , double); }