From 3823890b40e2bfaa191b4975b5e4ec587a33a55e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 16:45:58 -0700 Subject: [PATCH] rollback 34c3128b0cea7, move 'scaling' to proper enum, and move image_scaling functions to new cpp/hpp --- bindings/python/mapnik_python.cpp | 2 + bindings/python/mapnik_raster_symbolizer.cpp | 17 +- include/mapnik/image_scaling.hpp | 83 +++++ include/mapnik/image_util.hpp | 33 +- include/mapnik/raster_symbolizer.hpp | 22 +- include/mapnik/warp.hpp | 15 +- src/agg/process_raster_symbolizer.cpp | 51 ++- src/build.py | 1 + src/cairo_renderer.cpp | 50 ++- src/image_scaling.cpp | 359 +++++++++++++++++++ src/image_util.cpp | 321 ----------------- src/load_map.cpp | 23 +- src/save_map.cpp | 5 +- src/warp.cpp | 259 +++++++------ 14 files changed, 686 insertions(+), 555 deletions(-) create mode 100644 include/mapnik/image_scaling.hpp create mode 100644 src/image_scaling.cpp diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index beefea959..f30c35017 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -37,6 +37,7 @@ void export_palette(); void export_image(); void export_image_view(); void export_gamma_method(); +void export_scaling_method(); void export_grid(); void export_grid_view(); void export_map(); @@ -362,6 +363,7 @@ BOOST_PYTHON_MODULE(_mapnik) export_image(); export_image_view(); export_gamma_method(); + export_scaling_method(); export_grid(); export_grid_view(); export_expression(); diff --git a/bindings/python/mapnik_raster_symbolizer.cpp b/bindings/python/mapnik_raster_symbolizer.cpp index dacaea5de..3830dd9f1 100644 --- a/bindings/python/mapnik_raster_symbolizer.cpp +++ b/bindings/python/mapnik_raster_symbolizer.cpp @@ -25,6 +25,7 @@ // mapnik #include +#include using mapnik::raster_symbolizer; @@ -39,13 +40,13 @@ struct raster_symbolizer_pickle_suite : boost::python::pickle_suite */ static boost::python::tuple - getstate(const raster_symbolizer& r) + getstate(raster_symbolizer const& r) { - return boost::python::make_tuple(r.get_mode(),r.get_scaling(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size()); + return boost::python::make_tuple(r.get_mode(),r.get_scaling_method(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size()); } static void - setstate (raster_symbolizer& r, boost::python::tuple state) + setstate (raster_symbolizer & r, boost::python::tuple state) { using namespace boost::python; if (len(state) != 5) @@ -58,7 +59,7 @@ struct raster_symbolizer_pickle_suite : boost::python::pickle_suite } r.set_mode(extract(state[0])); - r.set_scaling(extract(state[1])); + r.set_scaling_method(extract(state[1])); r.set_opacity(extract(state[2])); r.set_filter_factor(extract(state[3])); r.set_mesh_size(extract(state[4])); @@ -91,17 +92,15 @@ void export_raster_symbolizer() ) .add_property("scaling", - make_function(&raster_symbolizer::get_scaling,return_value_policy()), - &raster_symbolizer::set_scaling, + &raster_symbolizer::get_scaling_method, + &raster_symbolizer::set_scaling_method, "Get/Set scaling algorithm.\n" - "Possible values are:\n" - "fast, bilinear, and bilinear8\n" "\n" "Usage:\n" "\n" ">>> from mapnik import RasterSymbolizer\n" ">>> r = RasterSymbolizer()\n" - ">>> r.scaling = 'bilinear8'\n" + ">>> r.scaling = 'mapnik.scaling_method.GAUSSIAN'\n" ) .add_property("opacity", diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp new file mode 100644 index 000000000..89e5fcd69 --- /dev/null +++ b/include/mapnik/image_scaling.hpp @@ -0,0 +1,83 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#ifndef MAPNIK_IMAGE_SCALING_HPP +#define MAPNIK_IMAGE_SCALING_HPP + +// stl +#include + +#include +#include + +namespace mapnik +{ + +enum scaling_method_e +{ + SCALING_NEAR=0, + SCALING_BILINEAR, + SCALING_BICUBIC, + SCALING_SPLINE16, + SCALING_SPLINE36, + SCALING_HANNING, + SCALING_HAMMING, + SCALING_HERMITE, + SCALING_KAISER, + SCALING_QUADRIC, + SCALING_CATROM, + SCALING_GAUSSIAN, + SCALING_BESSEL, + SCALING_MITCHELL, + SCALING_SINC, + SCALING_LANCZOS, + SCALING_BLACKMAN, + SCALING_BILINEAR8 +}; + +boost::optional scaling_method_from_string(std::string const& name); +boost::optional scaling_method_to_string(scaling_method_e scaling_method); + +template +void scale_image_agg(Image & target, + Image const& source, + scaling_method_e scaling_method, + double scale_factor, + double x_off_f=0, + double y_off_f=0, + double filter_radius=2, + double ratio=1); + +template +void scale_image_bilinear_old(Image & target, + Image const& source, + double x_off_f=0, + double y_off_f=0); + +template +void scale_image_bilinear8(Image & target, + Image const& source, + double x_off_f=0, + double y_off_f=0); + +} +#endif // MAPNIK_IMAGE_SCALING_HPP diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index eb8f7561c..0f438eeb8 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -61,7 +61,7 @@ public: MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, std::string const& type, - double scale_factor); + double scale_factor=1.0); #endif template @@ -185,38 +185,7 @@ void add_border(T & image) } } -// IMAGE SCALING -enum scaling_method_e -{ - SCALING_NEAR=0, - SCALING_BILINEAR=1, - SCALING_BICUBIC=2, - SCALING_SPLINE16=3, - SCALING_SPLINE36=4, - SCALING_HANNING=5, - SCALING_HAMMING=6, - SCALING_HERMITE=7, - SCALING_KAISER=8, - SCALING_QUADRIC=9, - SCALING_CATROM=10, - SCALING_GAUSSIAN=11, - SCALING_BESSEL=12, - SCALING_MITCHELL=13, - SCALING_SINC=14, - SCALING_LANCZOS=15, - SCALING_BLACKMAN=16 -}; -scaling_method_e get_scaling_method_by_name (std::string name); - -template -void scale_image_agg (Image& target,const Image& source, scaling_method_e scaling_method, double scale_factor, double x_off_f=0, double y_off_f=0, double filter_radius=2, double ratio=1); - -template -void scale_image_bilinear_old (Image& target,const Image& source, double x_off_f=0, double y_off_f=0); - -template -void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f=0, double y_off_f=0); /////////// save_to_file //////////////////////////////////////////////// class image_32; diff --git a/include/mapnik/raster_symbolizer.hpp b/include/mapnik/raster_symbolizer.hpp index 41561ca9a..192d70a7c 100644 --- a/include/mapnik/raster_symbolizer.hpp +++ b/include/mapnik/raster_symbolizer.hpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace mapnik { @@ -39,7 +40,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base raster_symbolizer() : symbolizer_base(), mode_("normal"), - scaling_("fast"), + scaling_(SCALING_NEAR), opacity_(1.0), colorizer_(), filter_factor_(-1), @@ -47,9 +48,9 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base raster_symbolizer(const raster_symbolizer &rhs) : symbolizer_base(rhs), - mode_(rhs.get_mode()), - scaling_(rhs.get_scaling()), - opacity_(rhs.get_opacity()), + mode_(rhs.mode_), + scaling_(rhs.scaling_), + opacity_(rhs.opacity_), colorizer_(rhs.colorizer_), filter_factor_(rhs.filter_factor_), mesh_size_(rhs.mesh_size_) {} @@ -76,11 +77,11 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode into comp-op"; } } - std::string const& get_scaling() const + scaling_method_e get_scaling_method() const { return scaling_; } - void set_scaling(std::string const& scaling) + void set_scaling_method(scaling_method_e scaling) { scaling_ = scaling; } @@ -115,13 +116,9 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base // respect explicitly specified values return filter_factor_; } else { - // No filter factor specified, calculate a sensible default value - // based on the scaling algorithm being employed. - scaling_method_e scaling = get_scaling_method_by_name (scaling_); - double ff = 1.0; - switch(scaling) + switch(scaling_) { case SCALING_NEAR: ff = 1.0; @@ -130,6 +127,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base // TODO potentially some of these algorithms would use filter_factor >2.0. // Contributions welcome from someone who knows more about them. case SCALING_BILINEAR: + case SCALING_BILINEAR8: case SCALING_BICUBIC: case SCALING_SPLINE16: case SCALING_SPLINE36: @@ -163,7 +161,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base private: std::string mode_; - std::string scaling_; + scaling_method_e scaling_; float opacity_; raster_colorizer_ptr colorizer_; double filter_factor_; diff --git a/include/mapnik/warp.hpp b/include/mapnik/warp.hpp index 035df63c0..f7e5ddcd9 100644 --- a/include/mapnik/warp.hpp +++ b/include/mapnik/warp.hpp @@ -26,16 +26,17 @@ // mapnik #include #include +#include namespace mapnik { -void reproject_raster(raster &target, raster const& source, - proj_transform const& prj_trans, - double offset_x, double offset_y, - unsigned mesh_size, - double filter_radius, - double scale_factor, - std::string scaling_method_name); +void reproject_and_scale_raster(raster & target, + raster const& source, + proj_transform const& prj_trans, + double offset_x, double offset_y, + unsigned mesh_size, + double filter_radius, + scaling_method_e scaling_method); } diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index ccf2c3d65..ec4fdc97a 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -22,6 +22,7 @@ // mapnik #include +#include #include #include #include @@ -44,7 +45,7 @@ void agg_renderer::process(raster_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - raster_ptr const& source=feature.get_raster(); + raster_ptr const& source = feature.get_raster(); if (source) { // If there's a colorizer defined, use it to color the raster in-place @@ -54,28 +55,44 @@ void agg_renderer::process(raster_symbolizer const& sym, box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); - - box2d ext=t_.forward(target_ext); - int start_x = (int)ext.minx(); - int start_y = (int)ext.miny(); - int end_x = (int)ceil(ext.maxx()); - int end_y = (int)ceil(ext.maxy()); + box2d ext = t_.forward(target_ext); + int start_x = static_cast(ext.minx()); + int start_y = static_cast(ext.miny()); + int end_x = static_cast(ceil(ext.maxx())); + int end_y = static_cast(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; - double err_offs_x = ext.minx() - start_x; - double err_offs_y = ext.miny() - start_y; - if (raster_width > 0 && raster_height > 0) { image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); - - reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, - sym.get_mesh_size(), - sym.calculate_filter_factor(), - scale_factor_, - sym.get_scaling()); - + scaling_method_e scaling_method = sym.get_scaling_method(); + double filter_radius = sym.calculate_filter_factor(); + double offset_x = ext.minx() - start_x; + double offset_y = ext.miny() - start_y; + if (!prj_trans.equal()) + { + reproject_and_scale_raster(target, *source, prj_trans, + offset_x, offset_y, + sym.get_mesh_size(), + filter_radius, + scaling_method); + } + else + { + if (scaling_method == SCALING_BILINEAR8){ + scale_image_bilinear8(target.data_,source->data_, offset_x, offset_y); + } else { + double scaling_ratio = ext.width() / source->data_.width(); + scale_image_agg(target.data_, + source->data_, + scaling_method, + scaling_ratio, + offset_x, + offset_y, + filter_radius); + } + } composite(current_buffer_->data(), target.data_, sym.comp_op(), sym.get_opacity(), start_x, start_y, true); } } diff --git a/src/build.py b/src/build.py index f34a067d8..b995bd24a 100644 --- a/src/build.py +++ b/src/build.py @@ -103,6 +103,7 @@ source = Split( color.cpp conversions.cpp image_compositing.cpp + image_scaling.cpp box2d.cpp building_symbolizer.cpp datasource_cache.cpp diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 094d665b2..70709af8c 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1344,32 +1344,46 @@ void cairo_renderer_base::process(raster_symbolizer const& sym, box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); - - box2d ext=t_.forward(target_ext); - int start_x = (int)ext.minx(); - int start_y = (int)ext.miny(); - int end_x = (int)ceil(ext.maxx()); - int end_y = (int)ceil(ext.maxy()); + box2d ext = t_.forward(target_ext); + int start_x = static_cast(ext.minx()); + int start_y = static_cast(ext.miny()); + int end_x = static_cast(ceil(ext.maxx())); + int end_y = static_cast(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; - double err_offs_x = ext.minx() - start_x; - double err_offs_y = ext.miny() - start_y; - if (raster_width > 0 && raster_height > 0) { - double scale_factor = ext.width() / source->data_.width(); image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); - - reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, - sym.get_mesh_size(), - sym.calculate_filter_factor(), - scale_factor, - sym.get_scaling()); - + scaling_method_e scaling_method = sym.get_scaling_method(); + double filter_radius = sym.calculate_filter_factor(); + double offset_x = ext.minx() - start_x; + double offset_y = ext.miny() - start_y; + if (!prj_trans.equal()) + { + reproject_and_scale_raster(target, *source, prj_trans, + offset_x, offset_y, + sym.get_mesh_size(), + filter_radius, + scaling_method); + } + else + { + if (scaling_method == SCALING_BILINEAR8){ + scale_image_bilinear8(target.data_,source->data_, offset_x, offset_y); + } else { + double scaling_ratio = ext.width() / source->data_.width(); + scale_image_agg(target.data_, + source->data_, + scaling_method, + scaling_ratio, + offset_x, + offset_y, + filter_radius); + } + } cairo_context context(context_); context.set_operator(sym.comp_op()); - //TODO -- support for advanced image merging context.add_image(start_x, start_y, target.data_, sym.get_opacity()); } } diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp new file mode 100644 index 000000000..c9ea1e862 --- /dev/null +++ b/src/image_scaling.cpp @@ -0,0 +1,359 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +// mapnik +#include +#include +#include + +// boost +#include +#include + +// agg +#include "agg_image_accessors.h" +#include "agg_pixfmt_rgba.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_rendering_buffer.h" +#include "agg_scanline_u.h" +#include "agg_span_allocator.h" +#include "agg_span_image_filter_rgba.h" +#include "agg_span_interpolator_linear.h" +#include "agg_trans_affine.h" +#include "agg_image_filters.h" + +namespace mapnik +{ + +typedef boost::bimap scaling_method_lookup_type; +static const scaling_method_lookup_type scaling_lookup = boost::assign::list_of + (SCALING_NEAR,"near") + (SCALING_BILINEAR,"bilinear") + (SCALING_BICUBIC,"bicubic") + (SCALING_SPLINE16,"spline16") + (SCALING_SPLINE36,"spline36") + (SCALING_HANNING,"hanning") + (SCALING_HAMMING,"hamming") + (SCALING_HERMITE,"hermite") + (SCALING_KAISER,"kaiser") + (SCALING_QUADRIC,"quadric") + (SCALING_CATROM,"catrom") + (SCALING_GAUSSIAN,"gaussian") + (SCALING_BESSEL,"bessel") + (SCALING_MITCHELL,"mitchell") + (SCALING_SINC,"sinc") + (SCALING_LANCZOS,"lanczos") + (SCALING_BLACKMAN,"blackman") + (SCALING_BILINEAR8,"bilinear8") + ; + +boost::optional scaling_method_from_string(std::string const& name) +{ + boost::optional mode; + scaling_method_lookup_type::right_const_iterator right_iter = scaling_lookup.right.find(name); + if (right_iter != scaling_lookup.right.end()) + { + mode.reset(right_iter->second); + } + return mode; +} + +boost::optional scaling_method_to_string(scaling_method_e scaling_method) +{ + boost::optional mode; + scaling_method_lookup_type::left_const_iterator left_iter = scaling_lookup.left.find(scaling_method); + if (left_iter != scaling_lookup.left.end()) + { + mode.reset(left_iter->second); + } + return mode; +} + +// this has been replaced by agg impl - see https://trac.mapnik.org/ticket/656 +template +void scale_image_bilinear_old (Image & target,Image const& source, double x_off_f, double y_off_f) +{ + + int source_width=source.width(); + int source_height=source.height(); + + int target_width=target.width(); + int target_height=target.height(); + + if (source_width<1 || source_height<1 || + target_width<1 || target_height<1) return; + int x=0,y=0,xs=0,ys=0; + int tw2 = target_width/2; + int th2 = target_height/2; + int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); + int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); + unsigned yprt, yprt1, xprt, xprt1; + + //no scaling or subpixel offset + if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ + for (y=0;y=source_height) + ys1--; + if (ys<0) + ys=ys1=0; + if (source_height/2=source_width) + xs1--; + if (xs<0) + xs=xs1=0; + + unsigned a = source(xs,ys); + unsigned b = source(xs1,ys); + unsigned c = source(xs,ys1); + unsigned d = source(xs1,ys1); + unsigned out=0; + unsigned t = 0; + + for(int i=0; i<4; i++){ + unsigned p,r,s; + // X axis + p = a&0xff; + r = b&0xff; + if (p!=r) + r = (r*xprt+p*xprt1+tw2)/target_width; + p = c&0xff; + s = d&0xff; + if (p!=s) + s = (s*xprt+p*xprt1+tw2)/target_width; + // Y axis + if (r!=s) + r = (s*yprt+r*yprt1+th2)/target_height; + // channel up + out |= r << t; + t += 8; + a >>= 8; + b >>= 8; + c >>= 8; + d >>= 8; + } + target(x,y)=out; + } + } +} + + +template +void scale_image_bilinear8 (Image & target,Image const& source, double x_off_f, double y_off_f) +{ + + int source_width=source.width(); + int source_height=source.height(); + + int target_width=target.width(); + int target_height=target.height(); + + if (source_width<1 || source_height<1 || + target_width<1 || target_height<1) return; + int x=0,y=0,xs=0,ys=0; + int tw2 = target_width/2; + int th2 = target_height/2; + int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); + int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); + unsigned yprt, yprt1, xprt, xprt1; + + //no scaling or subpixel offset + if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ + for (y=0;y=source_height) + ys1--; + if (ys<0) + ys=ys1=0; + if (source_height/2=source_width) + xs1--; + if (xs<0) + xs=xs1=0; + + unsigned a = source(xs,ys); + unsigned b = source(xs1,ys); + unsigned c = source(xs,ys1); + unsigned d = source(xs1,ys1); + unsigned p,r,s; + // X axis + p = a&0xff; + r = b&0xff; + if (p!=r) + r = (r*xprt+p*xprt1+tw2)/target_width; + p = c&0xff; + s = d&0xff; + if (p!=s) + s = (s*xprt+p*xprt1+tw2)/target_width; + // Y axis + if (r!=s) + r = (s*yprt+r*yprt1+th2)/target_height; + target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r; + } + } +} + +template +void scale_image_agg(Image & target, + Image const& source, + scaling_method_e scaling_method, + double image_ratio, + double x_off_f, + double y_off_f, + double filter_radius, + double ratio) +{ + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::pixfmt_rgba32_pre pixfmt_pre; + typedef agg::renderer_base 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((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); + pixfmt pixf_src(rbuf_src); + typedef agg::image_accessor_clone img_src_type; + img_src_type img_src(pixf_src); + + // initialise destination AGG buffer (with transparency) + agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); + pixfmt_pre pixf_dst(rbuf_dst); + renderer_base rb_dst(pixf_dst); + rb_dst.clear(agg::rgba(0, 0, 0, 0)); + + // create a scaling matrix + agg::trans_affine img_mtx; + img_mtx /= agg::trans_affine_scaling(image_ratio * ratio, image_ratio * ratio); + + // create a linear interpolator for our scaling matrix + typedef agg::span_interpolator_linear<> interpolator_type; + interpolator_type interpolator(img_mtx); + + // draw an anticlockwise polygon to render our image into + double scaled_width = source.width() * image_ratio; + double scaled_height = source.height() * image_ratio; + 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: + { + typedef agg::span_image_filter_rgba_nn span_gen_type; + span_gen_type sg(img_src, interpolator); + agg::render_scanlines_aa(ras, sl, rb_dst, 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_radius), true); break; + case SCALING_LANCZOS: + filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; + case SCALING_BLACKMAN: + filter.calculate(agg::image_filter_blackman(filter_radius), true); break; + } + typedef mapnik::span_image_resample_rgba_affine span_gen_type; + span_gen_type sg(img_src, interpolator, filter); + agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); +} + +template void scale_image_agg (image_data_32& target,const image_data_32& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio); + +template void scale_image_bilinear_old (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); + +template void scale_image_bilinear8 (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); + + +} diff --git a/src/image_util.cpp b/src/image_util.cpp index 7cebf19e4..741e07eda 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -35,7 +35,6 @@ extern "C" #include #include #include -#include // jpeg #if defined(HAVE_JPEG) #include @@ -56,20 +55,6 @@ extern "C" #include #include -// agg -#include "agg_image_accessors.h" -#include "agg_pixfmt_rgba.h" -#include "agg_rasterizer_scanline_aa.h" -#include "agg_renderer_scanline.h" -#include "agg_rendering_buffer.h" -#include "agg_scanline_u.h" -//#include "agg_scanline_p.h" -#include "agg_span_allocator.h" -#include "agg_span_image_filter_rgba.h" -#include "agg_span_interpolator_linear.h" -#include "agg_trans_affine.h" -#include "agg_image_filters.h" - namespace mapnik { @@ -477,306 +462,6 @@ template std::string save_to_string > (image_view -void scale_image_bilinear_old (Image& target,const Image& source, double x_off_f, double y_off_f) -{ - - int source_width=source.width(); - int source_height=source.height(); - - int target_width=target.width(); - int target_height=target.height(); - - if (source_width<1 || source_height<1 || - target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; - int tw2 = target_width/2; - int th2 = target_height/2; - int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); - int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt, yprt1, xprt, xprt1; - - //no scaling or subpixel offset - if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ - for (y=0;y=source_height) - ys1--; - if (ys<0) - ys=ys1=0; - if (source_height/2=source_width) - xs1--; - if (xs<0) - xs=xs1=0; - - unsigned a = source(xs,ys); - unsigned b = source(xs1,ys); - unsigned c = source(xs,ys1); - unsigned d = source(xs1,ys1); - unsigned out=0; - unsigned t = 0; - - for(int i=0; i<4; i++){ - unsigned p,r,s; - // X axis - p = a&0xff; - r = b&0xff; - if (p!=r) - r = (r*xprt+p*xprt1+tw2)/target_width; - p = c&0xff; - s = d&0xff; - if (p!=s) - s = (s*xprt+p*xprt1+tw2)/target_width; - // Y axis - if (r!=s) - r = (s*yprt+r*yprt1+th2)/target_height; - // channel up - out |= r << t; - t += 8; - a >>= 8; - b >>= 8; - c >>= 8; - d >>= 8; - } - target(x,y)=out; - } - } -} - - -template -void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f, double y_off_f) -{ - - int source_width=source.width(); - int source_height=source.height(); - - int target_width=target.width(); - int target_height=target.height(); - - if (source_width<1 || source_height<1 || - target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; - int tw2 = target_width/2; - int th2 = target_height/2; - int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); - int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt, yprt1, xprt, xprt1; - - //no scaling or subpixel offset - if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ - for (y=0;y=source_height) - ys1--; - if (ys<0) - ys=ys1=0; - if (source_height/2=source_width) - xs1--; - if (xs<0) - xs=xs1=0; - - unsigned a = source(xs,ys); - unsigned b = source(xs1,ys); - unsigned c = source(xs,ys1); - unsigned d = source(xs1,ys1); - unsigned p,r,s; - // X axis - p = a&0xff; - r = b&0xff; - if (p!=r) - r = (r*xprt+p*xprt1+tw2)/target_width; - p = c&0xff; - s = d&0xff; - if (p!=s) - s = (s*xprt+p*xprt1+tw2)/target_width; - // Y axis - if (r!=s) - r = (s*yprt+r*yprt1+th2)/target_height; - target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r; - } - } -} - -template -void scale_image_agg (Image& target,const Image& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio) -{ - typedef agg::pixfmt_rgba32 pixfmt; - typedef agg::pixfmt_rgba32_pre pixfmt_pre; - typedef agg::renderer_base 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((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); - pixfmt pixf_src(rbuf_src); - typedef agg::image_accessor_clone img_src_type; - img_src_type img_src(pixf_src); - - // initialise destination AGG buffer (with transparency) - agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); - pixfmt_pre pixf_dst(rbuf_dst); - renderer_base rb_dst(pixf_dst); - rb_dst.clear(agg::rgba(0, 0, 0, 0)); - - // create a scaling matrix - agg::trans_affine img_mtx; - img_mtx /= agg::trans_affine_scaling(scale_factor * ratio, scale_factor * ratio); - - // create a linear interpolator for our scaling matrix - typedef agg::span_interpolator_linear<> interpolator_type; - interpolator_type interpolator(img_mtx); - - // draw an anticlockwise polygon to render our image into - double scaled_width = source.width() * scale_factor; - double scaled_height = source.height() * scale_factor; - 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: - { - typedef agg::span_image_filter_rgba_nn span_gen_type; - span_gen_type sg(img_src, interpolator); - agg::render_scanlines_aa(ras, sl, rb_dst, 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_radius), true); break; - case SCALING_LANCZOS: - filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; - case SCALING_BLACKMAN: - filter.calculate(agg::image_filter_blackman(filter_radius), true); break; - } - typedef mapnik::span_image_resample_rgba_affine span_gen_type; - span_gen_type sg(img_src, interpolator, filter); - agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); -} - - void save_to_file(image_32 const& image,std::string const& file) { save_to_file(image.data(), file); @@ -810,10 +495,4 @@ std::string save_to_string(image_32 const& image, return save_to_string(image.data(), type, palette); } -template void scale_image_agg (image_data_32& target,const image_data_32& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio); - -template void scale_image_bilinear_old (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); - -template void scale_image_bilinear8 (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); - } diff --git a/src/load_map.cpp b/src/load_map.cpp index 27cce14b7..14a7eedb2 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1468,7 +1469,27 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym) // scaling optional scaling = sym.get_opt_attr("scaling"); - if (scaling) raster_sym.set_scaling(*scaling); + if (scaling) + { + std::string scaling_method = *scaling; + if (scaling_method == "fast") + { + MAPNIK_LOG_ERROR(raster_symbolizer) << "'scaling' value of 'fast' is deprecated and will be removed in Mapnik 3.x, use 'near' with Mapnik >= 2.1.x"; + raster_sym.set_scaling_method(SCALING_NEAR); + } + else + { + boost::optional method = scaling_method_from_string(scaling_method); + if (method) + { + raster_sym.set_scaling_method(*method); + } + else + { + throw config_error("failed to parse 'scaling': '" + *scaling + "'"); + } + } + } // opacity optional opacity = sym.get_opt_attr("opacity"); diff --git a/src/save_map.cpp b/src/save_map.cpp index e7e5923ab..b4b4946a5 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // boost #include @@ -158,9 +159,9 @@ public: ptree::value_type("RasterSymbolizer", ptree()))->second; raster_symbolizer dfl; - if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) + if ( sym.get_scaling_method() != dfl.get_scaling_method() || explicit_defaults_ ) { - set_attr( sym_node, "scaling", sym.get_scaling() ); + set_attr( sym_node, "scaling", *scaling_method_to_string(sym.get_scaling_method()) ); } if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) diff --git a/src/warp.cpp b/src/warp.cpp index 1033e062a..ee0dc6a05 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -46,162 +46,149 @@ namespace mapnik { -void reproject_raster(raster &target, raster const& source, +void reproject_and_scale_raster(raster & target, raster const& source, proj_transform const& prj_trans, double offset_x, double offset_y, unsigned mesh_size, double filter_radius, - double scale_factor, - std::string scaling_method_name) + scaling_method_e scaling_method) { - if (prj_trans.equal()) { + CoordTransform ts(source.data_.width(), source.data_.height(), + source.ext_); + CoordTransform tt(target.data_.width(), target.data_.height(), + target.ext_, offset_x, offset_y); + unsigned i, j; + unsigned mesh_nx = ceil(source.data_.width()/double(mesh_size)+1); + unsigned mesh_ny = ceil(source.data_.height()/double(mesh_size)+1); - if (scaling_method_name == "bilinear8"){ - scale_image_bilinear8(target.data_,source.data_, - offset_x, offset_y); - } else { - scaling_method_e scaling_method = get_scaling_method_by_name(scaling_method_name); - scale_image_agg(target.data_,source.data_, (scaling_method_e)scaling_method, scale_factor, offset_x, offset_y, filter_radius); + ImageData xs(mesh_nx, mesh_ny); + ImageData ys(mesh_nx, mesh_ny); + + // Precalculate reprojected mesh + for(j=0; j xs(mesh_nx, mesh_ny); - ImageData ys(mesh_nx, mesh_ny); + // Initialize AGG objects + typedef agg::pixfmt_rgba32 pixfmt; + typedef pixfmt::color_type color_type; + typedef agg::renderer_base renderer_base; + typedef agg::pixfmt_rgba32_pre pixfmt_pre; + typedef agg::renderer_base renderer_base_pre; - // Precalculate reprojected mesh - for(j=0; j rasterizer; + agg::scanline_u8 scanline; + agg::rendering_buffer buf((unsigned char*)target.data_.getData(), + target.data_.width(), + target.data_.height(), + target.data_.width()*4); + pixfmt_pre pixf_pre(buf); + renderer_base_pre rb_pre(pixf_pre); + rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); + agg::rendering_buffer buf_tile( + (unsigned char*)source.data_.getData(), + source.data_.width(), + source.data_.height(), + source.data_.width() * 4); - // Initialize AGG objects - typedef agg::pixfmt_rgba32 pixfmt; - typedef pixfmt::color_type color_type; - typedef agg::renderer_base renderer_base; - typedef agg::pixfmt_rgba32_pre pixfmt_pre; - typedef agg::renderer_base renderer_base_pre; + pixfmt pixf_tile(buf_tile); - agg::rasterizer_scanline_aa<> rasterizer; - agg::scanline_u8 scanline; - agg::rendering_buffer buf((unsigned char*)target.data_.getData(), - target.data_.width(), - target.data_.height(), - target.data_.width()*4); - pixfmt_pre pixf_pre(buf); - renderer_base_pre rb_pre(pixf_pre); - rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); - agg::rendering_buffer buf_tile( - (unsigned char*)source.data_.getData(), - source.data_.width(), - source.data_.height(), - source.data_.width() * 4); + typedef agg::image_accessor_clone img_accessor_type; + img_accessor_type ia(pixf_tile); - pixfmt pixf_tile(buf_tile); + agg::span_allocator sa; - typedef agg::image_accessor_clone img_accessor_type; - img_accessor_type ia(pixf_tile); + // Initialize filter + agg::image_filter_lut filter; + switch(scaling_method) + { + case SCALING_NEAR: break; + case SCALING_BILINEAR8: // TODO - impl this or remove? + 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_radius), true); break; + case SCALING_LANCZOS: + filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; + case SCALING_BLACKMAN: + filter.calculate(agg::image_filter_blackman(filter_radius), true); break; + } - agg::span_allocator sa; + // Project mesh cells into target interpolating raster inside each one + for(j=0; j + interpolator_type; + interpolator_type interpolator(tr); - unsigned x0 = i * mesh_size; - unsigned y0 = j * mesh_size; - unsigned x1 = (i+1) * mesh_size; - unsigned y1 = (j+1) * mesh_size; - - agg::trans_affine tr(polygon, x0, y0, x1, y1); - if (tr.is_valid()) - { - typedef agg::span_interpolator_linear - interpolator_type; - interpolator_type interpolator(tr); - - if (scaling_method == SCALING_NEAR) { - typedef agg::span_image_filter_rgba_nn - - span_gen_type; - span_gen_type sg(ia, interpolator); - agg::render_scanlines_aa(rasterizer, scanline, rb_pre, - sa, sg); - } else { - typedef mapnik::span_image_resample_rgba_affine - span_gen_type; - span_gen_type sg(ia, interpolator, filter); - agg::render_scanlines_aa(rasterizer, scanline, rb_pre, - sa, sg); - } + if (scaling_method == SCALING_NEAR) { + typedef agg::span_image_filter_rgba_nn + + span_gen_type; + span_gen_type sg(ia, interpolator); + agg::render_scanlines_aa(rasterizer, scanline, rb_pre, + sa, sg); + } else { + typedef mapnik::span_image_resample_rgba_affine + span_gen_type; + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(rasterizer, scanline, rb_pre, + sa, sg); } - } + } } }