From b0b89e76d1e7268b9bb51c60cc95d152a0c46d91 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 6 Jan 2015 12:44:28 +0100 Subject: [PATCH 01/91] image class - containing image_data_any and initial basic python interface --- bindings/python/mapnik_image.cpp | 28 ++++++++++- include/mapnik/image.hpp | 49 +++++++++++++++++++ src/build.py | 1 + src/image.cpp | 80 ++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 include/mapnik/image.hpp create mode 100644 src/image.cpp diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 5d674be72..4f1b61bc1 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -37,6 +37,7 @@ // mapnik #include #include +#include #include #include #include @@ -48,6 +49,8 @@ #include #endif +using mapnik::image; +using mapnik::image_data_any; using mapnik::image_32; using mapnik::image_reader; using mapnik::get_image_reader; @@ -222,6 +225,21 @@ std::shared_ptr from_cairo(PycairoSurface* py_surface) } #endif +// ============ image any +std::shared_ptr read_from_file_impl(std::string const& filename) +{ + std::shared_ptr img(new image); + std::unique_ptr reader(get_image_reader(filename)); + if (reader) + { + unsigned w = reader->width(); + unsigned h = reader->height(); + img->set_data(reader->read(0, 0, w, h)); + } + return img; +} +// ========================= + void export_image() { using namespace boost::python; @@ -265,7 +283,15 @@ void export_image() .value("divide", mapnik::divide) ; - class_ >("Image","This class represents a 32 bit RGBA image.",init()) + class_, boost::noncopyable > ("ImageAny", "This class represents an any Image object", no_init) + .def("width",&image::width) + .def("height",&image::height) + .def("open", &read_from_file_impl) + .staticmethod("open") + .def("save",&image::save_to_file) + ; + + class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) .def("width",&image_32::width) .def("height",&image_32::height) .def("view",&image_32::get_view) diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp new file mode 100644 index 000000000..d35b2cebc --- /dev/null +++ b/include/mapnik/image.hpp @@ -0,0 +1,49 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_HPP +#define MAPNIK_IMAGE_HPP + +#include +#include + +namespace mapnik { + +class image +{ +public: + image() = default; + inline std::size_t width() const { return data_.width(); } + inline std::size_t height() const { return data_.height(); } + void set_data(image_data_any && data); + inline image_data_any const& data() const { return data_;} + static image read_from_file(std::string const& filename); + void save_to_file(std::string const& filename, std::string const& format); +private: + image(image && other) = default; + image(image_data_any && data) noexcept; + image_data_any data_; +}; + +} + +#endif // MAPNIK_IMAGE_HPP diff --git a/src/build.py b/src/build.py index 0f32bce0b..489ed0232 100644 --- a/src/build.py +++ b/src/build.py @@ -152,6 +152,7 @@ source = Split( miniz_png.cpp color.cpp conversions.cpp + image.cpp image_compositing.cpp image_scaling.cpp box2d.cpp diff --git a/src/image.cpp b/src/image.cpp new file mode 100644 index 000000000..3746e19cc --- /dev/null +++ b/src/image.cpp @@ -0,0 +1,80 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#include +#include +#include + +namespace mapnik { + +image::image(image_data_any && data) noexcept + : data_(std::move(data)) {} + +void image::set_data(image_data_any && data) +{ + data_ = std::move(data); +} + +image image::read_from_file(std::string const& filename) +{ + std::unique_ptr reader(get_image_reader(filename)); + if (reader) + { + unsigned w = reader->width(); + unsigned h = reader->height(); + image_data_any data = reader->read(0, 0, w, h); + return image(std::move(data)); + } + else + { + return image(); + } +} + +namespace detail { + +struct save_to_file_visitor : mapnik::util::static_visitor<> +{ + save_to_file_visitor(std::string const& filename, std::string const& format) + : filename_(filename), + format_(format) {} + + void operator() (image_data_rgba8 const& data) const + { + save_to_file(data,filename_, format_); + } + + template + void operator() (T const& data) const {} + + std::string const& filename_; + std::string const& format_; +}; + +} + +void image::save_to_file(std::string const& filename, std::string const& format) +{ + util::apply_visitor(detail::save_to_file_visitor(filename, format), data_); +} + +} From b28aadcf41a5c7e19f2cbd70fd442bb8e042e84d Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 7 Jan 2015 10:51:59 +0100 Subject: [PATCH 02/91] update variant to the latest version --- include/mapnik/util/variant.hpp | 169 ++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 60 deletions(-) diff --git a/include/mapnik/util/variant.hpp b/include/mapnik/util/variant.hpp index 55be089b6..9e118f970 100644 --- a/include/mapnik/util/variant.hpp +++ b/include/mapnik/util/variant.hpp @@ -35,7 +35,8 @@ #include #include "recursive_wrapper.hpp" -#include + +#include // spirit support #ifdef _MSC_VER // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx @@ -59,7 +60,19 @@ // translates to 100 #define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) -namespace mapnik { namespace util { namespace detail { +namespace mapnik { namespace util { + +// static visitor +template +struct static_visitor +{ + using result_type = R; +protected: + static_visitor() {} + ~static_visitor() {} +}; + +namespace detail { static constexpr std::size_t invalid_value = std::size_t(-1); @@ -134,18 +147,38 @@ struct select_type<0, T, Types...> using type = T; }; -} // namespace detail -// static visitor -template -struct static_visitor +template +struct enable_if_type { using type = R; }; + +template +struct result_of_unary_visit { - using result_type = R; -protected: - static_visitor() {} - ~static_visitor() {} + using type = typename std::result_of::type; }; +template +struct result_of_unary_visit::type > +{ + using type = typename F::result_type; +}; + +template +struct result_of_binary_visit +{ + using type = typename std::result_of::type; +}; + + +template +struct result_of_binary_visit::type > +{ + using type = typename F::result_type; +}; + + +} // namespace detail + template struct static_max; @@ -244,13 +277,13 @@ struct unwrapper> }; -template +template struct dispatcher; -template -struct dispatcher +template +struct dispatcher { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const& v, F f) { if (v.get_type_index() == sizeof...(Types)) @@ -259,7 +292,7 @@ struct dispatcher } else { - return dispatcher::apply_const(v, f); + return dispatcher::apply_const(v, f); } } @@ -271,15 +304,15 @@ struct dispatcher } else { - return dispatcher::apply(v, f); + return dispatcher::apply(v, f); } } }; -template -struct dispatcher +template +struct dispatcher { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const&, F) { throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); @@ -292,13 +325,13 @@ struct dispatcher }; -template +template struct binary_dispatcher_rhs; -template -struct binary_dispatcher_rhs +template +struct binary_dispatcher_rhs { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) { if (rhs.get_type_index() == sizeof...(Types)) // call binary functor @@ -308,7 +341,7 @@ struct binary_dispatcher_rhs } else { - return binary_dispatcher_rhs::apply_const(lhs, rhs, f); + return binary_dispatcher_rhs::apply_const(lhs, rhs, f); } } @@ -321,16 +354,16 @@ struct binary_dispatcher_rhs } else { - return binary_dispatcher_rhs::apply(lhs, rhs, f); + return binary_dispatcher_rhs::apply(lhs, rhs, f); } } }; -template -struct binary_dispatcher_rhs +template +struct binary_dispatcher_rhs { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const&, V const&, F) { throw std::runtime_error("binary dispatch: FAIL"); @@ -342,13 +375,13 @@ struct binary_dispatcher_rhs }; -template +template struct binary_dispatcher_lhs; -template -struct binary_dispatcher_lhs +template +struct binary_dispatcher_lhs { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) { if (lhs.get_type_index() == sizeof...(Types)) // call binary functor @@ -357,7 +390,7 @@ struct binary_dispatcher_lhs } else { - return binary_dispatcher_lhs::apply_const(lhs, rhs, f); + return binary_dispatcher_lhs::apply_const(lhs, rhs, f); } } @@ -369,16 +402,16 @@ struct binary_dispatcher_lhs } else { - return binary_dispatcher_lhs::apply(lhs, rhs, f); + return binary_dispatcher_lhs::apply(lhs, rhs, f); } } }; -template -struct binary_dispatcher_lhs +template +struct binary_dispatcher_lhs { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const&, V const&, F) { throw std::runtime_error("binary dispatch: FAIL"); @@ -390,13 +423,13 @@ struct binary_dispatcher_lhs } }; -template +template struct binary_dispatcher; -template -struct binary_dispatcher +template +struct binary_dispatcher { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) { if (v0.get_type_index() == sizeof...(Types)) @@ -407,14 +440,14 @@ struct binary_dispatcher } else { - return binary_dispatcher_rhs::apply_const(v0, v1, f); + return binary_dispatcher_rhs::apply_const(v0, v1, f); } } else if (v1.get_type_index() == sizeof...(Types)) { - return binary_dispatcher_lhs::apply_const(v0, v1, f); + return binary_dispatcher_lhs::apply_const(v0, v1, f); } - return binary_dispatcher::apply_const(v0, v1, f); + return binary_dispatcher::apply_const(v0, v1, f); } VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) @@ -427,21 +460,21 @@ struct binary_dispatcher } else { - return binary_dispatcher_rhs::apply(v0, v1, f); + return binary_dispatcher_rhs::apply(v0, v1, f); } } else if (v1.get_type_index() == sizeof...(Types)) { - return binary_dispatcher_lhs::apply(v0, v1, f); + return binary_dispatcher_lhs::apply(v0, v1, f); } - return binary_dispatcher::apply(v0, v1, f); + return binary_dispatcher::apply(v0, v1, f); } }; -template -struct binary_dispatcher +template +struct binary_dispatcher { - using result_type = typename F::result_type; + using result_type = R; VARIANT_INLINE static result_type apply_const(V const&, V const&, F) { throw std::runtime_error("binary dispatch: FAIL"); @@ -473,7 +506,7 @@ struct less_comp }; template -class comparer : public static_visitor +class comparer { public: explicit comparer(Variant const& lhs) noexcept @@ -492,7 +525,7 @@ private: // operator<< helper template -class printer : public static_visitor<> +class printer { public: explicit printer(Out & out) @@ -528,9 +561,11 @@ private: data_type data; public: + // tell spirit that this is an adapted variant struct adapted_variant_tag; using types = boost::mpl::vector; + VARIANT_INLINE variant() : type_index(sizeof...(Types) - 1) { @@ -540,6 +575,7 @@ public: VARIANT_INLINE variant(no_init) : type_index(detail::invalid_value) {} + // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers template ::type, Types...>::value>::type> VARIANT_INLINE variant(T && val) noexcept @@ -649,17 +685,23 @@ public: template auto VARIANT_INLINE static visit(V const& v, F f) - -> decltype(detail::dispatcher::apply_const(v, f)) + -> decltype(detail::dispatcher::type>::type, Types...>::apply_const(v, f)) { - return detail::dispatcher::apply_const(v, f); + using R = typename detail::result_of_unary_visit::type>::type; + return detail::dispatcher::apply_const(v, f); } // non-const template auto VARIANT_INLINE static visit(V & v, F f) - -> decltype(detail::dispatcher::apply(v, f)) + -> decltype(detail::dispatcher::type>::type, Types...>::apply(v, f)) { - return detail::dispatcher::apply(v, f); + using R = typename detail::result_of_unary_visit::type>::type; + return detail::dispatcher::apply(v, f); } // binary @@ -667,17 +709,23 @@ public: template auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F f) - -> decltype(detail::binary_dispatcher::apply_const(v0, v1, f)) + -> decltype(detail::binary_dispatcher::type>::type, Types...>::apply_const(v0, v1, f)) { - return detail::binary_dispatcher::apply_const(v0, v1, f); + using R = typename detail::result_of_binary_visit::type>::type; + return detail::binary_dispatcher::apply_const(v0, v1, f); } // non-const template auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F f) - -> decltype(detail::binary_dispatcher::apply(v0, v1, f)) + -> decltype(detail::binary_dispatcher::type>::type, Types...>::apply(v0, v1, f)) { - return detail::binary_dispatcher::apply(v0, v1, f); + using R = typename detail::result_of_binary_visit::type>::type; + return detail::binary_dispatcher::apply(v0, v1, f); } ~variant() noexcept @@ -749,6 +797,7 @@ ResultType const& get(T const& var) return var.template get(); } + // operator<< template VARIANT_INLINE std::basic_ostream& From c2ea32feac176dc0f01eae29c60de84a43f6093c Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 7 Jan 2015 11:35:21 +0100 Subject: [PATCH 03/91] remove static_visitor usage and rely on automatic result type deduction (NOTE: expression_evaluator requires ```using result_type = T1;``` ) --- bindings/python/mapnik_symbolizer.cpp | 4 +- bindings/python/mapnik_value_converter.hpp | 2 +- demo/viewer/styles_model.cpp | 4 +- include/mapnik/attribute_collector.hpp | 6 +-- include/mapnik/evaluate_global_attributes.hpp | 8 ++-- include/mapnik/expression_evaluator.hpp | 4 +- include/mapnik/image_data_any.hpp | 8 ++-- include/mapnik/image_filter.hpp | 4 +- include/mapnik/image_filter_types.hpp | 2 +- include/mapnik/json/feature_grammar.hpp | 2 +- include/mapnik/json/geometry_util.hpp | 12 +++--- include/mapnik/json/symbolizer_grammar.hpp | 4 +- include/mapnik/json/topojson_utils.hpp | 2 +- include/mapnik/markers_placement.hpp | 2 +- include/mapnik/params_impl.hpp | 2 +- .../process_group_symbolizer.hpp | 2 +- .../process_raster_symbolizer.hpp | 4 +- include/mapnik/symbolizer.hpp | 4 +- include/mapnik/symbolizer_dispatch.hpp | 2 +- include/mapnik/symbolizer_hash.hpp | 4 +- include/mapnik/symbolizer_utils.hpp | 6 +-- include/mapnik/tiff_io.hpp | 12 +++--- include/mapnik/transform_expression.hpp | 2 +- include/mapnik/transform_processor.hpp | 4 +- include/mapnik/value.hpp | 38 +++++++++---------- include/mapnik/value_hash.hpp | 2 +- plugins/input/gdal/gdal_featureset.hpp | 2 +- plugins/input/geojson/geojson_datasource.cpp | 2 +- .../rasterlite/rasterlite_featureset.hpp | 2 +- .../input/topojson/topojson_datasource.cpp | 6 +-- .../input/topojson/topojson_featureset.cpp | 4 +- src/agg/process_group_symbolizer.cpp | 2 +- src/cairo/process_group_symbolizer.cpp | 2 +- src/expression_string.cpp | 2 +- src/grid/process_group_symbolizer.cpp | 2 +- src/group/group_layout_manager.cpp | 2 +- src/image.cpp | 2 +- src/parse_path.cpp | 6 +-- src/save_map.cpp | 6 +-- src/svg/output/process_symbolizers.cpp | 2 +- src/text/placements/simple.cpp | 2 +- src/text/properties_util.cpp | 2 +- src/transform_expression.cpp | 2 +- src/warp.cpp | 2 +- utils/pgsql2sqlite/sqlite.hpp | 2 +- 45 files changed, 99 insertions(+), 99 deletions(-) diff --git a/bindings/python/mapnik_symbolizer.cpp b/bindings/python/mapnik_symbolizer.cpp index 130cb8cc2..ef23bdb98 100644 --- a/bindings/python/mapnik_symbolizer.cpp +++ b/bindings/python/mapnik_symbolizer.cpp @@ -105,7 +105,7 @@ std::shared_ptr numeric_wrapper(const objec return result; } -struct extract_python_object : public mapnik::util::static_visitor +struct extract_python_object { using result_type = boost::python::object; @@ -153,7 +153,7 @@ std::size_t hash_impl_2(T const& sym) return mapnik::symbolizer_hash::value(sym); } -struct extract_underlying_type_visitor : mapnik::util::static_visitor +struct extract_underlying_type_visitor { template boost::python::object operator() (T const& sym) const diff --git a/bindings/python/mapnik_value_converter.hpp b/bindings/python/mapnik_value_converter.hpp index 19ea7fc53..4f152a035 100644 --- a/bindings/python/mapnik_value_converter.hpp +++ b/bindings/python/mapnik_value_converter.hpp @@ -31,7 +31,7 @@ namespace boost { namespace python { - struct value_converter : public mapnik::util::static_visitor + struct value_converter { PyObject * operator() (mapnik::value_integer val) const { diff --git a/demo/viewer/styles_model.cpp b/demo/viewer/styles_model.cpp index 68f5ab9de..abd3ed6a2 100644 --- a/demo/viewer/styles_model.cpp +++ b/demo/viewer/styles_model.cpp @@ -122,7 +122,7 @@ private: }; -struct symbolizer_info : public mapnik::util::static_visitor +struct symbolizer_info { QString operator() (mapnik::point_symbolizer const& sym) const { @@ -185,7 +185,7 @@ struct symbolizer_info : public mapnik::util::static_visitor } }; -struct symbolizer_icon : public mapnik::util::static_visitor +struct symbolizer_icon { QIcon operator() (mapnik::polygon_symbolizer const& sym) const { diff --git a/include/mapnik/attribute_collector.hpp b/include/mapnik/attribute_collector.hpp index 63e6ad992..e9946fb49 100644 --- a/include/mapnik/attribute_collector.hpp +++ b/include/mapnik/attribute_collector.hpp @@ -52,7 +52,7 @@ namespace mapnik { template -struct expression_attributes : util::static_visitor +struct expression_attributes { explicit expression_attributes(Container& names) : names_(names) {} @@ -107,7 +107,7 @@ public: }; template -struct extract_attribute_names : util::static_visitor +struct extract_attribute_names { explicit extract_attribute_names(Container& names) : names_(names), @@ -159,7 +159,7 @@ private: expression_attributes > f_attr_; }; -struct symbolizer_attributes : public util::static_visitor<> +struct symbolizer_attributes { symbolizer_attributes(std::set& names, double & filter_factor) diff --git a/include/mapnik/evaluate_global_attributes.hpp b/include/mapnik/evaluate_global_attributes.hpp index b9263553a..b7da878a5 100644 --- a/include/mapnik/evaluate_global_attributes.hpp +++ b/include/mapnik/evaluate_global_attributes.hpp @@ -39,7 +39,7 @@ namespace mapnik { namespace { template -struct evaluate_expression : util::static_visitor +struct evaluate_expression { using value_type = T; @@ -133,7 +133,7 @@ struct evaluate_expression : util::static_visitor }; template -struct evaluate_expression : util::static_visitor +struct evaluate_expression { using value_type = T; @@ -274,7 +274,7 @@ std::tuple pre_evaluate_expression (expression_ptr const& expr) struct evaluate_global_attributes : mapnik::noncopyable { template - struct evaluator : util::static_visitor<> + struct evaluator { evaluator(symbolizer_base::cont_type::value_type & prop, Attributes const& attributes) : prop_(prop), @@ -296,7 +296,7 @@ struct evaluate_global_attributes : mapnik::noncopyable }; template - struct extract_symbolizer : util::static_visitor<> + struct extract_symbolizer { extract_symbolizer(Attributes const& attributes) : attributes_(attributes) {} diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index 0db82062c..1d37bdecc 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -35,12 +35,12 @@ namespace mapnik { template -struct evaluate : util::static_visitor +struct evaluate { using feature_type = T0; using value_type = T1; using variable_type = T2; - + using result_type = T1; // we need this because automatic result_type deduction fails explicit evaluate(feature_type const& f, variable_type const& v) : feature_(f), vars_(v) {} diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index c9b2d0b2e..c09bfdf7d 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -40,7 +40,7 @@ using image_data_base = util::variant +struct get_bytes_visitor { template unsigned char* operator()(T & data) @@ -49,7 +49,7 @@ struct get_bytes_visitor : util::static_visitor } }; -struct get_bytes_visitor_const : util::static_visitor +struct get_bytes_visitor_const { template unsigned char const* operator()(T const& data) const @@ -58,7 +58,7 @@ struct get_bytes_visitor_const : util::static_visitor } }; -struct get_width_visitor : util::static_visitor +struct get_width_visitor { template std::size_t operator()(T const& data) const @@ -67,7 +67,7 @@ struct get_width_visitor : util::static_visitor } }; -struct get_height_visitor : util::static_visitor +struct get_height_visitor { template std::size_t operator()(T const& data) const diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index 668d55129..064e94a43 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -761,7 +761,7 @@ void apply_filter(Src & src, invert const& /*op*/) } template -struct filter_visitor : util::static_visitor +struct filter_visitor { filter_visitor(Src & src) : src_(src) {} @@ -775,7 +775,7 @@ struct filter_visitor : util::static_visitor Src & src_; }; -struct filter_radius_visitor : util::static_visitor +struct filter_radius_visitor { int & radius_; filter_radius_visitor(int & radius) diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp index f06118903..e4c9df03b 100644 --- a/include/mapnik/image_filter_types.hpp +++ b/include/mapnik/image_filter_types.hpp @@ -267,7 +267,7 @@ inline std::ostream& operator<< (std::ostream& os, colorize_alpha const& filter) template -struct to_string_visitor : util::static_visitor +struct to_string_visitor { to_string_visitor(Out & out) : out_(out) {} diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp index f45c3de7e..a75a84f3a 100644 --- a/include/mapnik/json/feature_grammar.hpp +++ b/include/mapnik/json/feature_grammar.hpp @@ -46,7 +46,7 @@ namespace standard_wide = boost::spirit::standard_wide; using standard_wide::space_type; class attribute_value_visitor - : public mapnik::util::static_visitor + { public: attribute_value_visitor(mapnik::transcoder const& tr) diff --git a/include/mapnik/json/geometry_util.hpp b/include/mapnik/json/geometry_util.hpp index dd0c56694..be42d7ede 100644 --- a/include/mapnik/json/geometry_util.hpp +++ b/include/mapnik/json/geometry_util.hpp @@ -31,7 +31,7 @@ namespace mapnik { namespace json { // geometries template -struct create_point : util::static_visitor<> +struct create_point { explicit create_point(Path & path) : path_(path) {} @@ -49,7 +49,7 @@ struct create_point : util::static_visitor<> }; template -struct create_linestring : util::static_visitor<> +struct create_linestring { explicit create_linestring(Path & path) : path_(path) {} @@ -77,7 +77,7 @@ struct create_linestring : util::static_visitor<> }; template -struct create_polygon : util::static_visitor<> +struct create_polygon { explicit create_polygon(Path & path) : path_(path) {} @@ -111,7 +111,7 @@ struct create_polygon : util::static_visitor<> // multi-geometries template -struct create_multipoint : util::static_visitor<> +struct create_multipoint { explicit create_multipoint(Path & path) : path_(path) {} @@ -133,7 +133,7 @@ struct create_multipoint : util::static_visitor<> }; template -struct create_multilinestring : util::static_visitor<> +struct create_multilinestring { explicit create_multilinestring(Path & path) : path_(path) {} @@ -163,7 +163,7 @@ struct create_multilinestring : util::static_visitor<> }; template -struct create_multipolygon : util::static_visitor<> +struct create_multipolygon { explicit create_multipolygon(Path & path) : path_(path) {} diff --git a/include/mapnik/json/symbolizer_grammar.hpp b/include/mapnik/json/symbolizer_grammar.hpp index 219b838fc..bd34af0bd 100644 --- a/include/mapnik/json/symbolizer_grammar.hpp +++ b/include/mapnik/json/symbolizer_grammar.hpp @@ -45,7 +45,7 @@ namespace standard_wide = boost::spirit::standard_wide; using standard_wide::space_type; template -struct json_value_visitor : mapnik::util::static_visitor<> +struct json_value_visitor { json_value_visitor(Symbolizer & sym, mapnik::keys key) : sym_(sym), key_(key) {} @@ -82,7 +82,7 @@ struct json_value_visitor : mapnik::util::static_visitor<> }; template -struct put_property_visitor : mapnik::util::static_visitor<> +struct put_property_visitor { using value_type = T; diff --git a/include/mapnik/json/topojson_utils.hpp b/include/mapnik/json/topojson_utils.hpp index 41d73d3cf..5f7e739d5 100644 --- a/include/mapnik/json/topojson_utils.hpp +++ b/include/mapnik/json/topojson_utils.hpp @@ -30,7 +30,7 @@ namespace mapnik { namespace topojson { -struct bounding_box_visitor : public mapnik::util::static_visitor > +struct bounding_box_visitor { bounding_box_visitor(topology const& topo) : topo_(topo) {} diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp index 97dc8649e..5b6964461 100644 --- a/include/mapnik/markers_placement.hpp +++ b/include/mapnik/markers_placement.hpp @@ -44,7 +44,7 @@ public: markers_vertex_first_placement, markers_vertex_last_placement>; - class get_point_visitor : public util::static_visitor + class get_point_visitor { public: get_point_visitor(double &x, double &y, double &angle, bool ignore_placement) diff --git a/include/mapnik/params_impl.hpp b/include/mapnik/params_impl.hpp index b17f10ea2..58ae52b00 100644 --- a/include/mapnik/params_impl.hpp +++ b/include/mapnik/params_impl.hpp @@ -121,7 +121,7 @@ boost::optional param_cast(std::string const& source) } // end namespace detail template -struct value_extractor_visitor : public util::static_visitor<> +struct value_extractor_visitor { value_extractor_visitor(boost::optional & var) diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 08302c459..b0463858d 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -154,7 +154,7 @@ using render_thunk_list = std::list; // The bounding boxes can be used for layout, and the thunks are // used to re-render at locations according to the group layout. -struct render_thunk_extractor : public util::static_visitor<> +struct render_thunk_extractor { render_thunk_extractor(box2d & box, render_thunk_list & thunks, diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 6b81c6f0e..7229c60f2 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -44,7 +44,7 @@ namespace mapnik { namespace detail { template -struct image_data_dispatcher : util::static_visitor +struct image_data_dispatcher { using composite_function = F; image_data_dispatcher(int start_x, int start_y, @@ -105,7 +105,7 @@ private: }; template -struct image_data_warp_dispatcher : util::static_visitor +struct image_data_warp_dispatcher { using composite_function = F; image_data_warp_dispatcher(proj_transform const& prj_trans, diff --git a/include/mapnik/symbolizer.hpp b/include/mapnik/symbolizer.hpp index 941edfe4a..d15c1e10e 100644 --- a/include/mapnik/symbolizer.hpp +++ b/include/mapnik/symbolizer.hpp @@ -339,7 +339,7 @@ struct evaluate_expression_wrapper }; template -struct extract_value : public util::static_visitor +struct extract_value { using result_type = T; @@ -379,7 +379,7 @@ struct extract_value : public util::static_visitor }; template -struct extract_raw_value : public util::static_visitor +struct extract_raw_value { using result_type = T1; diff --git a/include/mapnik/symbolizer_dispatch.hpp b/include/mapnik/symbolizer_dispatch.hpp index a0320cc77..213a38835 100644 --- a/include/mapnik/symbolizer_dispatch.hpp +++ b/include/mapnik/symbolizer_dispatch.hpp @@ -67,7 +67,7 @@ struct process_impl * \param sym Symbolizer object */ template -struct symbolizer_dispatch : public util::static_visitor<> +struct symbolizer_dispatch { symbolizer_dispatch(Processor & output, mapnik::feature_impl & f, diff --git a/include/mapnik/symbolizer_hash.hpp b/include/mapnik/symbolizer_hash.hpp index 9c1cc45fb..feadf02d3 100644 --- a/include/mapnik/symbolizer_hash.hpp +++ b/include/mapnik/symbolizer_hash.hpp @@ -33,7 +33,7 @@ namespace mapnik { -struct property_value_hash_visitor : util::static_visitor +struct property_value_hash_visitor { std::size_t operator() (color const& val) const { @@ -82,7 +82,7 @@ struct symbolizer_hash } }; -struct symbolizer_hash_visitor : util::static_visitor +struct symbolizer_hash_visitor { template std::size_t operator() (Symbolizer const& sym) const diff --git a/include/mapnik/symbolizer_utils.hpp b/include/mapnik/symbolizer_utils.hpp index 65e3f42bc..00a4f0208 100644 --- a/include/mapnik/symbolizer_utils.hpp +++ b/include/mapnik/symbolizer_utils.hpp @@ -129,7 +129,7 @@ struct symbolizer_traits // symbolizer name impl namespace detail { -struct symbolizer_name_impl : public util::static_visitor +struct symbolizer_name_impl { public: template @@ -150,7 +150,7 @@ inline std::string symbolizer_name(symbolizer const& sym) /* template -class symbolizer_property_value_string : public util::static_visitor +class symbolizer_property_value_string { public: symbolizer_property_value_string (Meta const& meta) @@ -237,7 +237,7 @@ private: Meta const& meta_; }; -struct symbolizer_to_json : public util::static_visitor +struct symbolizer_to_json { using result_type = std::string; diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index d5ebbc4d1..af60309d1 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -179,7 +179,7 @@ struct tiff_config }; -struct tag_setter : public mapnik::util::static_visitor<> +struct tag_setter { tag_setter(TIFF * output, tiff_config & config) : output_(output), @@ -270,7 +270,7 @@ void set_tiff_config(TIFF* output, tiff_config & config) // Set the compression for the TIFF TIFFSetField(output, TIFFTAG_COMPRESSION, config.compression); - if (COMPRESSION_ADOBE_DEFLATE == config.compression + if (COMPRESSION_ADOBE_DEFLATE == config.compression || COMPRESSION_DEFLATE == config.compression || COMPRESSION_LZW == config.compression) { @@ -332,7 +332,7 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) else if (TIFF_WRITE_STRIPPED == config.method) { std::size_t rows_per_strip = config.rows_per_strip; - if (0 == rows_per_strip) + if (0 == rows_per_strip) { rows_per_strip = height; } @@ -359,8 +359,8 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) { int tile_width = config.tile_width; int tile_height = config.tile_height; - - if (0 == tile_height) + + if (0 == tile_height) { tile_height = height; if (height % 16 > 0) @@ -385,7 +385,7 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) int end_x = (width / tile_width + 1) * tile_width; end_y = std::min(end_y, height); end_x = std::min(end_x, width); - + for (int y = 0; y < end_y; y += tile_height) { int ty1 = std::min(height, y + tile_height) - y; diff --git a/include/mapnik/transform_expression.hpp b/include/mapnik/transform_expression.hpp index 86d52e541..d73554b5a 100644 --- a/include/mapnik/transform_expression.hpp +++ b/include/mapnik/transform_expression.hpp @@ -192,7 +192,7 @@ inline void clear(transform_node& val) namespace { -struct is_null_transform_node : public mapnik::util::static_visitor +struct is_null_transform_node { bool operator() (value const& val) const { diff --git a/include/mapnik/transform_processor.hpp b/include/mapnik/transform_processor.hpp index ee1b24661..58f7e7c09 100644 --- a/include/mapnik/transform_processor.hpp +++ b/include/mapnik/transform_processor.hpp @@ -46,7 +46,7 @@ struct transform_processor using transform_type = agg::trans_affine; template - struct attribute_collector : util::static_visitor + struct attribute_collector { expression_attributes collect_; @@ -97,7 +97,7 @@ struct transform_processor } }; - struct node_evaluator : util::static_visitor + struct node_evaluator { node_evaluator(transform_type& tr, feature_type const& feat, diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index 987bcc433..29d4000bc 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -72,7 +72,7 @@ using value_base = util::variant + { bool operator() (value_integer lhs, value_double rhs) const { @@ -124,7 +124,7 @@ struct equals }; struct not_equals - : public util::static_visitor + { template bool operator() (const T &, const U &) const @@ -186,7 +186,7 @@ struct not_equals }; struct greater_than - : public util::static_visitor + { template bool operator()(const T &, const U &) const @@ -222,7 +222,7 @@ struct greater_than }; struct greater_or_equal - : public util::static_visitor + { template bool operator()(const T &, const U &) const @@ -258,7 +258,7 @@ struct greater_or_equal }; struct less_than - : public util::static_visitor + { template bool operator()(const T &, const U &) const @@ -295,7 +295,7 @@ struct less_than }; struct less_or_equal - : public util::static_visitor + { template bool operator()(const T &, const U &) const @@ -332,7 +332,7 @@ struct less_or_equal }; template -struct add : public util::static_visitor +struct add { using value_type = V; value_type operator() (value_unicode_string const& lhs , @@ -398,7 +398,7 @@ struct add : public util::static_visitor }; template -struct sub : public util::static_visitor +struct sub { using value_type = V; template @@ -436,7 +436,7 @@ struct sub : public util::static_visitor }; template -struct mult : public util::static_visitor +struct mult { using value_type = V; template @@ -473,7 +473,7 @@ struct mult : public util::static_visitor }; template -struct div: public util::static_visitor +struct div { using value_type = V; template @@ -514,7 +514,7 @@ struct div: public util::static_visitor }; template -struct mod: public util::static_visitor +struct mod { using value_type = V; template @@ -558,7 +558,7 @@ struct mod: public util::static_visitor }; template -struct negate : public util::static_visitor +struct negate { using value_type = V; @@ -589,7 +589,7 @@ template struct convert {}; template <> -struct convert : public util::static_visitor +struct convert { value_bool operator() (value_bool val) const { @@ -614,7 +614,7 @@ struct convert : public util::static_visitor }; template <> -struct convert : public util::static_visitor +struct convert { value_double operator() (value_double val) const { @@ -653,7 +653,7 @@ struct convert : public util::static_visitor }; template <> -struct convert : public util::static_visitor +struct convert { value_integer operator() (value_integer val) const { @@ -692,7 +692,7 @@ struct convert : public util::static_visitor }; template <> -struct convert : public util::static_visitor +struct convert { template std::string operator() (T val) const @@ -723,7 +723,7 @@ struct convert : public util::static_visitor } }; -struct to_unicode : public util::static_visitor +struct to_unicode { template @@ -753,7 +753,7 @@ struct to_unicode : public util::static_visitor } }; -struct to_expression_string : public util::static_visitor +struct to_expression_string { explicit to_expression_string(char quote = '\'') : quote_(quote) {} @@ -947,7 +947,7 @@ using value_adl_barrier::operator<<; namespace detail { -struct is_null_visitor : public util::static_visitor +struct is_null_visitor { bool operator() (value const& val) const { diff --git a/include/mapnik/value_hash.hpp b/include/mapnik/value_hash.hpp index 1a72108b4..0933f06d3 100644 --- a/include/mapnik/value_hash.hpp +++ b/include/mapnik/value_hash.hpp @@ -42,7 +42,7 @@ inline void hash_combine(std::size_t & seed, T const& v) seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); } -struct value_hasher: public util::static_visitor +struct value_hasher { std::size_t operator() (value_null val) const { diff --git a/plugins/input/gdal/gdal_featureset.hpp b/plugins/input/gdal/gdal_featureset.hpp index 5d920630c..04f24ed0f 100644 --- a/plugins/input/gdal/gdal_featureset.hpp +++ b/plugins/input/gdal/gdal_featureset.hpp @@ -38,7 +38,7 @@ using gdal_query = mapnik::util::variant; class gdal_featureset : public mapnik::Featureset { - struct query_dispatch : public mapnik::util::static_visitor + struct query_dispatch { query_dispatch( gdal_featureset & featureset) : featureset_(featureset) {} diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp index 59eda0efd..065226f01 100644 --- a/plugins/input/geojson/geojson_datasource.cpp +++ b/plugins/input/geojson/geojson_datasource.cpp @@ -53,7 +53,7 @@ using mapnik::parameters; DATASOURCE_PLUGIN(geojson_datasource) -struct attr_value_converter : public mapnik::util::static_visitor +struct attr_value_converter { mapnik::eAttributeType operator() (mapnik::value_integer) const { diff --git a/plugins/input/rasterlite/rasterlite_featureset.hpp b/plugins/input/rasterlite/rasterlite_featureset.hpp index a465ae90b..cf7973f15 100644 --- a/plugins/input/rasterlite/rasterlite_featureset.hpp +++ b/plugins/input/rasterlite/rasterlite_featureset.hpp @@ -35,7 +35,7 @@ using rasterlite_query = mapnik::util::variant; class rasterlite_featureset : public mapnik::Featureset { - struct query_dispatch : public mapnik::util::static_visitor + struct query_dispatch { query_dispatch( rasterlite_featureset & featureset) : featureset_(featureset) {} diff --git a/plugins/input/topojson/topojson_datasource.cpp b/plugins/input/topojson/topojson_datasource.cpp index 50ef1a8aa..23b3b2376 100644 --- a/plugins/input/topojson/topojson_datasource.cpp +++ b/plugins/input/topojson/topojson_datasource.cpp @@ -44,7 +44,7 @@ using mapnik::parameters; DATASOURCE_PLUGIN(topojson_datasource) -struct attr_value_converter : public mapnik::util::static_visitor +struct attr_value_converter { mapnik::eAttributeType operator() (mapnik::value_integer /*val*/) const { @@ -82,7 +82,7 @@ struct attr_value_converter : public mapnik::util::static_visitor +struct geometry_type_visitor { int operator() (mapnik::topojson::point const&) const { @@ -114,7 +114,7 @@ struct geometry_type_visitor : public mapnik::util::static_visitor } }; -struct collect_attributes_visitor : public mapnik::util::static_visitor +struct collect_attributes_visitor { mapnik::layer_descriptor & desc_; collect_attributes_visitor(mapnik::layer_descriptor & desc): diff --git a/plugins/input/topojson/topojson_featureset.cpp b/plugins/input/topojson/topojson_featureset.cpp index 6512b4e50..898c7db8c 100644 --- a/plugins/input/topojson/topojson_featureset.cpp +++ b/plugins/input/topojson/topojson_featureset.cpp @@ -51,7 +51,7 @@ BOOST_GEOMETRY_REGISTER_LINESTRING(std::vector) namespace mapnik { namespace topojson { struct attribute_value_visitor - : mapnik::util::static_visitor + { public: attribute_value_visitor(mapnik::transcoder const& tr) @@ -84,7 +84,7 @@ void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::tr } template -struct feature_generator : public mapnik::util::static_visitor +struct feature_generator { feature_generator(Context & ctx, mapnik::transcoder const& tr, topology const& topo, std::size_t feature_id) : ctx_(ctx), diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index 6397454a1..7d2abb107 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -43,7 +43,7 @@ namespace mapnik { * to render it, and the boxes themselves should already be * in the detector from the placement_finder. */ -struct thunk_renderer : public util::static_visitor<> +struct thunk_renderer { using renderer_type = agg_renderer; using buffer_type = renderer_type::buffer_type; diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index 9b8e09342..23c69f7bb 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -43,7 +43,7 @@ namespace { // to render it, and the boxes themselves should already be // in the detector from the placement_finder. template -struct thunk_renderer : public util::static_visitor<> +struct thunk_renderer { using renderer_type = cairo_renderer; diff --git a/src/expression_string.cpp b/src/expression_string.cpp index 1e800184e..6fe39209e 100644 --- a/src/expression_string.cpp +++ b/src/expression_string.cpp @@ -33,7 +33,7 @@ namespace mapnik { -struct expression_string : util::static_visitor +struct expression_string { explicit expression_string(std::string & str) : str_(str) {} diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 758653554..d622f066b 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -53,7 +53,7 @@ namespace mapnik { * in the detector from the placement_finder. */ template -struct thunk_renderer : public util::static_visitor<> +struct thunk_renderer { using renderer_type = grid_renderer; using buffer_type = typename renderer_type::buffer_type; diff --git a/src/group/group_layout_manager.cpp b/src/group/group_layout_manager.cpp index ecae32fb2..7c6f7b8c6 100644 --- a/src/group/group_layout_manager.cpp +++ b/src/group/group_layout_manager.cpp @@ -31,7 +31,7 @@ namespace mapnik { // This visitor will process offsets for the given layout -struct process_layout : public util::static_visitor<> +struct process_layout { // The vector containing the existing, centered item bounding boxes vector const& member_boxes_; diff --git a/src/image.cpp b/src/image.cpp index 3746e19cc..11b8ad33b 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -52,7 +52,7 @@ image image::read_from_file(std::string const& filename) namespace detail { -struct save_to_file_visitor : mapnik::util::static_visitor<> +struct save_to_file_visitor { save_to_file_visitor(std::string const& filename, std::string const& format) : filename_(filename), diff --git a/src/parse_path.cpp b/src/parse_path.cpp index 8fdc19450..0064f3ab3 100644 --- a/src/parse_path.cpp +++ b/src/parse_path.cpp @@ -53,7 +53,7 @@ path_expression_ptr parse_path(std::string const& str) namespace path_processor_detail { - struct path_visitor_ : util::static_visitor + struct path_visitor_ { path_visitor_ (std::string & filename, feature_impl const& f) : filename_(filename), @@ -75,7 +75,7 @@ namespace path_processor_detail feature_impl const& feature_; }; - struct to_string_ : util::static_visitor + struct to_string_ { to_string_ (std::string & str) : str_(str) {} @@ -95,7 +95,7 @@ namespace path_processor_detail std::string & str_; }; - struct collect_ : util::static_visitor + struct collect_ { collect_ (std::set & cont) : cont_(cont) {} diff --git a/src/save_map.cpp b/src/save_map.cpp index 28af42cfa..31fe20718 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -135,7 +135,7 @@ void serialize_group_symbolizer_properties(ptree & sym_node, bool explicit_defaults); template -class serialize_symbolizer_property : public util::static_visitor<> +class serialize_symbolizer_property { public: serialize_symbolizer_property(Meta const& meta, @@ -225,7 +225,7 @@ private: bool explicit_defaults_; }; -class serialize_symbolizer : public util::static_visitor<> +class serialize_symbolizer { public: serialize_symbolizer( ptree & r , bool explicit_defaults) @@ -255,7 +255,7 @@ private: bool explicit_defaults_; }; -class serialize_group_layout : public util::static_visitor<> +class serialize_group_layout { public: serialize_group_layout(ptree & parent_node, bool explicit_defaults) diff --git a/src/svg/output/process_symbolizers.cpp b/src/svg/output/process_symbolizers.cpp index 3c40f7941..8b57c4fa5 100644 --- a/src/svg/output/process_symbolizers.cpp +++ b/src/svg/output/process_symbolizers.cpp @@ -37,7 +37,7 @@ namespace mapnik { -struct symbol_type_dispatch : public util::static_visitor +struct symbol_type_dispatch { template bool operator()(Symbolizer const&) const diff --git a/src/text/placements/simple.cpp b/src/text/placements/simple.cpp index c365ae403..693b0bacd 100644 --- a/src/text/placements/simple.cpp +++ b/src/text/placements/simple.cpp @@ -169,7 +169,7 @@ text_placements_simple::text_placements_simple(symbolizer_base::value_type const positions_(positions) { } namespace detail { - struct serialize_positions : public util::static_visitor + struct serialize_positions { serialize_positions() {} diff --git a/src/text/properties_util.cpp b/src/text/properties_util.cpp index 873534f1e..ca76efd02 100644 --- a/src/text/properties_util.cpp +++ b/src/text/properties_util.cpp @@ -28,7 +28,7 @@ namespace mapnik { namespace detail { -struct property_serializer : public util::static_visitor<> +struct property_serializer { property_serializer(std::string const& name, boost::property_tree::ptree & node) : name_(name), diff --git a/src/transform_expression.cpp b/src/transform_expression.cpp index 0abba251f..e065ddc7e 100644 --- a/src/transform_expression.cpp +++ b/src/transform_expression.cpp @@ -30,7 +30,7 @@ namespace mapnik { struct transform_node_to_expression_string - : public util::static_visitor + { std::ostringstream& os_; diff --git a/src/warp.cpp b/src/warp.cpp index 787f8a58d..16a81492d 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -158,7 +158,7 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& namespace detail { -struct warp_image_visitor : util::static_visitor +struct warp_image_visitor { warp_image_visitor (raster & target_raster, proj_transform const& prj_trans, box2d const& source_ext, double offset_x, double offset_y, unsigned mesh_size, diff --git a/utils/pgsql2sqlite/sqlite.hpp b/utils/pgsql2sqlite/sqlite.hpp index c16c30ded..64b5b6409 100644 --- a/utils/pgsql2sqlite/sqlite.hpp +++ b/utils/pgsql2sqlite/sqlite.hpp @@ -77,7 +77,7 @@ namespace mapnik { namespace sqlite { class prepared_statement : mapnik::noncopyable { - struct binder : public mapnik::util::static_visitor + struct binder { binder(sqlite3_stmt * stmt, unsigned index) : stmt_(stmt), index_(index) {} From f6651ac74d76c0eb127f7d9eb4ef04e45b73e488 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 7 Jan 2015 12:20:19 +0100 Subject: [PATCH 04/91] use std::make_shared --- bindings/python/mapnik_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 4f1b61bc1..b46a0ef0f 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -228,7 +228,7 @@ std::shared_ptr from_cairo(PycairoSurface* py_surface) // ============ image any std::shared_ptr read_from_file_impl(std::string const& filename) { - std::shared_ptr img(new image); + std::shared_ptr img = std::make_shared(); std::unique_ptr reader(get_image_reader(filename)); if (reader) { From 00a20b78da4f77a86bc0b4ea4d6ba3927bf3f352 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 7 Jan 2015 18:17:44 +0100 Subject: [PATCH 05/91] add initial support for writing image_data_gray16 ( only TIFF supported ) --- include/mapnik/image.hpp | 1 - include/mapnik/tiff_io.hpp | 2 +- src/image.cpp | 26 +++++++++++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index d35b2cebc..d9e6d5243 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -23,7 +23,6 @@ #ifndef MAPNIK_IMAGE_HPP #define MAPNIK_IMAGE_HPP -#include #include namespace mapnik { diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index af60309d1..33dbf4a11 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -261,7 +261,7 @@ struct tag_setter tiff_config config_; }; -void set_tiff_config(TIFF* output, tiff_config & config) +inline void set_tiff_config(TIFF* output, tiff_config & config) { // Set some constant tiff information that doesn't vary based on type of data // or image size diff --git a/src/image.cpp b/src/image.cpp index 11b8ad33b..f7728fe62 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -23,6 +23,9 @@ #include #include #include +#include + +#include namespace mapnik { @@ -63,8 +66,29 @@ struct save_to_file_visitor save_to_file(data,filename_, format_); } + void operator() (image_data_gray16 const& data) const + { + if (format_ == "tiff") // only TIFF supported + { + std::ofstream file (filename_.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); + if (file) + { + tiff_config config; + save_as_tiff(file, data, config); + } + else throw ImageWriterException("Could not write file to " + filename_ ); + } + else + { + throw std::runtime_error("Error: saving gray16 image as " + format_ + " is not supported"); + } + } + template - void operator() (T const& data) const {} + void operator() (T const& data) const + { + throw std::runtime_error("Error: saving " + std::string(typeid(data).name()) + " as " + format_ + " is not supported"); + } std::string const& filename_; std::string const& format_; From a3f6a989dea2dc334dc573d51a4058055b322f9e Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 7 Jan 2015 15:44:31 -0500 Subject: [PATCH 06/91] An intial commit of a large set of changes attempting to clean up the way that saving images is processed in image_util.hpp and image_util.cpp. * Changed the passing of rgba_palette to a shared_ptr in order to better facilitate the use of a visitor pattern. * Moved PNG util processing into its own set of files so that image_util_impl.hpp would not have to depend on HAVE_PNG. --- .gitignore | 1 + bindings/python/mapnik_image.cpp | 4 +- bindings/python/mapnik_image_view.cpp | 4 +- bindings/python/mapnik_palette.cpp | 2 +- include/mapnik/image_util.hpp | 33 ++-- include/mapnik/image_util_png.hpp | 48 +++++ include/mapnik/palette.hpp | 2 + include/mapnik/png_io.hpp | 20 +-- src/image_util.cpp | 237 +++++-------------------- src/image_util_png.cpp | 241 ++++++++++++++++++++++++++ 10 files changed, 372 insertions(+), 220 deletions(-) create mode 100644 include/mapnik/image_util_png.hpp create mode 100644 src/image_util_png.cpp diff --git a/.gitignore b/.gitignore index bbf225e80..a7653de61 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.os *.so *.a +*.swp *.dylib plugins/input/*.input plugins/input/templates/*.input diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 5d674be72..92e023970 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -83,7 +83,7 @@ PyObject* tostring2(image_32 const & im, std::string const& format) (s.data(),s.size()); } -PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette_ptr const& pal) { std::string s = save_to_string(im, format, pal); return @@ -106,7 +106,7 @@ void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std: save_to_file(im,filename,type); } -void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) +void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette_ptr const& pal) { save_to_file(im,filename,type,pal); } diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index e08129f7f..bcd890385 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -77,7 +77,7 @@ PyObject* view_tostring2(image_view const & view, std::string (s.data(),s.size()); } -PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette_ptr const& pal) { std::string s = save_to_string(view, format, pal); return @@ -126,7 +126,7 @@ void save_view2(image_view const& view, void save_view3(image_view const& view, std::string const& filename, std::string const& type, - mapnik::rgba_palette const& pal) + mapnik::rgba_palette_ptr const& pal) { save_to_file(view,filename,type,pal); } diff --git a/bindings/python/mapnik_palette.cpp b/bindings/python/mapnik_palette.cpp index 12cf2fdec..08ab80e92 100644 --- a/bindings/python/mapnik_palette.cpp +++ b/bindings/python/mapnik_palette.cpp @@ -55,7 +55,7 @@ void export_palette () { using namespace boost::python; - class_, std::shared_ptr, boost::noncopyable >("Palette",no_init) //, init( diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index f6bb1ca21..b00c44c8b 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -46,6 +46,7 @@ namespace mapnik { class Map; class rgba_palette; class image_32; +typedef std::shared_ptr rgba_palette_ptr; class ImageWriterException : public std::exception { @@ -84,7 +85,7 @@ template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); // guess type from file extension template @@ -94,7 +95,7 @@ MAPNIK_DECL void save_to_file(T const& image, template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template MAPNIK_DECL std::string save_to_string(T const& image, @@ -103,7 +104,7 @@ MAPNIK_DECL std::string save_to_string(T const& image, template MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template MAPNIK_DECL void save_to_stream @@ -111,7 +112,7 @@ MAPNIK_DECL void save_to_stream T const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette + rgba_palette_ptr const& palette ); template @@ -125,7 +126,7 @@ MAPNIK_DECL void save_to_stream template void save_as_png(T const& image, std::string const& filename, - rgba_palette const& palette); + rgba_palette_ptr const& palette); #if defined(HAVE_JPEG) template @@ -224,7 +225,7 @@ MAPNIK_DECL void save_to_file (image_32 const& image, MAPNIK_DECL void save_to_file (image_32 const& image, std::string const& file, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); /////////////////////////////////////////////////////////////////////////// @@ -234,14 +235,14 @@ MAPNIK_DECL std::string save_to_string(image_32 const& image, MAPNIK_DECL std::string save_to_string(image_32 const& image, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); /////////////////////////////////////////////////////////////////////////// MAPNIK_DECL void save_to_stream(image_32 const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); MAPNIK_DECL void save_to_stream(image_32 const& image, std::ostream & stream, @@ -252,7 +253,7 @@ MAPNIK_DECL void save_to_stream(image_32 const& image, extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, @@ -260,7 +261,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&); @@ -269,7 +270,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, @@ -277,7 +278,7 @@ extern template MAPNIK_DECL void save_to_file > (im extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&); @@ -287,21 +288,21 @@ extern template MAPNIK_DECL std::string save_to_string(image_d extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL std::string save_to_string > (image_view const&, std::string const&); extern template MAPNIK_DECL std::string save_to_string > (image_view const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); #ifdef _MSC_VER template MAPNIK_DECL void save_to_stream( image_data_rgba8 const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette + rgba_palette_ptr const& palette ); template MAPNIK_DECL void save_to_stream( @@ -314,7 +315,7 @@ template MAPNIK_DECL void save_to_stream > ( image_view const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette + rgba_palette_ptr const& palette ); template MAPNIK_DECL void save_to_stream > ( diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp new file mode 100644 index 000000000..9a3f6d7b9 --- /dev/null +++ b/include/mapnik/image_util_png.hpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_UTIL_PNG_HPP +#define MAPNIK_IMAGE_UTIL_PNG_HPP + +// mapnik +#include + +// stl +#include +#include + +namespace mapnik { + +struct png_saver : public mapnik::util::static_visitor<> +{ + png_saver(std::ostream &, std::string &, rgba_palette_ptr const& = nullptr); + template + void operator() (T const&) const; + private: + std::ostream _stream; + std::string _t; + rgba_palette_ptr _pal; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_PNG_HPP diff --git a/include/mapnik/palette.hpp b/include/mapnik/palette.hpp index 4decf7d1c..78dcf3ed8 100644 --- a/include/mapnik/palette.hpp +++ b/include/mapnik/palette.hpp @@ -130,6 +130,8 @@ private: std::vector alpha_pal_; }; +typedef std::shared_ptr rgba_palette_ptr; + } // namespace mapnik #endif // MAPNIK_PALETTE_HPP diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 7034ca293..4efd781ff 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -607,7 +607,7 @@ void save_as_png8(T1 & file, mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); for (unsigned x = 0; x < width; ++x) { - row_out[x] = tree.quantize(row[x]); + row_out[x] = tree->quantize(row[x]); } } save_as_png(file, palette, reduced_image, width, height, 8, alphaTable, opts); @@ -635,7 +635,7 @@ void save_as_png8(T1 & file, for (unsigned x = 0; x < width; ++x) { - index = tree.quantize(row[x]); + index = tree->quantize(row[x]); if (x%2 == 0) { index = index<<4; @@ -657,14 +657,14 @@ void save_as_png8_hex(T1 & file, if (width + height > 3) // at least 3 pixels (hextree implementation requirement) { // structure for color quantization - hextree tree(opts.colors); + std::shared_ptr> tree = std::make_shared>(opts.colors); if (opts.trans_mode >= 0) { - tree.setTransMode(opts.trans_mode); + tree->setTransMode(opts.trans_mode); } if (opts.gamma > 0) { - tree.setGamma(opts.gamma); + tree->setGamma(opts.gamma); } for (unsigned y = 0; y < height; ++y) @@ -673,13 +673,13 @@ void save_as_png8_hex(T1 & file, for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; - tree.insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val))); + tree->insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val))); } } //transparency values per palette index std::vector pal; - tree.create_palette(pal); + tree->create_palette(pal); std::vector palette; std::vector alphaTable; for (unsigned i=0; i >(file, image, tree, palette, alphaTable, opts); + save_as_png8> >(file, image, tree, palette, alphaTable, opts); } else { @@ -698,10 +698,10 @@ void save_as_png8_hex(T1 & file, template void save_as_png8_pal(T1 & file, T2 const& image, - rgba_palette const& pal, + rgba_palette_ptr const& pal, png_options const& opts) { - save_as_png8(file, image, pal, pal.palette(), pal.alphaTable(), opts); + save_as_png8(file, image, pal, pal->palette(), pal->alphaTable(), opts); } } diff --git a/src/image_util.cpp b/src/image_util.cpp index a5bb8e98f..55e7cdf3f 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -20,18 +20,7 @@ * *****************************************************************************/ -#if defined(HAVE_PNG) -extern "C" -{ -#include -} -#endif - // mapnik -#if defined(HAVE_PNG) -#include -#endif - #if defined(HAVE_TIFF) #include #endif @@ -45,6 +34,7 @@ extern "C" #endif #include +#include #include #include #include @@ -52,6 +42,7 @@ extern "C" #include #include #include +#include #ifdef HAVE_CAIRO #include @@ -84,7 +75,7 @@ namespace mapnik template std::string save_to_string(T const& image, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { std::ostringstream ss(std::ios::out|std::ios::binary); save_to_stream(image, ss, type, palette); @@ -104,7 +95,7 @@ template void save_to_file(T const& image, std::string const& filename, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) @@ -127,134 +118,6 @@ void save_to_file(T const& image, else throw ImageWriterException("Could not write file to " + filename ); } -#if defined(HAVE_PNG) - -void handle_png_options(std::string const& type, - png_options & opts) -{ - if (type == "png" || type == "png24" || type == "png32") - { - opts.paletted = false; - return; - } - else if (type == "png8" || type == "png256") - { - opts.paletted = true; - return; - } - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - bool set_colors = false; - bool set_gamma = false; - for (std::string const& t : tokens) - { - if (t == "png8" || t == "png256") - { - opts.paletted = true; - } - else if (t == "png" || t == "png24" || t == "png32") - { - opts.paletted = false; - } - else if (t == "m=o") - { - opts.use_hextree = false; - } - else if (t == "m=h") - { - opts.use_hextree = true; - } - else if (t == "e=miniz") - { - opts.use_miniz = true; - } - else if (boost::algorithm::starts_with(t, "c=")) - { - set_colors = true; - if (!mapnik::util::string2int(t.substr(2),opts.colors) || opts.colors < 1 || opts.colors > 256) - { - throw ImageWriterException("invalid color parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "t=")) - { - if (!mapnik::util::string2int(t.substr(2),opts.trans_mode) || opts.trans_mode < 0 || opts.trans_mode > 2) - { - throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "g=")) - { - set_gamma = true; - if (!mapnik::util::string2double(t.substr(2),opts.gamma) || opts.gamma < 0) - { - throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "z=")) - { - /* - #define Z_NO_COMPRESSION 0 - #define Z_BEST_SPEED 1 - #define Z_BEST_COMPRESSION 9 - #define Z_DEFAULT_COMPRESSION (-1) - */ - if (!mapnik::util::string2int(t.substr(2),opts.compression) - || opts.compression < Z_DEFAULT_COMPRESSION - || opts.compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION - { - throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)"); - } - } - else if (boost::algorithm::starts_with(t, "s=")) - { - std::string s = t.substr(2); - if (s == "default") - { - opts.strategy = Z_DEFAULT_STRATEGY; - } - else if (s == "filtered") - { - opts.strategy = Z_FILTERED; - } - else if (s == "huff") - { - opts.strategy = Z_HUFFMAN_ONLY; - } - else if (s == "rle") - { - opts.strategy = Z_RLE; - } - else if (s == "fixed") - { - opts.strategy = Z_FIXED; - } - else - { - throw ImageWriterException("invalid compression strategy parameter: " + s); - } - } - else - { - throw ImageWriterException("unhandled png option: " + t); - } - } - // validation - if (!opts.paletted && set_colors) - { - throw ImageWriterException("invalid color parameter: unavailable for true color (non-paletted) images"); - } - if (!opts.paletted && set_gamma) - { - throw ImageWriterException("invalid gamma parameter: unavailable for true color (non-paletted) images"); - } - if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) - { - throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)"); - } -} -#endif - #if defined(HAVE_TIFF) void handle_tiff_options(std::string const& type, tiff_config & config) @@ -666,10 +529,26 @@ void handle_webp_options(std::string const& type, #endif template -void save_to_stream(T const& image, +void save_to_stream(image_view const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) +{ + save_to_stream(image.data(), stream, type, palette); +} + +void save_to_stream(image_32 const& image, + std::ostream & stream, + std::string const& type, + rgba_palette_ptr const& palette) +{ + save_to_stream(image.data(), stream, type, palette); +} + +void save_to_stream(image_data_any const& image, + std::ostream & stream, + std::string const& type, + rgba_palette_ptr const& palette) { if (stream && image.width() > 0 && image.height() > 0) { @@ -677,20 +556,7 @@ void save_to_stream(T const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { -#if defined(HAVE_PNG) - if (palette.valid()) - { - png_options opts; - handle_png_options(t,opts); - save_as_png8_pal(stream, image, palette, opts); - } - else - { - save_to_stream(image,stream,type); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + mapnik::util::apply_visitor(png_saver(stream, t, palette), image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -705,9 +571,22 @@ void save_to_stream(T const& image, else throw ImageWriterException("Could not write to empty stream" ); } - template -void save_to_stream(T const& image, +void save_to_stream(image_view const& image, + std::ostream & stream, + std::string const& type) +{ + save_to_stream(image.data(), stream, type); +} + +void save_to_stream(image_32 const& image, + std::ostream & stream, + std::string const& type) +{ + save_to_stream(image.data(), stream, type); +} + +void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type) { @@ -717,27 +596,7 @@ void save_to_stream(T const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t,opts); - if (opts.paletted) - { - if (opts.use_hextree) - { - save_as_png8_hex(stream, image, opts); - } - else - { - save_as_png8_oct(stream, image, opts); - } - } - else - { - save_as_png(stream, image, opts); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + mapnik::util::apply_visitor(png_saver(stream, t), image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -800,7 +659,7 @@ void save_to_file(T const& image, std::string const& filename) } template -void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) +void save_to_file(T const& image, std::string const& filename, rgba_palette_ptr const& palette) { boost::optional type = type_from_filename(filename); if (type) @@ -899,21 +758,21 @@ template void save_to_file(image_data_rgba8 const&, template void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template void save_to_file(image_data_rgba8 const&, std::string const&); template void save_to_file(image_data_rgba8 const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template std::string save_to_string(image_data_rgba8 const&, std::string const&); template std::string save_to_string(image_data_rgba8 const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template void save_to_file > (image_view const&, std::string const&, @@ -922,21 +781,21 @@ template void save_to_file > (image_view > (image_view const&, std::string const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template void save_to_file > (image_view const&, std::string const&); template void save_to_file > (image_view const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template std::string save_to_string > (image_view const&, std::string const&); template std::string save_to_string > (image_view const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); void save_to_file(image_32 const& image,std::string const& file) { @@ -953,7 +812,7 @@ void save_to_file (image_32 const& image, void save_to_file (image_32 const& image, std::string const& file, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { save_to_file(image.data(), file, type, palette); } @@ -966,7 +825,7 @@ std::string save_to_string(image_32 const& image, std::string save_to_string(image_32 const& image, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { return save_to_string(image.data(), type, palette); } diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp new file mode 100644 index 000000000..344a8a151 --- /dev/null +++ b/src/image_util_png.cpp @@ -0,0 +1,241 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#if defined(HAVE_PNG) +extern "C" +{ +#include +} +#endif + +// mapnik +#if defined(HAVE_PNG) +#include +#endif + +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +#if defined(HAVE_PNG) + +void handle_png_options(std::string const& type, + png_options & opts) +{ + if (type == "png" || type == "png24" || type == "png32") + { + opts.paletted = false; + return; + } + else if (type == "png8" || type == "png256") + { + opts.paletted = true; + return; + } + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + bool set_colors = false; + bool set_gamma = false; + for (std::string const& t : tokens) + { + if (t == "png8" || t == "png256") + { + opts.paletted = true; + } + else if (t == "png" || t == "png24" || t == "png32") + { + opts.paletted = false; + } + else if (t == "m=o") + { + opts.use_hextree = false; + } + else if (t == "m=h") + { + opts.use_hextree = true; + } + else if (t == "e=miniz") + { + opts.use_miniz = true; + } + else if (boost::algorithm::starts_with(t, "c=")) + { + set_colors = true; + if (!mapnik::util::string2int(t.substr(2),opts.colors) || opts.colors < 1 || opts.colors > 256) + { + throw ImageWriterException("invalid color parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "t=")) + { + if (!mapnik::util::string2int(t.substr(2),opts.trans_mode) || opts.trans_mode < 0 || opts.trans_mode > 2) + { + throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "g=")) + { + set_gamma = true; + if (!mapnik::util::string2double(t.substr(2),opts.gamma) || opts.gamma < 0) + { + throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "z=")) + { + /* + #define Z_NO_COMPRESSION 0 + #define Z_BEST_SPEED 1 + #define Z_BEST_COMPRESSION 9 + #define Z_DEFAULT_COMPRESSION (-1) + */ + if (!mapnik::util::string2int(t.substr(2),opts.compression) + || opts.compression < Z_DEFAULT_COMPRESSION + || opts.compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION + { + throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)"); + } + } + else if (boost::algorithm::starts_with(t, "s=")) + { + std::string s = t.substr(2); + if (s == "default") + { + opts.strategy = Z_DEFAULT_STRATEGY; + } + else if (s == "filtered") + { + opts.strategy = Z_FILTERED; + } + else if (s == "huff") + { + opts.strategy = Z_HUFFMAN_ONLY; + } + else if (s == "rle") + { + opts.strategy = Z_RLE; + } + else if (s == "fixed") + { + opts.strategy = Z_FIXED; + } + else + { + throw ImageWriterException("invalid compression strategy parameter: " + s); + } + } + else + { + throw ImageWriterException("unhandled png option: " + t); + } + } + // validation + if (!opts.paletted && set_colors) + { + throw ImageWriterException("invalid color parameter: unavailable for true color (non-paletted) images"); + } + if (!opts.paletted && set_gamma) + { + throw ImageWriterException("invalid gamma parameter: unavailable for true color (non-paletted) images"); + } + if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) + { + throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)"); + } +} +#endif + +png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): + _stream(stream), _t(t), _pal(pal) {} + +void png_saver::operator() (mapnik::image_data_rgba8 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + if (_pal && _pal->valid()) + { + png_options opts; + handle_png_options(t,opts); + save_as_png8_pal(stream, image, _pal, opts); + } + else if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(_stream, image, opts); + } + else + { + save_as_png8_oct(_stream, image, opts); + } + } + else + { + save_as_png(_stream, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (mapnik::image_data_gray8 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (mapnik::image_data_gray16 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (mapnik::image_data_gray32f const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} From 6df688160c56a9f612e81e4ac08a5e89c7a3d630 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 7 Jan 2015 18:16:38 -0500 Subject: [PATCH 07/91] More stuff to break it all --- include/mapnik/graphics.hpp | 4 ++ include/mapnik/image_data_any.hpp | 21 ++++++--- include/mapnik/image_view.hpp | 8 ++-- src/image_util.cpp | 32 -------------- src/image_util_png.cpp | 71 +++++++++++++++++++++++++++++-- 5 files changed, 92 insertions(+), 44 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 0e753fb44..3a2ce4db5 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -112,6 +112,10 @@ public: { return data_.getBytes(); } + inline const unsigned char* getBytes() const + { + return data_.getBytes(); + } inline unsigned char* raw_data() { diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index c9b2d0b2e..e97d8d849 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -24,6 +24,8 @@ #define MAPNIK_IMAGE_DATA_ANY_HPP #include +#include +#include #include namespace mapnik { @@ -36,18 +38,27 @@ struct image_data_null std::size_t height() const { return 0; } }; -using image_data_base = util::variant; +using image_data_base = util::variant, + image_view, + image_view, + image_view>; namespace detail { -struct get_bytes_visitor : util::static_visitor +/*struct get_bytes_visitor : util::static_visitor { template unsigned char* operator()(T & data) { return data.getBytes(); } -}; +};*/ struct get_bytes_visitor_const : util::static_visitor { @@ -91,10 +102,10 @@ struct image_data_any : image_data_base return util::apply_visitor(detail::get_bytes_visitor_const(),*this); } - unsigned char* getBytes() + /*unsigned char* getBytes() { return util::apply_visitor(detail::get_bytes_visitor(),*this); - } + }*/ std::size_t width() const { diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 4b648aab5..146271ade 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -109,18 +109,18 @@ public: { return data_.getBytes(); } - inline T& data() + /*inline T& data() { return data_; - } + }*/ inline T const& data() const { return data_; } - inline pixel_type* getData() + /*inline pixel_type* getData() { return data_.getData(); - } + }*/ inline const pixel_type* getData() const { return data_.getData(); diff --git a/src/image_util.cpp b/src/image_util.cpp index 55e7cdf3f..2d0e68747 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -528,23 +528,6 @@ void handle_webp_options(std::string const& type, } #endif -template -void save_to_stream(image_view const& image, - std::ostream & stream, - std::string const& type, - rgba_palette_ptr const& palette) -{ - save_to_stream(image.data(), stream, type, palette); -} - -void save_to_stream(image_32 const& image, - std::ostream & stream, - std::string const& type, - rgba_palette_ptr const& palette) -{ - save_to_stream(image.data(), stream, type, palette); -} - void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type, @@ -571,21 +554,6 @@ void save_to_stream(image_data_any const& image, else throw ImageWriterException("Could not write to empty stream" ); } -template -void save_to_stream(image_view const& image, - std::ostream & stream, - std::string const& type) -{ - save_to_stream(image.data(), stream, type); -} - -void save_to_stream(image_32 const& image, - std::ostream & stream, - std::string const& type) -{ - save_to_stream(image.data(), stream, type); -} - void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type) diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 344a8a151..31cccec57 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -176,7 +176,7 @@ void handle_png_options(std::string const& type, png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): _stream(stream), _t(t), _pal(pal) {} -void png_saver::operator() (mapnik::image_data_rgba8 const& image) const +void png_saver::operator() (image_data_rgba8 const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -207,7 +207,38 @@ void png_saver::operator() (mapnik::image_data_rgba8 const& image) const #endif } -void png_saver::operator() (mapnik::image_data_gray8 const& image) const +void png_saver::operator() (image_view const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + if (_pal && _pal->valid()) + { + png_options opts; + handle_png_options(t,opts); + save_as_png8_pal(stream, image, _pal, opts); + } + else if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(_stream, image, opts); + } + else + { + save_as_png8_oct(_stream, image, opts); + } + } + else + { + save_as_png(_stream, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (image_data_gray8 const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -218,7 +249,29 @@ void png_saver::operator() (mapnik::image_data_gray8 const& image) const #endif } -void png_saver::operator() (mapnik::image_data_gray16 const& image) const +void png_saver::operator() (image_view const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (image_data_gray16 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (image_view const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -239,3 +292,15 @@ void png_saver::operator() (mapnik::image_data_gray32f const& image) const throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif } +void png_saver::operator() (mapnik::image_data_gray32f const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +} // end ns From 515491ab705a7245bc66fd90e047827557239c3d Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 8 Jan 2015 12:42:38 +0100 Subject: [PATCH 08/91] image_compositing - fix composite method signature to composite(T & dst, T const& src,...) via providing const_rendering_buffer adapter --- include/mapnik/image_compositing.hpp | 2 +- src/image_compositing.cpp | 51 +++++++++++++++++++++------- 2 files changed, 39 insertions(+), 14 deletions(-) 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); } } From 454326df177a54e38f02c15eea85045d3f4aad15 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 7 Jan 2015 15:44:31 -0500 Subject: [PATCH 09/91] An intial commit of a large set of changes attempting to clean up the way that saving images is processed in image_util.hpp and image_util.cpp. * Changed the passing of rgba_palette to a shared_ptr in order to better facilitate the use of a visitor pattern. * Moved PNG util processing into its own set of files so that image_util_impl.hpp would not have to depend on HAVE_PNG. --- .gitignore | 1 + bindings/python/mapnik_image.cpp | 4 +- bindings/python/mapnik_image_view.cpp | 4 +- bindings/python/mapnik_palette.cpp | 2 +- include/mapnik/image_util.hpp | 33 ++-- include/mapnik/image_util_png.hpp | 48 +++++ include/mapnik/palette.hpp | 2 + include/mapnik/png_io.hpp | 20 +-- src/image_util.cpp | 237 +++++-------------------- src/image_util_png.cpp | 241 ++++++++++++++++++++++++++ 10 files changed, 372 insertions(+), 220 deletions(-) create mode 100644 include/mapnik/image_util_png.hpp create mode 100644 src/image_util_png.cpp diff --git a/.gitignore b/.gitignore index bbf225e80..a7653de61 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.os *.so *.a +*.swp *.dylib plugins/input/*.input plugins/input/templates/*.input diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 5d674be72..92e023970 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -83,7 +83,7 @@ PyObject* tostring2(image_32 const & im, std::string const& format) (s.data(),s.size()); } -PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette_ptr const& pal) { std::string s = save_to_string(im, format, pal); return @@ -106,7 +106,7 @@ void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std: save_to_file(im,filename,type); } -void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) +void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette_ptr const& pal) { save_to_file(im,filename,type,pal); } diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index e08129f7f..bcd890385 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -77,7 +77,7 @@ PyObject* view_tostring2(image_view const & view, std::string (s.data(),s.size()); } -PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette_ptr const& pal) { std::string s = save_to_string(view, format, pal); return @@ -126,7 +126,7 @@ void save_view2(image_view const& view, void save_view3(image_view const& view, std::string const& filename, std::string const& type, - mapnik::rgba_palette const& pal) + mapnik::rgba_palette_ptr const& pal) { save_to_file(view,filename,type,pal); } diff --git a/bindings/python/mapnik_palette.cpp b/bindings/python/mapnik_palette.cpp index 12cf2fdec..08ab80e92 100644 --- a/bindings/python/mapnik_palette.cpp +++ b/bindings/python/mapnik_palette.cpp @@ -55,7 +55,7 @@ void export_palette () { using namespace boost::python; - class_, std::shared_ptr, boost::noncopyable >("Palette",no_init) //, init( diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index f6bb1ca21..b00c44c8b 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -46,6 +46,7 @@ namespace mapnik { class Map; class rgba_palette; class image_32; +typedef std::shared_ptr rgba_palette_ptr; class ImageWriterException : public std::exception { @@ -84,7 +85,7 @@ template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); // guess type from file extension template @@ -94,7 +95,7 @@ MAPNIK_DECL void save_to_file(T const& image, template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template MAPNIK_DECL std::string save_to_string(T const& image, @@ -103,7 +104,7 @@ MAPNIK_DECL std::string save_to_string(T const& image, template MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template MAPNIK_DECL void save_to_stream @@ -111,7 +112,7 @@ MAPNIK_DECL void save_to_stream T const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette + rgba_palette_ptr const& palette ); template @@ -125,7 +126,7 @@ MAPNIK_DECL void save_to_stream template void save_as_png(T const& image, std::string const& filename, - rgba_palette const& palette); + rgba_palette_ptr const& palette); #if defined(HAVE_JPEG) template @@ -224,7 +225,7 @@ MAPNIK_DECL void save_to_file (image_32 const& image, MAPNIK_DECL void save_to_file (image_32 const& image, std::string const& file, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); /////////////////////////////////////////////////////////////////////////// @@ -234,14 +235,14 @@ MAPNIK_DECL std::string save_to_string(image_32 const& image, MAPNIK_DECL std::string save_to_string(image_32 const& image, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); /////////////////////////////////////////////////////////////////////////// MAPNIK_DECL void save_to_stream(image_32 const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette); + rgba_palette_ptr const& palette); MAPNIK_DECL void save_to_stream(image_32 const& image, std::ostream & stream, @@ -252,7 +253,7 @@ MAPNIK_DECL void save_to_stream(image_32 const& image, extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, @@ -260,7 +261,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&); @@ -269,7 +270,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, @@ -277,7 +278,7 @@ extern template MAPNIK_DECL void save_to_file > (im extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&); @@ -287,21 +288,21 @@ extern template MAPNIK_DECL std::string save_to_string(image_d extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); extern template MAPNIK_DECL std::string save_to_string > (image_view const&, std::string const&); extern template MAPNIK_DECL std::string save_to_string > (image_view const&, std::string const&, - rgba_palette const&); + rgba_palette_ptr const&); #ifdef _MSC_VER template MAPNIK_DECL void save_to_stream( image_data_rgba8 const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette + rgba_palette_ptr const& palette ); template MAPNIK_DECL void save_to_stream( @@ -314,7 +315,7 @@ template MAPNIK_DECL void save_to_stream > ( image_view const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette + rgba_palette_ptr const& palette ); template MAPNIK_DECL void save_to_stream > ( diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp new file mode 100644 index 000000000..9a3f6d7b9 --- /dev/null +++ b/include/mapnik/image_util_png.hpp @@ -0,0 +1,48 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_UTIL_PNG_HPP +#define MAPNIK_IMAGE_UTIL_PNG_HPP + +// mapnik +#include + +// stl +#include +#include + +namespace mapnik { + +struct png_saver : public mapnik::util::static_visitor<> +{ + png_saver(std::ostream &, std::string &, rgba_palette_ptr const& = nullptr); + template + void operator() (T const&) const; + private: + std::ostream _stream; + std::string _t; + rgba_palette_ptr _pal; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_PNG_HPP diff --git a/include/mapnik/palette.hpp b/include/mapnik/palette.hpp index 5dc3a4cdf..950a76984 100644 --- a/include/mapnik/palette.hpp +++ b/include/mapnik/palette.hpp @@ -130,6 +130,8 @@ private: std::vector alpha_pal_; }; +typedef std::shared_ptr rgba_palette_ptr; + } // namespace mapnik #endif // MAPNIK_PALETTE_HPP diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 7034ca293..4efd781ff 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -607,7 +607,7 @@ void save_as_png8(T1 & file, mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); for (unsigned x = 0; x < width; ++x) { - row_out[x] = tree.quantize(row[x]); + row_out[x] = tree->quantize(row[x]); } } save_as_png(file, palette, reduced_image, width, height, 8, alphaTable, opts); @@ -635,7 +635,7 @@ void save_as_png8(T1 & file, for (unsigned x = 0; x < width; ++x) { - index = tree.quantize(row[x]); + index = tree->quantize(row[x]); if (x%2 == 0) { index = index<<4; @@ -657,14 +657,14 @@ void save_as_png8_hex(T1 & file, if (width + height > 3) // at least 3 pixels (hextree implementation requirement) { // structure for color quantization - hextree tree(opts.colors); + std::shared_ptr> tree = std::make_shared>(opts.colors); if (opts.trans_mode >= 0) { - tree.setTransMode(opts.trans_mode); + tree->setTransMode(opts.trans_mode); } if (opts.gamma > 0) { - tree.setGamma(opts.gamma); + tree->setGamma(opts.gamma); } for (unsigned y = 0; y < height; ++y) @@ -673,13 +673,13 @@ void save_as_png8_hex(T1 & file, for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; - tree.insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val))); + tree->insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val))); } } //transparency values per palette index std::vector pal; - tree.create_palette(pal); + tree->create_palette(pal); std::vector palette; std::vector alphaTable; for (unsigned i=0; i >(file, image, tree, palette, alphaTable, opts); + save_as_png8> >(file, image, tree, palette, alphaTable, opts); } else { @@ -698,10 +698,10 @@ void save_as_png8_hex(T1 & file, template void save_as_png8_pal(T1 & file, T2 const& image, - rgba_palette const& pal, + rgba_palette_ptr const& pal, png_options const& opts) { - save_as_png8(file, image, pal, pal.palette(), pal.alphaTable(), opts); + save_as_png8(file, image, pal, pal->palette(), pal->alphaTable(), opts); } } diff --git a/src/image_util.cpp b/src/image_util.cpp index a5bb8e98f..55e7cdf3f 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -20,18 +20,7 @@ * *****************************************************************************/ -#if defined(HAVE_PNG) -extern "C" -{ -#include -} -#endif - // mapnik -#if defined(HAVE_PNG) -#include -#endif - #if defined(HAVE_TIFF) #include #endif @@ -45,6 +34,7 @@ extern "C" #endif #include +#include #include #include #include @@ -52,6 +42,7 @@ extern "C" #include #include #include +#include #ifdef HAVE_CAIRO #include @@ -84,7 +75,7 @@ namespace mapnik template std::string save_to_string(T const& image, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { std::ostringstream ss(std::ios::out|std::ios::binary); save_to_stream(image, ss, type, palette); @@ -104,7 +95,7 @@ template void save_to_file(T const& image, std::string const& filename, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) @@ -127,134 +118,6 @@ void save_to_file(T const& image, else throw ImageWriterException("Could not write file to " + filename ); } -#if defined(HAVE_PNG) - -void handle_png_options(std::string const& type, - png_options & opts) -{ - if (type == "png" || type == "png24" || type == "png32") - { - opts.paletted = false; - return; - } - else if (type == "png8" || type == "png256") - { - opts.paletted = true; - return; - } - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - bool set_colors = false; - bool set_gamma = false; - for (std::string const& t : tokens) - { - if (t == "png8" || t == "png256") - { - opts.paletted = true; - } - else if (t == "png" || t == "png24" || t == "png32") - { - opts.paletted = false; - } - else if (t == "m=o") - { - opts.use_hextree = false; - } - else if (t == "m=h") - { - opts.use_hextree = true; - } - else if (t == "e=miniz") - { - opts.use_miniz = true; - } - else if (boost::algorithm::starts_with(t, "c=")) - { - set_colors = true; - if (!mapnik::util::string2int(t.substr(2),opts.colors) || opts.colors < 1 || opts.colors > 256) - { - throw ImageWriterException("invalid color parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "t=")) - { - if (!mapnik::util::string2int(t.substr(2),opts.trans_mode) || opts.trans_mode < 0 || opts.trans_mode > 2) - { - throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "g=")) - { - set_gamma = true; - if (!mapnik::util::string2double(t.substr(2),opts.gamma) || opts.gamma < 0) - { - throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "z=")) - { - /* - #define Z_NO_COMPRESSION 0 - #define Z_BEST_SPEED 1 - #define Z_BEST_COMPRESSION 9 - #define Z_DEFAULT_COMPRESSION (-1) - */ - if (!mapnik::util::string2int(t.substr(2),opts.compression) - || opts.compression < Z_DEFAULT_COMPRESSION - || opts.compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION - { - throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)"); - } - } - else if (boost::algorithm::starts_with(t, "s=")) - { - std::string s = t.substr(2); - if (s == "default") - { - opts.strategy = Z_DEFAULT_STRATEGY; - } - else if (s == "filtered") - { - opts.strategy = Z_FILTERED; - } - else if (s == "huff") - { - opts.strategy = Z_HUFFMAN_ONLY; - } - else if (s == "rle") - { - opts.strategy = Z_RLE; - } - else if (s == "fixed") - { - opts.strategy = Z_FIXED; - } - else - { - throw ImageWriterException("invalid compression strategy parameter: " + s); - } - } - else - { - throw ImageWriterException("unhandled png option: " + t); - } - } - // validation - if (!opts.paletted && set_colors) - { - throw ImageWriterException("invalid color parameter: unavailable for true color (non-paletted) images"); - } - if (!opts.paletted && set_gamma) - { - throw ImageWriterException("invalid gamma parameter: unavailable for true color (non-paletted) images"); - } - if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) - { - throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)"); - } -} -#endif - #if defined(HAVE_TIFF) void handle_tiff_options(std::string const& type, tiff_config & config) @@ -666,10 +529,26 @@ void handle_webp_options(std::string const& type, #endif template -void save_to_stream(T const& image, +void save_to_stream(image_view const& image, std::ostream & stream, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) +{ + save_to_stream(image.data(), stream, type, palette); +} + +void save_to_stream(image_32 const& image, + std::ostream & stream, + std::string const& type, + rgba_palette_ptr const& palette) +{ + save_to_stream(image.data(), stream, type, palette); +} + +void save_to_stream(image_data_any const& image, + std::ostream & stream, + std::string const& type, + rgba_palette_ptr const& palette) { if (stream && image.width() > 0 && image.height() > 0) { @@ -677,20 +556,7 @@ void save_to_stream(T const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { -#if defined(HAVE_PNG) - if (palette.valid()) - { - png_options opts; - handle_png_options(t,opts); - save_as_png8_pal(stream, image, palette, opts); - } - else - { - save_to_stream(image,stream,type); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + mapnik::util::apply_visitor(png_saver(stream, t, palette), image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -705,9 +571,22 @@ void save_to_stream(T const& image, else throw ImageWriterException("Could not write to empty stream" ); } - template -void save_to_stream(T const& image, +void save_to_stream(image_view const& image, + std::ostream & stream, + std::string const& type) +{ + save_to_stream(image.data(), stream, type); +} + +void save_to_stream(image_32 const& image, + std::ostream & stream, + std::string const& type) +{ + save_to_stream(image.data(), stream, type); +} + +void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type) { @@ -717,27 +596,7 @@ void save_to_stream(T const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t,opts); - if (opts.paletted) - { - if (opts.use_hextree) - { - save_as_png8_hex(stream, image, opts); - } - else - { - save_as_png8_oct(stream, image, opts); - } - } - else - { - save_as_png(stream, image, opts); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + mapnik::util::apply_visitor(png_saver(stream, t), image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -800,7 +659,7 @@ void save_to_file(T const& image, std::string const& filename) } template -void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) +void save_to_file(T const& image, std::string const& filename, rgba_palette_ptr const& palette) { boost::optional type = type_from_filename(filename); if (type) @@ -899,21 +758,21 @@ template void save_to_file(image_data_rgba8 const&, template void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template void save_to_file(image_data_rgba8 const&, std::string const&); template void save_to_file(image_data_rgba8 const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template std::string save_to_string(image_data_rgba8 const&, std::string const&); template std::string save_to_string(image_data_rgba8 const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template void save_to_file > (image_view const&, std::string const&, @@ -922,21 +781,21 @@ template void save_to_file > (image_view > (image_view const&, std::string const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template void save_to_file > (image_view const&, std::string const&); template void save_to_file > (image_view const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); template std::string save_to_string > (image_view const&, std::string const&); template std::string save_to_string > (image_view const&, std::string const&, - rgba_palette const& palette); + rgba_palette_ptr const& palette); void save_to_file(image_32 const& image,std::string const& file) { @@ -953,7 +812,7 @@ void save_to_file (image_32 const& image, void save_to_file (image_32 const& image, std::string const& file, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { save_to_file(image.data(), file, type, palette); } @@ -966,7 +825,7 @@ std::string save_to_string(image_32 const& image, std::string save_to_string(image_32 const& image, std::string const& type, - rgba_palette const& palette) + rgba_palette_ptr const& palette) { return save_to_string(image.data(), type, palette); } diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp new file mode 100644 index 000000000..344a8a151 --- /dev/null +++ b/src/image_util_png.cpp @@ -0,0 +1,241 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#if defined(HAVE_PNG) +extern "C" +{ +#include +} +#endif + +// mapnik +#if defined(HAVE_PNG) +#include +#endif + +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +#if defined(HAVE_PNG) + +void handle_png_options(std::string const& type, + png_options & opts) +{ + if (type == "png" || type == "png24" || type == "png32") + { + opts.paletted = false; + return; + } + else if (type == "png8" || type == "png256") + { + opts.paletted = true; + return; + } + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + bool set_colors = false; + bool set_gamma = false; + for (std::string const& t : tokens) + { + if (t == "png8" || t == "png256") + { + opts.paletted = true; + } + else if (t == "png" || t == "png24" || t == "png32") + { + opts.paletted = false; + } + else if (t == "m=o") + { + opts.use_hextree = false; + } + else if (t == "m=h") + { + opts.use_hextree = true; + } + else if (t == "e=miniz") + { + opts.use_miniz = true; + } + else if (boost::algorithm::starts_with(t, "c=")) + { + set_colors = true; + if (!mapnik::util::string2int(t.substr(2),opts.colors) || opts.colors < 1 || opts.colors > 256) + { + throw ImageWriterException("invalid color parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "t=")) + { + if (!mapnik::util::string2int(t.substr(2),opts.trans_mode) || opts.trans_mode < 0 || opts.trans_mode > 2) + { + throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "g=")) + { + set_gamma = true; + if (!mapnik::util::string2double(t.substr(2),opts.gamma) || opts.gamma < 0) + { + throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "z=")) + { + /* + #define Z_NO_COMPRESSION 0 + #define Z_BEST_SPEED 1 + #define Z_BEST_COMPRESSION 9 + #define Z_DEFAULT_COMPRESSION (-1) + */ + if (!mapnik::util::string2int(t.substr(2),opts.compression) + || opts.compression < Z_DEFAULT_COMPRESSION + || opts.compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION + { + throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)"); + } + } + else if (boost::algorithm::starts_with(t, "s=")) + { + std::string s = t.substr(2); + if (s == "default") + { + opts.strategy = Z_DEFAULT_STRATEGY; + } + else if (s == "filtered") + { + opts.strategy = Z_FILTERED; + } + else if (s == "huff") + { + opts.strategy = Z_HUFFMAN_ONLY; + } + else if (s == "rle") + { + opts.strategy = Z_RLE; + } + else if (s == "fixed") + { + opts.strategy = Z_FIXED; + } + else + { + throw ImageWriterException("invalid compression strategy parameter: " + s); + } + } + else + { + throw ImageWriterException("unhandled png option: " + t); + } + } + // validation + if (!opts.paletted && set_colors) + { + throw ImageWriterException("invalid color parameter: unavailable for true color (non-paletted) images"); + } + if (!opts.paletted && set_gamma) + { + throw ImageWriterException("invalid gamma parameter: unavailable for true color (non-paletted) images"); + } + if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) + { + throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)"); + } +} +#endif + +png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): + _stream(stream), _t(t), _pal(pal) {} + +void png_saver::operator() (mapnik::image_data_rgba8 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + if (_pal && _pal->valid()) + { + png_options opts; + handle_png_options(t,opts); + save_as_png8_pal(stream, image, _pal, opts); + } + else if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(_stream, image, opts); + } + else + { + save_as_png8_oct(_stream, image, opts); + } + } + else + { + save_as_png(_stream, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (mapnik::image_data_gray8 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (mapnik::image_data_gray16 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (mapnik::image_data_gray32f const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} From cc0a27f2f0a9f85de0da67f4250121a16453bc1c Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 7 Jan 2015 18:16:38 -0500 Subject: [PATCH 10/91] More stuff to break it all --- include/mapnik/graphics.hpp | 4 ++ include/mapnik/image_data_any.hpp | 13 +++++- include/mapnik/image_view.hpp | 2 +- src/image_util.cpp | 32 -------------- src/image_util_png.cpp | 71 +++++++++++++++++++++++++++++-- 5 files changed, 85 insertions(+), 37 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 0e753fb44..3a2ce4db5 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -112,6 +112,10 @@ public: { return data_.getBytes(); } + inline const unsigned char* getBytes() const + { + return data_.getBytes(); + } inline unsigned char* raw_data() { diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index c09bfdf7d..e1501cd16 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -24,6 +24,8 @@ #define MAPNIK_IMAGE_DATA_ANY_HPP #include +#include +#include #include namespace mapnik { @@ -36,7 +38,16 @@ struct image_data_null std::size_t height() const { return 0; } }; -using image_data_base = util::variant; +using image_data_base = util::variant, + image_view, + image_view, + image_view>; namespace detail { diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index ede67e490..7be33bf78 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -109,7 +109,7 @@ public: { return data_.getBytes(); } - + inline T const& data() const { return data_; diff --git a/src/image_util.cpp b/src/image_util.cpp index 55e7cdf3f..2d0e68747 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -528,23 +528,6 @@ void handle_webp_options(std::string const& type, } #endif -template -void save_to_stream(image_view const& image, - std::ostream & stream, - std::string const& type, - rgba_palette_ptr const& palette) -{ - save_to_stream(image.data(), stream, type, palette); -} - -void save_to_stream(image_32 const& image, - std::ostream & stream, - std::string const& type, - rgba_palette_ptr const& palette) -{ - save_to_stream(image.data(), stream, type, palette); -} - void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type, @@ -571,21 +554,6 @@ void save_to_stream(image_data_any const& image, else throw ImageWriterException("Could not write to empty stream" ); } -template -void save_to_stream(image_view const& image, - std::ostream & stream, - std::string const& type) -{ - save_to_stream(image.data(), stream, type); -} - -void save_to_stream(image_32 const& image, - std::ostream & stream, - std::string const& type) -{ - save_to_stream(image.data(), stream, type); -} - void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type) diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 344a8a151..31cccec57 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -176,7 +176,7 @@ void handle_png_options(std::string const& type, png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): _stream(stream), _t(t), _pal(pal) {} -void png_saver::operator() (mapnik::image_data_rgba8 const& image) const +void png_saver::operator() (image_data_rgba8 const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -207,7 +207,38 @@ void png_saver::operator() (mapnik::image_data_rgba8 const& image) const #endif } -void png_saver::operator() (mapnik::image_data_gray8 const& image) const +void png_saver::operator() (image_view const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + if (_pal && _pal->valid()) + { + png_options opts; + handle_png_options(t,opts); + save_as_png8_pal(stream, image, _pal, opts); + } + else if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(_stream, image, opts); + } + else + { + save_as_png8_oct(_stream, image, opts); + } + } + else + { + save_as_png(_stream, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (image_data_gray8 const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -218,7 +249,29 @@ void png_saver::operator() (mapnik::image_data_gray8 const& image) const #endif } -void png_saver::operator() (mapnik::image_data_gray16 const& image) const +void png_saver::operator() (image_view const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (image_data_gray16 const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver::operator() (image_view const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -239,3 +292,15 @@ void png_saver::operator() (mapnik::image_data_gray32f const& image) const throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif } +void png_saver::operator() (mapnik::image_data_gray32f const& image) const +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(_t, opts); + save_as_png(_stream, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +} // end ns From 847682d783d7f0a3669989ca9227e43a3be5658f Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 8 Jan 2015 10:12:34 -0500 Subject: [PATCH 11/91] Some more minor changes --- include/mapnik/graphics.hpp | 1 + src/image_util.cpp | 11 +++++++---- src/image_util_png.cpp | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 3a2ce4db5..24d49b8a5 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -49,6 +49,7 @@ using cairo_surface_ptr = std::shared_ptr; class MAPNIK_DECL image_32 { + using pixel_type = typename image_data_rgba8::pixel_type; private: unsigned width_; unsigned height_; diff --git a/src/image_util.cpp b/src/image_util.cpp index 2d0e68747..6a8f2e27a 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -528,7 +528,8 @@ void handle_webp_options(std::string const& type, } #endif -void save_to_stream(image_data_any const& image, +template +void save_to_stream(T const& image, std::ostream & stream, std::string const& type, rgba_palette_ptr const& palette) @@ -538,8 +539,9 @@ void save_to_stream(image_data_any const& image, std::string t = type; std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) - { - mapnik::util::apply_visitor(png_saver(stream, t, palette), image); + { + png_saver visitor(stream, t, palette); + mapnik::util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -554,7 +556,8 @@ void save_to_stream(image_data_any const& image, else throw ImageWriterException("Could not write to empty stream" ); } -void save_to_stream(image_data_any const& image, +template +void save_to_stream(T const& image, std::ostream & stream, std::string const& type) { diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 31cccec57..0cc5ac2bc 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -176,6 +176,11 @@ void handle_png_options(std::string const& type, png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): _stream(stream), _t(t), _pal(pal) {} +void png_saver::operator() (image_data_null const& image) const +{ + throw ImageWriterException("null images not supported"); +} + void png_saver::operator() (image_data_rgba8 const& image) const { #if defined(HAVE_PNG) From 81ef4225acba3979f8f8734698b22cc0b7934986 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 8 Jan 2015 11:30:02 -0500 Subject: [PATCH 12/91] Continuing to modify various areas of image_util so that save_to_stream will be provided an image_data_any object. --- include/mapnik/graphics.hpp | 8 ++++- include/mapnik/image_util_png.hpp | 6 ++-- include/mapnik/image_view.hpp | 5 ++++ src/image_util.cpp | 6 ++-- src/image_util_png.cpp | 50 +++++++++++++++---------------- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 24d49b8a5..b45da8dc0 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -49,7 +49,6 @@ using cairo_surface_ptr = std::shared_ptr; class MAPNIK_DECL image_32 { - using pixel_type = typename image_data_rgba8::pixel_type; private: unsigned width_; unsigned height_; @@ -58,6 +57,7 @@ private: bool painted_; bool premultiplied_; public: + using pixel_type = typename image_data_rgba8::pixel_type; image_32(int width,int height); image_32(image_32 const& rhs); #ifdef HAVE_CAIRO @@ -113,6 +113,7 @@ public: { return data_.getBytes(); } + inline const unsigned char* getBytes() const { return data_.getBytes(); @@ -123,6 +124,11 @@ public: return data_.getBytes(); } + inline unsigned char* getBytes() + { + return data_.getBytes(); + } + inline image_view get_view(unsigned x,unsigned y, unsigned w,unsigned h) { return image_view(x,y,w,h,data_); diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp index 9a3f6d7b9..b3097b24a 100644 --- a/include/mapnik/image_util_png.hpp +++ b/include/mapnik/image_util_png.hpp @@ -38,9 +38,9 @@ struct png_saver : public mapnik::util::static_visitor<> template void operator() (T const&) const; private: - std::ostream _stream; - std::string _t; - rgba_palette_ptr _pal; + std::ostream & stream_; + std::string const& t_; + rgba_palette_ptr const& pal_; }; } // end ns diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 7be33bf78..0b748d552 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -110,6 +110,11 @@ public: return data_.getBytes(); } + inline unsigned char* getBytes() + { + return const_cast(data_.getBytes()); + } + inline T const& data() const { return data_; diff --git a/src/image_util.cpp b/src/image_util.cpp index 6a8f2e27a..42cd489af 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -528,8 +528,7 @@ void handle_webp_options(std::string const& type, } #endif -template -void save_to_stream(T const& image, +void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type, rgba_palette_ptr const& palette) @@ -556,8 +555,7 @@ void save_to_stream(T const& image, else throw ImageWriterException("Could not write to empty stream" ); } -template -void save_to_stream(T const& image, +void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type) { diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 0cc5ac2bc..b639b98d2 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -174,7 +174,7 @@ void handle_png_options(std::string const& type, #endif png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): - _stream(stream), _t(t), _pal(pal) {} + stream_(stream), t_(t), pal_(pal) {} void png_saver::operator() (image_data_null const& image) const { @@ -185,27 +185,27 @@ void png_saver::operator() (image_data_rgba8 const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - if (_pal && _pal->valid()) + handle_png_options(t_, opts); + if (pal_ && pal_->valid()) { png_options opts; handle_png_options(t,opts); - save_as_png8_pal(stream, image, _pal, opts); + save_as_png8_pal(stream, image, pal_, opts); } else if (opts.paletted) { if (opts.use_hextree) { - save_as_png8_hex(_stream, image, opts); + save_as_png8_hex(stream_, image, opts); } else { - save_as_png8_oct(_stream, image, opts); + save_as_png8_oct(stream_, image, opts); } } else { - save_as_png(_stream, image, opts); + save_as_png(stream_, image, opts); } #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); @@ -216,27 +216,27 @@ void png_saver::operator() (image_view const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - if (_pal && _pal->valid()) + handle_png_options(t_, opts); + if (pal_ && pal_->valid()) { png_options opts; handle_png_options(t,opts); - save_as_png8_pal(stream, image, _pal, opts); + save_as_png8_pal(stream, image, pal_, opts); } else if (opts.paletted) { if (opts.use_hextree) { - save_as_png8_hex(_stream, image, opts); + save_as_png8_hex(stream_, image, opts); } else { - save_as_png8_oct(_stream, image, opts); + save_as_png8_oct(stream_, image, opts); } } else { - save_as_png(_stream, image, opts); + save_as_png(stream_, image, opts); } #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); @@ -247,8 +247,8 @@ void png_saver::operator() (image_data_gray8 const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - save_as_png(_stream, image, opts); + handle_png_options(t_, opts); + save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif @@ -258,8 +258,8 @@ void png_saver::operator() (image_view const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - save_as_png(_stream, image, opts); + handle_png_options(t_, opts); + save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif @@ -269,8 +269,8 @@ void png_saver::operator() (image_data_gray16 const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - save_as_png(_stream, image, opts); + handle_png_options(t_, opts); + save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif @@ -280,8 +280,8 @@ void png_saver::operator() (image_view const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - save_as_png(_stream, image, opts); + handle_png_options(t_, opts); + save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif @@ -291,8 +291,8 @@ void png_saver::operator() (mapnik::image_data_gray32f const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - save_as_png(_stream, image, opts); + handle_png_options(t_, opts); + save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif @@ -301,8 +301,8 @@ void png_saver::operator() (mapnik::image_data_gray32f const& image) const { #if defined(HAVE_PNG) png_options opts; - handle_png_options(_t, opts); - save_as_png(_stream, image, opts); + handle_png_options(t_, opts); + save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif From 035557450d38462c1824693a90babaa83a86ac53 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 8 Jan 2015 16:55:51 -0500 Subject: [PATCH 13/91] Split out the process for tiff, webp, and jpeg into their own util folders. Added the intial concepts for an image_view_any variant. --- bindings/python/mapnik_image.cpp | 4 +- bindings/python/mapnik_image_view.cpp | 4 +- bindings/python/mapnik_palette.cpp | 2 +- include/mapnik/image_data_any.hpp | 9 +- include/mapnik/image_scaling_traits.hpp | 15 - include/mapnik/image_util.hpp | 33 +- include/mapnik/image_util_jpeg.hpp | 47 +++ include/mapnik/image_util_png.hpp | 16 +- include/mapnik/image_util_tiff.hpp | 47 +++ include/mapnik/image_util_webp.hpp | 47 +++ include/mapnik/image_view.hpp | 8 +- include/mapnik/image_view_any.hpp | 79 ++++ include/mapnik/palette.hpp | 2 - include/mapnik/png_io.hpp | 16 +- src/image_util.cpp | 495 ++---------------------- src/image_util_jpeg.cpp | 77 ++++ src/image_util_png.cpp | 138 ++++--- src/image_util_tiff.cpp | 191 +++++++++ src/image_util_webp.cpp | 366 ++++++++++++++++++ 19 files changed, 992 insertions(+), 604 deletions(-) create mode 100644 include/mapnik/image_util_jpeg.hpp create mode 100644 include/mapnik/image_util_tiff.hpp create mode 100644 include/mapnik/image_util_webp.hpp create mode 100644 include/mapnik/image_view_any.hpp create mode 100644 src/image_util_jpeg.cpp create mode 100644 src/image_util_tiff.cpp create mode 100644 src/image_util_webp.cpp diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 92e023970..5d674be72 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -83,7 +83,7 @@ PyObject* tostring2(image_32 const & im, std::string const& format) (s.data(),s.size()); } -PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette_ptr const& pal) +PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal) { std::string s = save_to_string(im, format, pal); return @@ -106,7 +106,7 @@ void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std: save_to_file(im,filename,type); } -void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette_ptr const& pal) +void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) { save_to_file(im,filename,type,pal); } diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index bcd890385..e08129f7f 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -77,7 +77,7 @@ PyObject* view_tostring2(image_view const & view, std::string (s.data(),s.size()); } -PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette_ptr const& pal) +PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette const& pal) { std::string s = save_to_string(view, format, pal); return @@ -126,7 +126,7 @@ void save_view2(image_view const& view, void save_view3(image_view const& view, std::string const& filename, std::string const& type, - mapnik::rgba_palette_ptr const& pal) + mapnik::rgba_palette const& pal) { save_to_file(view,filename,type,pal); } diff --git a/bindings/python/mapnik_palette.cpp b/bindings/python/mapnik_palette.cpp index 08ab80e92..12cf2fdec 100644 --- a/bindings/python/mapnik_palette.cpp +++ b/bindings/python/mapnik_palette.cpp @@ -55,7 +55,7 @@ void export_palette () { using namespace boost::python; - class_, + class_, boost::noncopyable >("Palette",no_init) //, init( diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index e1501cd16..336b4220c 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -24,8 +24,6 @@ #define MAPNIK_IMAGE_DATA_ANY_HPP #include -#include -#include #include namespace mapnik { @@ -42,12 +40,7 @@ using image_data_base = util::variant, - image_view, - image_view, - image_view>; + image_data_gray32f>; namespace detail { diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp index fbc805bb5..fe2ce61ed 100644 --- a/include/mapnik/image_scaling_traits.hpp +++ b/include/mapnik/image_scaling_traits.hpp @@ -23,9 +23,6 @@ #ifndef MAPNIK_IMAGE_SCALING_TRAITS_HPP #define MAPNIK_IMAGE_SCALING_TRAITS_HPP -// mapnik -#include - // agg #include "agg_image_accessors.h" #include "agg_pixfmt_rgba.h" @@ -52,18 +49,6 @@ 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 { diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index b00c44c8b..f6bb1ca21 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -46,7 +46,6 @@ namespace mapnik { class Map; class rgba_palette; class image_32; -typedef std::shared_ptr rgba_palette_ptr; class ImageWriterException : public std::exception { @@ -85,7 +84,7 @@ template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type, - rgba_palette_ptr const& palette); + rgba_palette const& palette); // guess type from file extension template @@ -95,7 +94,7 @@ MAPNIK_DECL void save_to_file(T const& image, template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template MAPNIK_DECL std::string save_to_string(T const& image, @@ -104,7 +103,7 @@ MAPNIK_DECL std::string save_to_string(T const& image, template MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template MAPNIK_DECL void save_to_stream @@ -112,7 +111,7 @@ MAPNIK_DECL void save_to_stream T const& image, std::ostream & stream, std::string const& type, - rgba_palette_ptr const& palette + rgba_palette const& palette ); template @@ -126,7 +125,7 @@ MAPNIK_DECL void save_to_stream template void save_as_png(T const& image, std::string const& filename, - rgba_palette_ptr const& palette); + rgba_palette const& palette); #if defined(HAVE_JPEG) template @@ -225,7 +224,7 @@ MAPNIK_DECL void save_to_file (image_32 const& image, MAPNIK_DECL void save_to_file (image_32 const& image, std::string const& file, std::string const& type, - rgba_palette_ptr const& palette); + rgba_palette const& palette); /////////////////////////////////////////////////////////////////////////// @@ -235,14 +234,14 @@ MAPNIK_DECL std::string save_to_string(image_32 const& image, MAPNIK_DECL std::string save_to_string(image_32 const& image, std::string const& type, - rgba_palette_ptr const& palette); + rgba_palette const& palette); /////////////////////////////////////////////////////////////////////////// MAPNIK_DECL void save_to_stream(image_32 const& image, std::ostream & stream, std::string const& type, - rgba_palette_ptr const& palette); + rgba_palette const& palette); MAPNIK_DECL void save_to_stream(image_32 const& image, std::ostream & stream, @@ -253,7 +252,7 @@ MAPNIK_DECL void save_to_stream(image_32 const& image, extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, - rgba_palette_ptr const&); + rgba_palette const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, @@ -261,7 +260,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, - rgba_palette_ptr const&); + rgba_palette const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&); @@ -270,7 +269,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, std::string const&, - rgba_palette_ptr const&); + rgba_palette const&); extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, @@ -278,7 +277,7 @@ extern template MAPNIK_DECL void save_to_file > (im extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&, - rgba_palette_ptr const&); + rgba_palette const&); extern template MAPNIK_DECL void save_to_file > (image_view const&, std::string const&); @@ -288,21 +287,21 @@ extern template MAPNIK_DECL std::string save_to_string(image_d extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, std::string const&, - rgba_palette_ptr const&); + rgba_palette const&); extern template MAPNIK_DECL std::string save_to_string > (image_view const&, std::string const&); extern template MAPNIK_DECL std::string save_to_string > (image_view const&, std::string const&, - rgba_palette_ptr const&); + rgba_palette const&); #ifdef _MSC_VER template MAPNIK_DECL void save_to_stream( image_data_rgba8 const& image, std::ostream & stream, std::string const& type, - rgba_palette_ptr const& palette + rgba_palette const& palette ); template MAPNIK_DECL void save_to_stream( @@ -315,7 +314,7 @@ template MAPNIK_DECL void save_to_stream > ( image_view const& image, std::ostream & stream, std::string const& type, - rgba_palette_ptr const& palette + rgba_palette const& palette ); template MAPNIK_DECL void save_to_stream > ( diff --git a/include/mapnik/image_util_jpeg.hpp b/include/mapnik/image_util_jpeg.hpp new file mode 100644 index 000000000..091ce2566 --- /dev/null +++ b/include/mapnik/image_util_jpeg.hpp @@ -0,0 +1,47 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_UTIL_JPEG_HPP +#define MAPNIK_IMAGE_UTIL_JPEG_HPP + +// mapnik +#include + +// stl +#include +#include + +namespace mapnik { + +struct jpeg_saver : public mapnik::util::static_visitor<> +{ + jpeg_saver(std::ostream &, std::string &); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_JPEG_HPP diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp index b3097b24a..a48c02bef 100644 --- a/include/mapnik/image_util_png.hpp +++ b/include/mapnik/image_util_png.hpp @@ -32,15 +32,25 @@ namespace mapnik { -struct png_saver : public mapnik::util::static_visitor<> +struct png_saver_pal : public mapnik::util::static_visitor<> { - png_saver(std::ostream &, std::string &, rgba_palette_ptr const& = nullptr); + png_saver_pal(std::ostream &, std::string &, rgba_palette const&); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; + rgba_palette const& pal_; +}; + +struct png_saver : public mapnik::util::static_visitor<> +{ + png_saver(std::ostream &, std::string &); template void operator() (T const&) const; private: std::ostream & stream_; std::string const& t_; - rgba_palette_ptr const& pal_; }; } // end ns diff --git a/include/mapnik/image_util_tiff.hpp b/include/mapnik/image_util_tiff.hpp new file mode 100644 index 000000000..6a2861b2a --- /dev/null +++ b/include/mapnik/image_util_tiff.hpp @@ -0,0 +1,47 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_UTIL_TIFF_HPP +#define MAPNIK_IMAGE_UTIL_TIFF_HPP + +// mapnik +#include + +// stl +#include +#include + +namespace mapnik { + +struct tiff_saver : public mapnik::util::static_visitor<> +{ + tiff_saver(std::ostream &, std::string &); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_TIFF_HPP diff --git a/include/mapnik/image_util_webp.hpp b/include/mapnik/image_util_webp.hpp new file mode 100644 index 000000000..8ba687082 --- /dev/null +++ b/include/mapnik/image_util_webp.hpp @@ -0,0 +1,47 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_UTIL_WEBP_HPP +#define MAPNIK_IMAGE_UTIL_WEBP_HPP + +// mapnik +#include + +// stl +#include +#include + +namespace mapnik { + +struct webp_saver : public mapnik::util::static_visitor<> +{ + webp_saver(std::ostream &, std::string &); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_WEBP_HPP diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 0b748d552..74fe7cab8 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -133,6 +133,12 @@ private: unsigned height_; T const& data_; }; -} + +using image_view_rgba8 = image_view; +using image_view_gray8 = image_view; +using image_view_gray16 = image_view; +using image_view_gray32f = image_view; + +} // end ns #endif // MAPNIK_IMAGE_VIEW_HPP diff --git a/include/mapnik/image_view_any.hpp b/include/mapnik/image_view_any.hpp new file mode 100644 index 000000000..822986d13 --- /dev/null +++ b/include/mapnik/image_view_any.hpp @@ -0,0 +1,79 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_VIEW_ANY_HPP +#define MAPNIK_IMAGE_VIEW_ANY_HPP + +#include +#include + +namespace mapnik { + +using image_view_base = util::variant; + +namespace detail { + +struct get_view_width_visitor +{ + template + std::size_t operator()(T const& data) const + { + return data.width(); + } +}; + +struct get_view_height_visitor +{ + template + std::size_t operator()(T const& data) const + { + return data.height(); + } +}; + +} // namespace detail + +struct image_view_any : image_view_base +{ + image_view_any() = default; + + template + image_view_any(T && data) noexcept + : image_view_base(std::move(data)) {} + + std::size_t width() const + { + return util::apply_visitor(detail::get_view_width_visitor(),*this); + } + + std::size_t height() const + { + return util::apply_visitor(detail::get_view_height_visitor(),*this); + } +}; + +} + +#endif // MAPNIK_IMAGE_VIEW_ANY_HPP diff --git a/include/mapnik/palette.hpp b/include/mapnik/palette.hpp index 950a76984..5dc3a4cdf 100644 --- a/include/mapnik/palette.hpp +++ b/include/mapnik/palette.hpp @@ -130,8 +130,6 @@ private: std::vector alpha_pal_; }; -typedef std::shared_ptr rgba_palette_ptr; - } // namespace mapnik #endif // MAPNIK_PALETTE_HPP diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 4efd781ff..14b9edc44 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -657,14 +657,14 @@ void save_as_png8_hex(T1 & file, if (width + height > 3) // at least 3 pixels (hextree implementation requirement) { // structure for color quantization - std::shared_ptr> tree = std::make_shared>(opts.colors); + hextree tree(opts.colors); if (opts.trans_mode >= 0) { - tree->setTransMode(opts.trans_mode); + tree.setTransMode(opts.trans_mode); } if (opts.gamma > 0) { - tree->setGamma(opts.gamma); + tree.setGamma(opts.gamma); } for (unsigned y = 0; y < height; ++y) @@ -673,13 +673,13 @@ void save_as_png8_hex(T1 & file, for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; - tree->insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val))); + tree.insert(mapnik::rgba(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val))); } } //transparency values per palette index std::vector pal; - tree->create_palette(pal); + tree.create_palette(pal); std::vector palette; std::vector alphaTable; for (unsigned i=0; i> >(file, image, tree, palette, alphaTable, opts); + save_as_png8 >(file, image, tree, palette, alphaTable, opts); } else { @@ -698,10 +698,10 @@ void save_as_png8_hex(T1 & file, template void save_as_png8_pal(T1 & file, T2 const& image, - rgba_palette_ptr const& pal, + rgba_palette const& pal, png_options const& opts) { - save_as_png8(file, image, pal, pal->palette(), pal->alphaTable(), opts); + save_as_png8(file, image, pal, pal.palette(), pal.alphaTable(), opts); } } diff --git a/src/image_util.cpp b/src/image_util.cpp index 2d0e68747..b54e75a8a 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -21,21 +21,13 @@ *****************************************************************************/ // mapnik -#if defined(HAVE_TIFF) -#include -#endif - -#if defined(HAVE_JPEG) -#include -#endif - -#if defined(HAVE_WEBP) -#include -#endif - #include +#include #include +#include +#include #include +#include #include #include #include @@ -75,7 +67,7 @@ namespace mapnik template std::string save_to_string(T const& image, std::string const& type, - rgba_palette_ptr const& palette) + rgba_palette const& palette) { std::ostringstream ss(std::ios::out|std::ios::binary); save_to_stream(image, ss, type, palette); @@ -95,7 +87,7 @@ template void save_to_file(T const& image, std::string const& filename, std::string const& type, - rgba_palette_ptr const& palette) + rgba_palette const& palette) { std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) @@ -118,420 +110,11 @@ void save_to_file(T const& image, else throw ImageWriterException("Could not write file to " + filename ); } -#if defined(HAVE_TIFF) -void handle_tiff_options(std::string const& type, - tiff_config & config) -{ - if (type == "tiff") - { - return; - } - if (type.length() > 4) - { - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - for (auto const& t : tokens) - { - if (t == "tiff") - { - continue; - } - else if (boost::algorithm::starts_with(t, "compression=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (val == "deflate") - { - config.compression = COMPRESSION_DEFLATE; - } - else if (val == "adobedeflate") - { - config.compression = COMPRESSION_ADOBE_DEFLATE; - } - else if (val == "lzw") - { - config.compression = COMPRESSION_LZW; - } - else if (val == "none") - { - config.compression = COMPRESSION_NONE; - } - else - { - throw ImageWriterException("invalid tiff compression: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "method=")) - { - std::string val = t.substr(7); - if (!val.empty()) - { - if (val == "scanline") - { - config.method = TIFF_WRITE_SCANLINE; - } - else if (val == "strip" || val == "stripped") - { - config.method = TIFF_WRITE_STRIPPED; - } - else if (val == "tiled") - { - config.method = TIFF_WRITE_TILED; - } - else - { - throw ImageWriterException("invalid tiff method: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "zlevel=")) - { - std::string val = t.substr(7); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.zlevel) || config.zlevel < 0 || config.zlevel > 9) - { - throw ImageWriterException("invalid tiff zlevel: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "tile_height=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.tile_height) || config.tile_height < 0 ) - { - throw ImageWriterException("invalid tiff tile_height: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "tile_width=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.tile_width) || config.tile_width < 0 ) - { - throw ImageWriterException("invalid tiff tile_width: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "rows_per_strip=")) - { - std::string val = t.substr(15); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.rows_per_strip) || config.rows_per_strip < 0 ) - { - throw ImageWriterException("invalid tiff rows_per_strip: '" + val + "'"); - } - } - } - else - { - throw ImageWriterException("unhandled tiff option: " + t); - } - } - } -} -#endif - -#if defined(HAVE_WEBP) -void handle_webp_options(std::string const& type, - WebPConfig & config, - bool & alpha) -{ - if (type == "webp") - { - return; - } - if (type.length() > 4){ - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - for (auto const& t : tokens) - { - if (t == "webp") - { - continue; - } - else if (boost::algorithm::starts_with(t, "quality=")) - { - std::string val = t.substr(8); - if (!val.empty()) - { - double quality = 90; - if (!mapnik::util::string2double(val,quality) || quality < 0.0 || quality > 100.0) - { - throw ImageWriterException("invalid webp quality: '" + val + "'"); - } - config.quality = static_cast(quality); - } - } - else if (boost::algorithm::starts_with(t, "method=")) - { - std::string val = t.substr(7); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.method) || config.method < 0 || config.method > 6) - { - throw ImageWriterException("invalid webp method: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "lossless=")) - { - std::string val = t.substr(9); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - if (!mapnik::util::string2int(val,config.lossless) || config.lossless < 0 || config.lossless > 1) - { - throw ImageWriterException("invalid webp lossless: '" + val + "'"); - } - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the lossless flag) - #else - #warning "compiling against webp that does not support the lossless flag" - #endif - throw ImageWriterException("your webp version does not support the lossless option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "image_hint=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - int image_hint = 0; - if (!mapnik::util::string2int(val,image_hint) || image_hint < 0 || image_hint > 3) - { - throw ImageWriterException("invalid webp image_hint: '" + val + "'"); - } - config.image_hint = static_cast(image_hint); - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the image_hint flag) - #else - #warning "compiling against webp that does not support the image_hint flag" - #endif - throw ImageWriterException("your webp version does not support the image_hint option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "alpha=")) - { - std::string val = t.substr(6); - if (!val.empty()) - { - if (!mapnik::util::string2bool(val,alpha)) - { - throw ImageWriterException("invalid webp alpha: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "target_size=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.target_size)) - { - throw ImageWriterException("invalid webp target_size: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "target_psnr=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - double psnr = 0; - if (!mapnik::util::string2double(val,psnr)) - { - throw ImageWriterException("invalid webp target_psnr: '" + val + "'"); - } - config.target_PSNR = psnr; - } - } - else if (boost::algorithm::starts_with(t, "segments=")) - { - std::string val = t.substr(9); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.segments)) - { - throw ImageWriterException("invalid webp segments: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "sns_strength=")) - { - std::string val = t.substr(13); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.sns_strength)) - { - throw ImageWriterException("invalid webp sns_strength: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "filter_strength=")) - { - std::string val = t.substr(16); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.filter_strength)) - { - throw ImageWriterException("invalid webp filter_strength: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "filter_sharpness=")) - { - std::string val = t.substr(17); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.filter_sharpness)) - { - throw ImageWriterException("invalid webp filter_sharpness: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "filter_type=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.filter_type)) - { - throw ImageWriterException("invalid webp filter_type: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "autofilter=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.autofilter)) - { - throw ImageWriterException("invalid webp autofilter: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "alpha_compression=")) - { - std::string val = t.substr(18); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.alpha_compression)) - { - throw ImageWriterException("invalid webp alpha_compression: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "alpha_filtering=")) - { - std::string val = t.substr(16); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - if (!mapnik::util::string2int(val,config.alpha_filtering)) - { - throw ImageWriterException("invalid webp alpha_filtering: '" + val + "'"); - } - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the alpha_filtering flag) - #else - #warning "compiling against webp that does not support the alpha_filtering flag" - #endif - throw ImageWriterException("your webp version does not support the alpha_filtering option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "alpha_quality=")) - { - std::string val = t.substr(14); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - if (!mapnik::util::string2int(val,config.alpha_quality)) - { - throw ImageWriterException("invalid webp alpha_quality: '" + val + "'"); - } - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the alpha_quality flag) - #else - #warning "compiling against webp that does not support the alpha_quality flag" - #endif - throw ImageWriterException("your webp version does not support the alpha_quality option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "pass=")) - { - std::string val = t.substr(5); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.pass)) - { - throw ImageWriterException("invalid webp pass: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "preprocessing=")) - { - std::string val = t.substr(14); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.preprocessing)) - { - throw ImageWriterException("invalid webp preprocessing: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "partitions=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.partitions)) - { - throw ImageWriterException("invalid webp partitions: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "partition_limit=")) - { - std::string val = t.substr(16); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.partition_limit)) - { - throw ImageWriterException("invalid webp partition_limit: '" + val + "'"); - } - } - } - else - { - throw ImageWriterException("unhandled webp option: " + t); - } - } - } -} -#endif - -void save_to_stream(image_data_any const& image, +template <> +void save_to_stream(image_data_any const& image, std::ostream & stream, std::string const& type, - rgba_palette_ptr const& palette) + rgba_palette const& palette) { if (stream && image.width() > 0 && image.height() > 0) { @@ -539,7 +122,7 @@ void save_to_stream(image_data_any const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { - mapnik::util::apply_visitor(png_saver(stream, t, palette), image); + mapnik::util::apply_visitor(png_saver_pal(stream, t, palette), image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -564,51 +147,19 @@ void save_to_stream(image_data_any const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { - mapnik::util::apply_visitor(png_saver(stream, t), image); + util::apply_visitor(png_saver(stream, t), image); } else if (boost::algorithm::starts_with(t, "tif")) { -#if defined(HAVE_TIFF) - tiff_config config; - handle_tiff_options(t, config); - save_as_tiff(stream, image, config); -#else - throw ImageWriterException("tiff output is not enabled in your build of Mapnik"); -#endif + util::apply_visitor(tiff_saver(stream, t), image); } else if (boost::algorithm::starts_with(t, "jpeg")) { -#if defined(HAVE_JPEG) - int quality = 85; - std::string val = t.substr(4); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100) - { - throw ImageWriterException("invalid jpeg quality: '" + val + "'"); - } - } - save_as_jpeg(stream, quality, image); -#else - throw ImageWriterException("jpeg output is not enabled in your build of Mapnik"); -#endif + util::apply_visitor(jpeg_saver(stream, t), image); } else if (boost::algorithm::starts_with(t, "webp")) { -#if defined(HAVE_WEBP) - WebPConfig config; - // Default values set here will be lossless=0 and quality=75 (as least as of webp v0.3.1) - if (!WebPConfigInit(&config)) - { - throw std::runtime_error("version mismatch"); - } - // see for more details: https://github.com/mapnik/mapnik/wiki/Image-IO#webp-output-options - bool alpha = true; - handle_webp_options(t,config,alpha); - save_as_webp(stream,image,config,alpha); -#else - throw ImageWriterException("webp output is not enabled in your build of Mapnik"); -#endif + util::apply_visitor(webp_saver(stream, t), image); } else throw ImageWriterException("unknown file type: " + type); } @@ -627,7 +178,7 @@ void save_to_file(T const& image, std::string const& filename) } template -void save_to_file(T const& image, std::string const& filename, rgba_palette_ptr const& palette) +void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) { boost::optional type = type_from_filename(filename); if (type) @@ -726,21 +277,21 @@ template void save_to_file(image_data_rgba8 const&, template void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template void save_to_file(image_data_rgba8 const&, std::string const&); template void save_to_file(image_data_rgba8 const&, std::string const&, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template std::string save_to_string(image_data_rgba8 const&, std::string const&); template std::string save_to_string(image_data_rgba8 const&, std::string const&, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template void save_to_file > (image_view const&, std::string const&, @@ -749,21 +300,21 @@ template void save_to_file > (image_view > (image_view const&, std::string const&, std::string const&, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template void save_to_file > (image_view const&, std::string const&); template void save_to_file > (image_view const&, std::string const&, - rgba_palette_ptr const& palette); + rgba_palette const& palette); template std::string save_to_string > (image_view const&, std::string const&); template std::string save_to_string > (image_view const&, std::string const&, - rgba_palette_ptr const& palette); + rgba_palette const& palette); void save_to_file(image_32 const& image,std::string const& file) { @@ -780,7 +331,7 @@ void save_to_file (image_32 const& image, void save_to_file (image_32 const& image, std::string const& file, std::string const& type, - rgba_palette_ptr const& palette) + rgba_palette const& palette) { save_to_file(image.data(), file, type, palette); } @@ -793,7 +344,7 @@ std::string save_to_string(image_32 const& image, std::string save_to_string(image_32 const& image, std::string const& type, - rgba_palette_ptr const& palette) + rgba_palette const& palette) { return save_to_string(image.data(), type, palette); } diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp new file mode 100644 index 000000000..74a3c5aa5 --- /dev/null +++ b/src/image_util_jpeg.cpp @@ -0,0 +1,77 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#if defined(HAVE_JPEG) +#include +#endif + +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +void jpeg_saver::operator() (image_data_null const& image) const +{ + throw ImageWriterException("null images not supported"); +} + +template +void jpeg_saver::operator() (T const& image) const +{ +#if defined(HAVE_JPEG) + int quality = 85; + std::string val = t.substr(4); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100) + { + throw ImageWriterException("invalid jpeg quality: '" + val + "'"); + } + } + save_as_jpeg(stream, quality, image); +#else + throw ImageWriterException("jpeg output is not enabled in your build of Mapnik"); +#endif +} + +template void jpeg_saver::operator() (image_data_rgba8 const& image) const; +template void jpeg_saver::operator() (image_data_gray8 const& image) const; +template void jpeg_saver::operator() (image_data_gray16 const& image) const; +template void jpeg_saver::operator() (image_data_gray32f const& image) const; +template void jpeg_saver::operator()> (image_view const& image) const; +template void jpeg_saver::operator()> (image_view const& image) const; +template void jpeg_saver::operator()> (image_view const& image) const; +template void jpeg_saver::operator()> (image_view const& image) const; + +} // end ns diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index b639b98d2..cd3527e8a 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -173,7 +173,10 @@ void handle_png_options(std::string const& type, } #endif -png_saver::png_saver(std::ostream & stream, std::string const& t, rgba_palette_ptr const& pal): +png_saver::png_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +png_saver_pal::png_saver_pal(std::ostream & stream, std::string const& t, rgba_palette const& pal): stream_(stream), t_(t), pal_(pal) {} void png_saver::operator() (image_data_null const& image) const @@ -181,7 +184,8 @@ void png_saver::operator() (image_data_null const& image) const throw ImageWriterException("null images not supported"); } -void png_saver::operator() (image_data_rgba8 const& image) const +template +void process_rgb8_png_pal(T const& image) { #if defined(HAVE_PNG) png_options opts; @@ -212,38 +216,54 @@ void png_saver::operator() (image_data_rgba8 const& image) const #endif } +template +void process_rgb8_png(T const& image) +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(t_, opts); + if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(stream_, image, opts); + } + else + { + save_as_png8_oct(stream_, image, opts); + } + } + else + { + save_as_png(stream_, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +void png_saver_pal::operator() (image_data_rgba8 const& image) const +{ + process_rgb8_png(image); +} + +void png_saver_pal::operator() (image_view const& image) const +{ + process_rgb8_png(image); +} + +void png_saver::operator() (image_data_rgba8 const& image) const +{ + process_rgb8_png(image); +} + void png_saver::operator() (image_view const& image) const { -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - if (pal_ && pal_->valid()) - { - png_options opts; - handle_png_options(t,opts); - save_as_png8_pal(stream, image, pal_, opts); - } - else if (opts.paletted) - { - if (opts.use_hextree) - { - save_as_png8_hex(stream_, image, opts); - } - else - { - save_as_png8_oct(stream_, image, opts); - } - } - else - { - save_as_png(stream_, image, opts); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + process_rgb8_png(image); } -void png_saver::operator() (image_data_gray8 const& image) const +template +void png_saver::operator() (T const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -254,7 +274,15 @@ void png_saver::operator() (image_data_gray8 const& image) const #endif } -void png_saver::operator() (image_view const& image) const +template void png_saver::operator() (image_data_gray8 const& image) const; +template void png_saver::operator() (image_data_gray16 const& image) const; +template void png_saver::operator() (image_data_gray32f const& image) const; +template void png_saver::operator()> (image_view const& image) const; +template void png_saver::operator()> (image_view const& image) const; +template void png_saver::operator()> (image_view const& image) const; + +template +void png_saver_pal::operator() (T const& image) const { #if defined(HAVE_PNG) png_options opts; @@ -265,47 +293,11 @@ void png_saver::operator() (image_view const& image) const #endif } -void png_saver::operator() (image_data_gray16 const& image) const -{ -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - save_as_png(stream_, image, opts); -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif -} - -void png_saver::operator() (image_view const& image) const -{ -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - save_as_png(stream_, image, opts); -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif -} - -void png_saver::operator() (mapnik::image_data_gray32f const& image) const -{ -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - save_as_png(stream_, image, opts); -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif -} -void png_saver::operator() (mapnik::image_data_gray32f const& image) const -{ -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - save_as_png(stream_, image, opts); -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif -} +template void png_saver_pal::operator() (image_data_gray8 const& image) const; +template void png_saver_pal::operator() (image_data_gray16 const& image) const; +template void png_saver_pal::operator() (image_data_gray32f const& image) const; +template void png_saver_pal::operator()> (image_view const& image) const; +template void png_saver_pal::operator()> (image_view const& image) const; +template void png_saver_pal::operator()> (image_view const& image) const; } // end ns diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp new file mode 100644 index 000000000..92bd01a2b --- /dev/null +++ b/src/image_util_tiff.cpp @@ -0,0 +1,191 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#if defined(HAVE_TIFF) +#include +#endif + +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +#if defined(HAVE_TIFF) +void handle_tiff_options(std::string const& type, + tiff_config & config) +{ + if (type == "tiff") + { + return; + } + if (type.length() > 4) + { + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + for (auto const& t : tokens) + { + if (t == "tiff") + { + continue; + } + else if (boost::algorithm::starts_with(t, "compression=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (val == "deflate") + { + config.compression = COMPRESSION_DEFLATE; + } + else if (val == "adobedeflate") + { + config.compression = COMPRESSION_ADOBE_DEFLATE; + } + else if (val == "lzw") + { + config.compression = COMPRESSION_LZW; + } + else if (val == "none") + { + config.compression = COMPRESSION_NONE; + } + else + { + throw ImageWriterException("invalid tiff compression: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "method=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (val == "scanline") + { + config.method = TIFF_WRITE_SCANLINE; + } + else if (val == "strip" || val == "stripped") + { + config.method = TIFF_WRITE_STRIPPED; + } + else if (val == "tiled") + { + config.method = TIFF_WRITE_TILED; + } + else + { + throw ImageWriterException("invalid tiff method: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "zlevel=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.zlevel) || config.zlevel < 0 || config.zlevel > 9) + { + throw ImageWriterException("invalid tiff zlevel: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "tile_height=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.tile_height) || config.tile_height < 0 ) + { + throw ImageWriterException("invalid tiff tile_height: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "tile_width=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.tile_width) || config.tile_width < 0 ) + { + throw ImageWriterException("invalid tiff tile_width: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "rows_per_strip=")) + { + std::string val = t.substr(15); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.rows_per_strip) || config.rows_per_strip < 0 ) + { + throw ImageWriterException("invalid tiff rows_per_strip: '" + val + "'"); + } + } + } + else + { + throw ImageWriterException("unhandled tiff option: " + t); + } + } + } +} +#endif + +tiff_saver::tiff_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +void tiff_saver::operator() (image_data_null const& image) const +{ + throw ImageWriterException("null images not supported"); +} + +template +void tiff_saver::operator() (T const& image) const +{ +#if defined(HAVE_TIFF) + tiff_config opts; + handle_tiff_options(t_, opts); + save_as_tiff(stream_, image, opts); +#else + throw ImageWriterException("tiff output is not enabled in your build of Mapnik"); +#endif +} + +template void tiff_saver::operator() (image_data_rgba8 const& image) const; +template void tiff_saver::operator() (image_data_gray8 const& image) const; +template void tiff_saver::operator() (image_data_gray16 const& image) const; +template void tiff_saver::operator() (image_data_gray32f const& image) const; +template void tiff_saver::operator()> (image_view const& image) const; +template void tiff_saver::operator()> (image_view const& image) const; +template void tiff_saver::operator()> (image_view const& image) const; +template void tiff_saver::operator()> (image_view const& image) const; + +} // end ns diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp new file mode 100644 index 000000000..a98168cbf --- /dev/null +++ b/src/image_util_webp.cpp @@ -0,0 +1,366 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#if defined(HAVE_WEBP) +#include +#endif + +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +#if defined(HAVE_WEBP) +void handle_webp_options(std::string const& type, + WebPConfig & config, + bool & alpha) +{ + if (type == "webp") + { + return; + } + if (type.length() > 4){ + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + for (auto const& t : tokens) + { + if (t == "webp") + { + continue; + } + else if (boost::algorithm::starts_with(t, "quality=")) + { + std::string val = t.substr(8); + if (!val.empty()) + { + double quality = 90; + if (!mapnik::util::string2double(val,quality) || quality < 0.0 || quality > 100.0) + { + throw ImageWriterException("invalid webp quality: '" + val + "'"); + } + config.quality = static_cast(quality); + } + } + else if (boost::algorithm::starts_with(t, "method=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.method) || config.method < 0 || config.method > 6) + { + throw ImageWriterException("invalid webp method: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "lossless=")) + { + std::string val = t.substr(9); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + if (!mapnik::util::string2int(val,config.lossless) || config.lossless < 0 || config.lossless > 1) + { + throw ImageWriterException("invalid webp lossless: '" + val + "'"); + } + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the lossless flag) + #else + #warning "compiling against webp that does not support the lossless flag" + #endif + throw ImageWriterException("your webp version does not support the lossless option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "image_hint=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + int image_hint = 0; + if (!mapnik::util::string2int(val,image_hint) || image_hint < 0 || image_hint > 3) + { + throw ImageWriterException("invalid webp image_hint: '" + val + "'"); + } + config.image_hint = static_cast(image_hint); + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the image_hint flag) + #else + #warning "compiling against webp that does not support the image_hint flag" + #endif + throw ImageWriterException("your webp version does not support the image_hint option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "alpha=")) + { + std::string val = t.substr(6); + if (!val.empty()) + { + if (!mapnik::util::string2bool(val,alpha)) + { + throw ImageWriterException("invalid webp alpha: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "target_size=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.target_size)) + { + throw ImageWriterException("invalid webp target_size: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "target_psnr=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + double psnr = 0; + if (!mapnik::util::string2double(val,psnr)) + { + throw ImageWriterException("invalid webp target_psnr: '" + val + "'"); + } + config.target_PSNR = psnr; + } + } + else if (boost::algorithm::starts_with(t, "segments=")) + { + std::string val = t.substr(9); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.segments)) + { + throw ImageWriterException("invalid webp segments: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "sns_strength=")) + { + std::string val = t.substr(13); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.sns_strength)) + { + throw ImageWriterException("invalid webp sns_strength: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "filter_strength=")) + { + std::string val = t.substr(16); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.filter_strength)) + { + throw ImageWriterException("invalid webp filter_strength: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "filter_sharpness=")) + { + std::string val = t.substr(17); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.filter_sharpness)) + { + throw ImageWriterException("invalid webp filter_sharpness: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "filter_type=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.filter_type)) + { + throw ImageWriterException("invalid webp filter_type: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "autofilter=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.autofilter)) + { + throw ImageWriterException("invalid webp autofilter: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "alpha_compression=")) + { + std::string val = t.substr(18); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.alpha_compression)) + { + throw ImageWriterException("invalid webp alpha_compression: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "alpha_filtering=")) + { + std::string val = t.substr(16); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + if (!mapnik::util::string2int(val,config.alpha_filtering)) + { + throw ImageWriterException("invalid webp alpha_filtering: '" + val + "'"); + } + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the alpha_filtering flag) + #else + #warning "compiling against webp that does not support the alpha_filtering flag" + #endif + throw ImageWriterException("your webp version does not support the alpha_filtering option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "alpha_quality=")) + { + std::string val = t.substr(14); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + if (!mapnik::util::string2int(val,config.alpha_quality)) + { + throw ImageWriterException("invalid webp alpha_quality: '" + val + "'"); + } + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the alpha_quality flag) + #else + #warning "compiling against webp that does not support the alpha_quality flag" + #endif + throw ImageWriterException("your webp version does not support the alpha_quality option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "pass=")) + { + std::string val = t.substr(5); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.pass)) + { + throw ImageWriterException("invalid webp pass: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "preprocessing=")) + { + std::string val = t.substr(14); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.preprocessing)) + { + throw ImageWriterException("invalid webp preprocessing: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "partitions=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.partitions)) + { + throw ImageWriterException("invalid webp partitions: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "partition_limit=")) + { + std::string val = t.substr(16); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.partition_limit)) + { + throw ImageWriterException("invalid webp partition_limit: '" + val + "'"); + } + } + } + else + { + throw ImageWriterException("unhandled webp option: " + t); + } + } + } +} +#endif + +webp_saver::webp_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +void webp_saver::operator() (image_data_null const& image) const +{ + throw ImageWriterException("null images not supported"); +} + +template +void webp_saver::operator() (T const& image) const +{ +#if defined(HAVE_WEBP) + WebPConfig config; + // Default values set here will be lossless=0 and quality=75 (as least as of webp v0.3.1) + if (!WebPConfigInit(&config)) + { + throw std::runtime_error("version mismatch"); + } + // see for more details: https://github.com/mapnik/mapnik/wiki/Image-IO#webp-output-options + bool alpha = true; + handle_webp_options(t,config,alpha); + save_as_webp(stream,image,config,alpha); +#else + throw ImageWriterException("webp output is not enabled in your build of Mapnik"); +#endif +} + +template void webp_saver::operator() (image_data_rgba8 const& image) const; +template void webp_saver::operator() (image_data_gray8 const& image) const; +template void webp_saver::operator() (image_data_gray16 const& image) const; +template void webp_saver::operator() (image_data_gray32f const& image) const; +template void webp_saver::operator()> (image_view const& image) const; +template void webp_saver::operator()> (image_view const& image) const; +template void webp_saver::operator()> (image_view const& image) const; +template void webp_saver::operator()> (image_view const& image) const; + +} // end ns From 094d0ec3e148d5e632666b2ea194e6fad60df493 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 8 Jan 2015 19:31:14 -0500 Subject: [PATCH 14/91] Another large set of modifications, finally allow this branch to build. Mostly modifications to the image_util_* files. Different processing based on the image type is now possible, and save_to_stream now could possibly accept grayscale with out breaking existing code. --- include/mapnik/image_util.hpp | 20 +++--- include/mapnik/image_util_jpeg.hpp | 7 +- include/mapnik/image_util_png.hpp | 11 ++- include/mapnik/image_util_tiff.hpp | 7 +- include/mapnik/image_util_webp.hpp | 7 +- include/mapnik/png_io.hpp | 4 +- src/build.py | 4 ++ src/image_util.cpp | 27 +++++--- src/image_util_jpeg.cpp | 43 ++++++++---- src/image_util_png.cpp | 103 +++++++++++++++++------------ src/image_util_tiff.cpp | 24 ++++--- src/image_util_webp.cpp | 27 +++++++- 12 files changed, 175 insertions(+), 109 deletions(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index f6bb1ca21..a02826f6a 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -266,20 +266,20 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 std::string const&); -extern template MAPNIK_DECL void save_to_file > (image_view const&, +extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, std::string const&, std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file > (image_view const&, +extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, std::string const&, std::string const&); -extern template MAPNIK_DECL void save_to_file > (image_view const&, +extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file > (image_view const&, +extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, std::string const&); extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, @@ -289,10 +289,10 @@ extern template MAPNIK_DECL std::string save_to_string(image_d std::string const&, rgba_palette const&); -extern template MAPNIK_DECL std::string save_to_string > (image_view const&, +extern template MAPNIK_DECL std::string save_to_string (image_view_rgba8 const&, std::string const&); -extern template MAPNIK_DECL std::string save_to_string > (image_view const&, +extern template MAPNIK_DECL std::string save_to_string (image_view_rgba8 const&, std::string const&, rgba_palette const&); #ifdef _MSC_VER @@ -310,15 +310,15 @@ template MAPNIK_DECL void save_to_stream( std::string const& type ); -template MAPNIK_DECL void save_to_stream > ( - image_view const& image, +template MAPNIK_DECL void save_to_stream ( + image_view_rgba8 const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette ); -template MAPNIK_DECL void save_to_stream > ( - image_view const& image, +template MAPNIK_DECL void save_to_stream ( + image_view_rgba8 const& image, std::ostream & stream, std::string const& type ); diff --git a/include/mapnik/image_util_jpeg.hpp b/include/mapnik/image_util_jpeg.hpp index 091ce2566..5f77f56f0 100644 --- a/include/mapnik/image_util_jpeg.hpp +++ b/include/mapnik/image_util_jpeg.hpp @@ -23,18 +23,15 @@ #ifndef MAPNIK_IMAGE_UTIL_JPEG_HPP #define MAPNIK_IMAGE_UTIL_JPEG_HPP -// mapnik -#include - // stl #include #include namespace mapnik { -struct jpeg_saver : public mapnik::util::static_visitor<> +struct jpeg_saver { - jpeg_saver(std::ostream &, std::string &); + jpeg_saver(std::ostream &, std::string const&); template void operator() (T const&) const; private: diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp index a48c02bef..06dcde894 100644 --- a/include/mapnik/image_util_png.hpp +++ b/include/mapnik/image_util_png.hpp @@ -23,18 +23,15 @@ #ifndef MAPNIK_IMAGE_UTIL_PNG_HPP #define MAPNIK_IMAGE_UTIL_PNG_HPP -// mapnik -#include - // stl #include #include namespace mapnik { -struct png_saver_pal : public mapnik::util::static_visitor<> +struct png_saver_pal { - png_saver_pal(std::ostream &, std::string &, rgba_palette const&); + png_saver_pal(std::ostream &, std::string const&, rgba_palette const&); template void operator() (T const&) const; private: @@ -43,9 +40,9 @@ struct png_saver_pal : public mapnik::util::static_visitor<> rgba_palette const& pal_; }; -struct png_saver : public mapnik::util::static_visitor<> +struct png_saver { - png_saver(std::ostream &, std::string &); + png_saver(std::ostream &, std::string const&); template void operator() (T const&) const; private: diff --git a/include/mapnik/image_util_tiff.hpp b/include/mapnik/image_util_tiff.hpp index 6a2861b2a..5cacc6781 100644 --- a/include/mapnik/image_util_tiff.hpp +++ b/include/mapnik/image_util_tiff.hpp @@ -23,18 +23,15 @@ #ifndef MAPNIK_IMAGE_UTIL_TIFF_HPP #define MAPNIK_IMAGE_UTIL_TIFF_HPP -// mapnik -#include - // stl #include #include namespace mapnik { -struct tiff_saver : public mapnik::util::static_visitor<> +struct tiff_saver { - tiff_saver(std::ostream &, std::string &); + tiff_saver(std::ostream &, std::string const&); template void operator() (T const&) const; private: diff --git a/include/mapnik/image_util_webp.hpp b/include/mapnik/image_util_webp.hpp index 8ba687082..14a218309 100644 --- a/include/mapnik/image_util_webp.hpp +++ b/include/mapnik/image_util_webp.hpp @@ -23,18 +23,15 @@ #ifndef MAPNIK_IMAGE_UTIL_WEBP_HPP #define MAPNIK_IMAGE_UTIL_WEBP_HPP -// mapnik -#include - // stl #include #include namespace mapnik { -struct webp_saver : public mapnik::util::static_visitor<> +struct webp_saver { - webp_saver(std::ostream &, std::string &); + webp_saver(std::ostream &, std::string const&); template void operator() (T const&) const; private: diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 14b9edc44..7034ca293 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -607,7 +607,7 @@ void save_as_png8(T1 & file, mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); for (unsigned x = 0; x < width; ++x) { - row_out[x] = tree->quantize(row[x]); + row_out[x] = tree.quantize(row[x]); } } save_as_png(file, palette, reduced_image, width, height, 8, alphaTable, opts); @@ -635,7 +635,7 @@ void save_as_png8(T1 & file, for (unsigned x = 0; x < width; ++x) { - index = tree->quantize(row[x]); + index = tree.quantize(row[x]); if (x%2 == 0) { index = index<<4; diff --git a/src/build.py b/src/build.py index 0f32bce0b..044659f94 100644 --- a/src/build.py +++ b/src/build.py @@ -174,6 +174,10 @@ source = Split( parse_path.cpp image_reader.cpp image_util.cpp + image_util_jpeg.cpp + image_util_png.cpp + image_util_tiff.cpp + image_util_webp.cpp layer.cpp map.cpp load_map.cpp diff --git a/src/image_util.cpp b/src/image_util.cpp index b54e75a8a..22a431b7d 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -110,8 +110,8 @@ void save_to_file(T const& image, else throw ImageWriterException("Could not write file to " + filename ); } -template <> -void save_to_stream(image_data_any const& image, +template +void save_to_stream(T const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) @@ -122,7 +122,9 @@ void save_to_stream(image_data_any const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { - mapnik::util::apply_visitor(png_saver_pal(stream, t, palette), image); + png_saver_pal visitor(stream, t, palette); + visitor(image); + //mapnik::util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -137,7 +139,8 @@ void save_to_stream(image_data_any const& image, else throw ImageWriterException("Could not write to empty stream" ); } -void save_to_stream(image_data_any const& image, +template +void save_to_stream(T const& image, std::ostream & stream, std::string const& type) { @@ -147,19 +150,27 @@ void save_to_stream(image_data_any const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { - util::apply_visitor(png_saver(stream, t), image); + png_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "tif")) { - util::apply_visitor(tiff_saver(stream, t), image); + tiff_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "jpeg")) { - util::apply_visitor(jpeg_saver(stream, t), image); + jpeg_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "webp")) { - util::apply_visitor(webp_saver(stream, t), image); + webp_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); } else throw ImageWriterException("unknown file type: " + type); } diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index 74a3c5aa5..d44c13974 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -25,8 +25,12 @@ #include #endif +#include #include #include +#include +#include +#include // boost #include @@ -41,13 +45,8 @@ namespace mapnik jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t): stream_(stream), t_(t) {} -void jpeg_saver::operator() (image_data_null const& image) const -{ - throw ImageWriterException("null images not supported"); -} - template -void jpeg_saver::operator() (T const& image) const +void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & stream) { #if defined(HAVE_JPEG) int quality = 85; @@ -65,13 +64,29 @@ void jpeg_saver::operator() (T const& image) const #endif } -template void jpeg_saver::operator() (image_data_rgba8 const& image) const; -template void jpeg_saver::operator() (image_data_gray8 const& image) const; -template void jpeg_saver::operator() (image_data_gray16 const& image) const; -template void jpeg_saver::operator() (image_data_gray32f const& image) const; -template void jpeg_saver::operator()> (image_view const& image) const; -template void jpeg_saver::operator()> (image_view const& image) const; -template void jpeg_saver::operator()> (image_view const& image) const; -template void jpeg_saver::operator()> (image_view const& image) const; +template<> +void jpeg_saver::operator() (image_data_rgba8 const& image) const +{ + process_rgba8_jpeg(image, t_, stream_); +} + +template<> +void jpeg_saver::operator() (image_view_rgba8 const& image) const +{ + process_rgba8_jpeg(image, t_, stream_); +} + +template +void jpeg_saver::operator() (T const& image) const +{ + throw ImageWriterException("Mapnik does not support jpeg grayscale images"); +} + +template void jpeg_saver::operator() (image_data_gray8 const& image) const; +template void jpeg_saver::operator() (image_data_gray16 const& image) const; +template void jpeg_saver::operator() (image_data_gray32f const& image) const; +template void jpeg_saver::operator() (image_view_gray8 const& image) const; +template void jpeg_saver::operator() (image_view_gray16 const& image) const; +template void jpeg_saver::operator() (image_view_gray32f const& image) const; } // end ns diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index cd3527e8a..b4b102798 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -32,8 +32,12 @@ extern "C" #include #endif +#include #include #include +#include +#include +#include // boost #include @@ -179,37 +183,47 @@ png_saver::png_saver(std::ostream & stream, std::string const& t): png_saver_pal::png_saver_pal(std::ostream & stream, std::string const& t, rgba_palette const& pal): stream_(stream), t_(t), pal_(pal) {} -void png_saver::operator() (image_data_null const& image) const +template<> +void png_saver::operator() (image_data_null const& image) const { - throw ImageWriterException("null images not supported"); + throw ImageWriterException("null images not supported for png"); +} + +template<> +void png_saver_pal::operator() (image_data_null const& image) const +{ + throw ImageWriterException("null images not supported for png"); } template -void process_rgb8_png_pal(T const& image) +void process_rgba8_png_pal(T const& image, + std::string const& t, + std::ostream & stream, + rgba_palette const& pal) { #if defined(HAVE_PNG) png_options opts; - handle_png_options(t_, opts); - if (pal_ && pal_->valid()) + handle_png_options(t, opts); + if (pal.valid()) { png_options opts; handle_png_options(t,opts); - save_as_png8_pal(stream, image, pal_, opts); + save_as_png8_pal(stream, image, pal, opts); } else if (opts.paletted) { if (opts.use_hextree) { - save_as_png8_hex(stream_, image, opts); + save_as_png8_hex(stream, image, opts); } else { - save_as_png8_oct(stream_, image, opts); + save_as_png8_oct(stream, image, opts); } } else { - save_as_png(stream_, image, opts); + save_as_png(stream, image, opts); } #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); @@ -217,87 +231,94 @@ void process_rgb8_png_pal(T const& image) } template -void process_rgb8_png(T const& image) +void process_rgba8_png(T const& image, + std::string const& t, + std::ostream & stream) { #if defined(HAVE_PNG) png_options opts; - handle_png_options(t_, opts); + handle_png_options(t, opts); if (opts.paletted) { if (opts.use_hextree) { - save_as_png8_hex(stream_, image, opts); + save_as_png8_hex(stream, image, opts); } else { - save_as_png8_oct(stream_, image, opts); + save_as_png8_oct(stream, image, opts); } } else { - save_as_png(stream_, image, opts); + save_as_png(stream, image, opts); } #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif } -void png_saver_pal::operator() (image_data_rgba8 const& image) const +template<> +void png_saver_pal::operator() (image_data_rgba8 const& image) const { - process_rgb8_png(image); + process_rgba8_png_pal(image, t_, stream_, pal_); } -void png_saver_pal::operator() (image_view const& image) const +template<> +void png_saver_pal::operator() (image_view_rgba8 const& image) const { - process_rgb8_png(image); + process_rgba8_png_pal(image, t_, stream_, pal_); } -void png_saver::operator() (image_data_rgba8 const& image) const +template<> +void png_saver::operator() (image_data_rgba8 const& image) const { - process_rgb8_png(image); + process_rgba8_png(image, t_, stream_); } -void png_saver::operator() (image_view const& image) const +template<> +void png_saver::operator() (image_view_rgba8 const& image) const { - process_rgb8_png(image); + process_rgba8_png(image, t_, stream_); } template void png_saver::operator() (T const& image) const { #if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - save_as_png(stream_, image, opts); + throw ImageWriterException("Mapnik does not support grayscale images for png"); + //png_options opts; + //handle_png_options(t_, opts); + //save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif } -template void png_saver::operator() (image_data_gray8 const& image) const; -template void png_saver::operator() (image_data_gray16 const& image) const; -template void png_saver::operator() (image_data_gray32f const& image) const; -template void png_saver::operator()> (image_view const& image) const; -template void png_saver::operator()> (image_view const& image) const; -template void png_saver::operator()> (image_view const& image) const; - template void png_saver_pal::operator() (T const& image) const { #if defined(HAVE_PNG) - png_options opts; - handle_png_options(t_, opts); - save_as_png(stream_, image, opts); + throw ImageWriterException("Mapnik does not support grayscale images for png"); + //png_options opts; + //handle_png_options(t_, opts); + //save_as_png(stream_, image, opts); #else throw ImageWriterException("png output is not enabled in your build of Mapnik"); #endif } -template void png_saver_pal::operator() (image_data_gray8 const& image) const; -template void png_saver_pal::operator() (image_data_gray16 const& image) const; -template void png_saver_pal::operator() (image_data_gray32f const& image) const; -template void png_saver_pal::operator()> (image_view const& image) const; -template void png_saver_pal::operator()> (image_view const& image) const; -template void png_saver_pal::operator()> (image_view const& image) const; +template void png_saver::operator() (image_data_gray8 const& image) const; +template void png_saver::operator() (image_data_gray16 const& image) const; +template void png_saver::operator() (image_data_gray32f const& image) const; +template void png_saver::operator() (image_view_gray8 const& image) const; +template void png_saver::operator() (image_view_gray16 const& image) const; +template void png_saver::operator() (image_view_gray32f const& image) const; +template void png_saver_pal::operator() (image_data_gray8 const& image) const; +template void png_saver_pal::operator() (image_data_gray16 const& image) const; +template void png_saver_pal::operator() (image_data_gray32f const& image) const; +template void png_saver_pal::operator() (image_view_gray8 const& image) const; +template void png_saver_pal::operator() (image_view_gray16 const& image) const; +template void png_saver_pal::operator() (image_view_gray32f const& image) const; } // end ns diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index 92bd01a2b..f4a94ffc7 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -25,8 +25,12 @@ #include #endif +#include #include #include +#include +#include +#include // boost #include @@ -161,8 +165,8 @@ void handle_tiff_options(std::string const& type, tiff_saver::tiff_saver(std::ostream & stream, std::string const& t): stream_(stream), t_(t) {} - -void tiff_saver::operator() (image_data_null const& image) const +template<> +void tiff_saver::operator() (image_data_null const& image) const { throw ImageWriterException("null images not supported"); } @@ -179,13 +183,13 @@ void tiff_saver::operator() (T const& image) const #endif } -template void tiff_saver::operator() (image_data_rgba8 const& image) const; -template void tiff_saver::operator() (image_data_gray8 const& image) const; -template void tiff_saver::operator() (image_data_gray16 const& image) const; -template void tiff_saver::operator() (image_data_gray32f const& image) const; -template void tiff_saver::operator()> (image_view const& image) const; -template void tiff_saver::operator()> (image_view const& image) const; -template void tiff_saver::operator()> (image_view const& image) const; -template void tiff_saver::operator()> (image_view const& image) const; +template void tiff_saver::operator() (image_data_rgba8 const& image) const; +template void tiff_saver::operator() (image_data_gray8 const& image) const; +template void tiff_saver::operator() (image_data_gray16 const& image) const; +template void tiff_saver::operator() (image_data_gray32f const& image) const; +template void tiff_saver::operator() (image_view_rgba8 const& image) const; +template void tiff_saver::operator() (image_view_gray8 const& image) const; +template void tiff_saver::operator() (image_view_gray16 const& image) const; +template void tiff_saver::operator() (image_view_gray32f const& image) const; } // end ns diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index a98168cbf..5d6770947 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -25,8 +25,12 @@ #include #endif +#include #include #include +#include +#include +#include // boost #include @@ -330,13 +334,14 @@ void handle_webp_options(std::string const& type, webp_saver::webp_saver(std::ostream & stream, std::string const& t): stream_(stream), t_(t) {} -void webp_saver::operator() (image_data_null const& image) const +template<> +void webp_saver::operator() (image_data_null const& image) const { throw ImageWriterException("null images not supported"); } template -void webp_saver::operator() (T const& image) const +void process_rgba8_webp(T const& image, std::string const& t, std::ostream & stream) { #if defined(HAVE_WEBP) WebPConfig config; @@ -354,6 +359,24 @@ void webp_saver::operator() (T const& image) const #endif } +template <> +void webp_saver::operator() (image_data_rgba8 const& image) const +{ + process_rgba8_webp(image, t_, stream_); +} + +template <> +void webp_saver::operator() (image_view_rgba8 const& image) const +{ + process_rgba8_webp(image, t_, stream_); +} + +template +void webp_saver::operator() (T const& image) const +{ + throw ImageWriterException("Mapnik does not support webp grayscale images"); +} + template void webp_saver::operator() (image_data_rgba8 const& image) const; template void webp_saver::operator() (image_data_gray8 const& image) const; template void webp_saver::operator() (image_data_gray16 const& image) const; From 42ee4ec90de7ced1be9ebb50f92e02882d0dff50 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 9 Jan 2015 16:49:31 -0500 Subject: [PATCH 15/91] Moved cairo out of the image_util.*pp files and now have created a cairo_io.*pp files. Ref #2622 --- bindings/python/mapnik_image_view.cpp | 32 +++---- bindings/python/mapnik_python.cpp | 1 + demo/c++/rundemo.cpp | 1 + include/mapnik/cairo_io.hpp | 49 ++++++++++ include/mapnik/graphics.hpp | 4 +- include/mapnik/image_util.hpp | 12 --- include/mapnik/miniz_png.hpp | 6 +- localize.sh | 4 +- src/build.py | 1 + src/cairo_io.cpp | 131 ++++++++++++++++++++++++++ src/image_util.cpp | 109 ++------------------- src/image_util_webp.cpp | 8 +- src/miniz_png.cpp | 6 +- 13 files changed, 218 insertions(+), 146 deletions(-) create mode 100644 include/mapnik/cairo_io.hpp create mode 100644 src/cairo_io.cpp diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index e08129f7f..8894a96eb 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -39,21 +39,19 @@ #include #include #include -#include #include -using mapnik::image_data_rgba8; -using mapnik::image_view; +using mapnik::image_view_rgba8; using mapnik::save_to_file; // output 'raw' pixels -PyObject* view_tostring1(image_view const& view) +PyObject* view_tostring1(image_view_rgba8 const& view) { std::ostringstream ss(std::ios::out|std::ios::binary); for (unsigned i=0;i(view.getRow(i)), - view.width() * sizeof(image_view::pixel_type)); + view.width() * sizeof(image_view_rgba8::pixel_type)); } return #if PY_VERSION_HEX >= 0x03000000 @@ -65,7 +63,7 @@ PyObject* view_tostring1(image_view const& view) } // encode (png,jpeg) -PyObject* view_tostring2(image_view const & view, std::string const& format) +PyObject* view_tostring2(image_view_rgba8 const & view, std::string const& format) { std::string s = save_to_string(view, format); return @@ -77,7 +75,7 @@ PyObject* view_tostring2(image_view const & view, std::string (s.data(),s.size()); } -PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& format, mapnik::rgba_palette const& pal) { std::string s = save_to_string(view, format, pal); return @@ -89,15 +87,15 @@ PyObject* view_tostring3(image_view const & view, std::string (s.data(),s.size()); } -bool is_solid(image_view const& view) +bool is_solid(image_view_rgba8 const& view) { if (view.width() > 0 && view.height() > 0) { - mapnik::image_view::pixel_type const* first_row = view.getRow(0); - mapnik::image_view::pixel_type const first_pixel = first_row[0]; + mapnik::image_view_rgba8::pixel_type const* first_row = view.getRow(0); + mapnik::image_view_rgba8::pixel_type const first_pixel = first_row[0]; for (unsigned y = 0; y < view.height(); ++y) { - mapnik::image_view::pixel_type const * row = view.getRow(y); + mapnik::image_view_rgba8::pixel_type const * row = view.getRow(y); for (unsigned x = 0; x < view.width(); ++x) { if (first_pixel != row[x]) @@ -110,20 +108,20 @@ bool is_solid(image_view const& view) return true; } -void save_view1(image_view const& view, +void save_view1(image_view_rgba8 const& view, std::string const& filename) { save_to_file(view,filename); } -void save_view2(image_view const& view, +void save_view2(image_view_rgba8 const& view, std::string const& filename, std::string const& type) { save_to_file(view,filename,type); } -void save_view3(image_view const& view, +void save_view3(image_view_rgba8 const& view, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) @@ -135,9 +133,9 @@ void save_view3(image_view const& view, void export_image_view() { using namespace boost::python; - class_ >("ImageView","A view into an image.",no_init) - .def("width",&image_view::width) - .def("height",&image_view::height) + class_("ImageView","A view into an image.",no_init) + .def("width",&image_view_rgba8::width) + .def("height",&image_view_rgba8::height) .def("is_solid",&is_solid) .def("tostring",&view_tostring1) .def("tostring",&view_tostring2) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 73fba74f6..649d20126 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -137,6 +137,7 @@ void clear_cache() } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) +#include #include #include #include diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index bb354fdeb..8f568affb 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #if defined(HAVE_CAIRO) #include diff --git a/include/mapnik/cairo_io.hpp b/include/mapnik/cairo_io.hpp new file mode 100644 index 000000000..c808b9970 --- /dev/null +++ b/include/mapnik/cairo_io.hpp @@ -0,0 +1,49 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_CAIRO_IO_HPP +#define MAPNIK_CAIRO_IO_HPP + +// mapnik +#include +#include + +// stl +#include + +namespace mapnik { + +#if defined(HAVE_CAIRO) +MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + double scale_factor=1.0, + double scale_denominator=0.0); +MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + std::string const& type, + double scale_factor=1.0, + double scale_denominator=0.0); +#endif + +} // end ns + +#endif // MAPNIK_CAIRO_IO_HPP diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 5e84af2a7..c1fe52414 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -119,9 +119,9 @@ public: return data_.getBytes(); } - inline image_view get_view(unsigned x,unsigned y, unsigned w,unsigned h) + inline image_view_rgba8 get_view(unsigned x,unsigned y, unsigned w,unsigned h) { - return image_view(x,y,w,h,data_); + return image_view_rgba8(x,y,w,h,data_); } private: diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index b84326f6a..8501d578d 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -62,18 +62,6 @@ public: } }; -#if defined(HAVE_CAIRO) -MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, - std::string const& filename, - double scale_factor=1.0, - double scale_denominator=0.0); -MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, - std::string const& filename, - std::string const& type, - double scale_factor=1.0, - double scale_denominator=0.0); -#endif - template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, diff --git a/include/mapnik/miniz_png.hpp b/include/mapnik/miniz_png.hpp index bc9221f36..5c6fed248 100644 --- a/include/mapnik/miniz_png.hpp +++ b/include/mapnik/miniz_png.hpp @@ -84,11 +84,11 @@ private: }; extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_gray8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT >(image_view const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_gray8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT >(image_view const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_rgba8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_data_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha >(image_view const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); }} diff --git a/localize.sh b/localize.sh index 4f227e73c..1e79ded61 100755 --- a/localize.sh +++ b/localize.sh @@ -6,8 +6,8 @@ if [ ${UNAME} = 'Darwin' ]; then else export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH} fi -export PYTHONPATH="${CURRENT_DIR}/bindings/python/":$PYTHONPATH +export PYTHONPATH="${CURRENT_DIR}/bindings/python/" #:$PYTHONPATH export MAPNIK_FONT_DIRECTORY="${CURRENT_DIR}/fonts/dejavu-fonts-ttf-2.34/ttf/" export MAPNIK_INPUT_PLUGINS_DIRECTORY="${CURRENT_DIR}/plugins/input/" export PATH="${CURRENT_DIR}/utils/mapnik-config":${PATH} -export PATH="${CURRENT_DIR}/utils/nik2img":${PATH} \ No newline at end of file +export PATH="${CURRENT_DIR}/utils/nik2img":${PATH} diff --git a/src/build.py b/src/build.py index 044659f94..737d1b7b5 100644 --- a/src/build.py +++ b/src/build.py @@ -173,6 +173,7 @@ source = Split( graphics.cpp parse_path.cpp image_reader.cpp + cairo_io.cpp image_util.cpp image_util_jpeg.cpp image_util_png.cpp diff --git a/src/cairo_io.cpp b/src/cairo_io.cpp new file mode 100644 index 000000000..0eefa2e89 --- /dev/null +++ b/src/cairo_io.cpp @@ -0,0 +1,131 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + +#ifdef HAVE_CAIRO +#include +#include +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif +#endif + +// stl +#include +#include +#include +#include + +namespace mapnik { + +#if defined(HAVE_CAIRO) +void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, double scale_factor, double scale_denominator) +{ + boost::optional type = type_from_filename(filename); + if (type) + { + save_to_cairo_file(map,filename,*type,scale_factor,scale_denominator); + } + else throw ImageWriterException("Could not write file to " + filename ); +} + +void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + std::string const& type, + double scale_factor, + double scale_denominator) +{ + std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); + if (file) + { + cairo_surface_ptr surface; + unsigned width = map.width(); + unsigned height = map.height(); + if (type == "pdf") + { +#ifdef CAIRO_HAS_PDF_SURFACE + surface = cairo_surface_ptr(cairo_pdf_surface_create(filename.c_str(),width,height),cairo_surface_closer()); +#else + throw ImageWriterException("PDFSurface not supported in the cairo backend"); +#endif + } +#ifdef CAIRO_HAS_SVG_SURFACE + else if (type == "svg") + { + surface = cairo_surface_ptr(cairo_svg_surface_create(filename.c_str(),width,height),cairo_surface_closer()); + } +#endif +#ifdef CAIRO_HAS_PS_SURFACE + else if (type == "ps") + { + surface = cairo_surface_ptr(cairo_ps_surface_create(filename.c_str(),width,height),cairo_surface_closer()); + } +#endif +#ifdef CAIRO_HAS_IMAGE_SURFACE + else if (type == "ARGB32") + { + surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width,height),cairo_surface_closer()); + } + else if (type == "RGB24") + { + surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_RGB24,width,height),cairo_surface_closer()); + } +#endif + else + { + throw ImageWriterException("unknown file type: " + type); + } + + //cairo_t * ctx = cairo_create(surface); + + // TODO - expose as user option + /* + if (type == "ARGB32" || type == "RGB24") + { + context->set_antialias(Cairo::ANTIALIAS_NONE); + } + */ + + mapnik::cairo_renderer ren(map, create_context(surface), scale_factor); + ren.apply(scale_denominator); + + if (type == "ARGB32" || type == "RGB24") + { + cairo_surface_write_to_png(&*surface, filename.c_str()); + } + cairo_surface_finish(&*surface); + } +} + +#endif + +} // end ns diff --git a/src/image_util.cpp b/src/image_util.cpp index c6f532c88..8f6c00e13 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -34,20 +34,6 @@ #include #include -#ifdef HAVE_CAIRO -#include -#include -#ifdef CAIRO_HAS_PDF_SURFACE -#include -#endif -#ifdef CAIRO_HAS_PS_SURFACE -#include -#endif -#ifdef CAIRO_HAS_SVG_SURFACE -#include -#endif -#endif - // boost #include @@ -61,7 +47,6 @@ namespace mapnik { - template std::string save_to_string(T const& image, std::string const& type, @@ -197,88 +182,6 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } -#if defined(HAVE_CAIRO) -// TODO - move to separate cairo_io.hpp -void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, double scale_factor, double scale_denominator) -{ - boost::optional type = type_from_filename(filename); - if (type) - { - save_to_cairo_file(map,filename,*type,scale_factor,scale_denominator); - } - else throw ImageWriterException("Could not write file to " + filename ); -} - -void save_to_cairo_file(mapnik::Map const& map, - std::string const& filename, - std::string const& type, - double scale_factor, - double scale_denominator) -{ - std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); - if (file) - { - cairo_surface_ptr surface; - unsigned width = map.width(); - unsigned height = map.height(); - if (type == "pdf") - { -#ifdef CAIRO_HAS_PDF_SURFACE - surface = cairo_surface_ptr(cairo_pdf_surface_create(filename.c_str(),width,height),cairo_surface_closer()); -#else - throw ImageWriterException("PDFSurface not supported in the cairo backend"); -#endif - } -#ifdef CAIRO_HAS_SVG_SURFACE - else if (type == "svg") - { - surface = cairo_surface_ptr(cairo_svg_surface_create(filename.c_str(),width,height),cairo_surface_closer()); - } -#endif -#ifdef CAIRO_HAS_PS_SURFACE - else if (type == "ps") - { - surface = cairo_surface_ptr(cairo_ps_surface_create(filename.c_str(),width,height),cairo_surface_closer()); - } -#endif -#ifdef CAIRO_HAS_IMAGE_SURFACE - else if (type == "ARGB32") - { - surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width,height),cairo_surface_closer()); - } - else if (type == "RGB24") - { - surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_RGB24,width,height),cairo_surface_closer()); - } -#endif - else - { - throw ImageWriterException("unknown file type: " + type); - } - - //cairo_t * ctx = cairo_create(surface); - - // TODO - expose as user option - /* - if (type == "ARGB32" || type == "RGB24") - { - context->set_antialias(Cairo::ANTIALIAS_NONE); - } - */ - - mapnik::cairo_renderer ren(map, create_context(surface), scale_factor); - ren.apply(scale_denominator); - - if (type == "ARGB32" || type == "RGB24") - { - cairo_surface_write_to_png(&*surface, filename.c_str()); - } - cairo_surface_finish(&*surface); - } -} - -#endif - template void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&); @@ -302,26 +205,26 @@ template std::string save_to_string(image_data_rgba8 const&, std::string const&, rgba_palette const& palette); -template void save_to_file > (image_view const&, +template void save_to_file (image_view_rgba8 const&, std::string const&, std::string const&); -template void save_to_file > (image_view const&, +template void save_to_file (image_view_rgba8 const&, std::string const&, std::string const&, rgba_palette const& palette); -template void save_to_file > (image_view const&, +template void save_to_file (image_view_rgba8 const&, std::string const&); -template void save_to_file > (image_view const&, +template void save_to_file (image_view_rgba8 const&, std::string const&, rgba_palette const& palette); -template std::string save_to_string > (image_view const&, +template std::string save_to_string (image_view_rgba8 const&, std::string const&); -template std::string save_to_string > (image_view const&, +template std::string save_to_string (image_view_rgba8 const&, std::string const&, rgba_palette const& palette); diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index 5d6770947..62c9ca2ed 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -381,9 +381,9 @@ template void webp_saver::operator() (image_data_rgba8 const& template void webp_saver::operator() (image_data_gray8 const& image) const; template void webp_saver::operator() (image_data_gray16 const& image) const; template void webp_saver::operator() (image_data_gray32f const& image) const; -template void webp_saver::operator()> (image_view const& image) const; -template void webp_saver::operator()> (image_view const& image) const; -template void webp_saver::operator()> (image_view const& image) const; -template void webp_saver::operator()> (image_view const& image) const; +template void webp_saver::operator() (image_view_rgba8 const& image) const; +template void webp_saver::operator() (image_view_gray8 const& image) const; +template void webp_saver::operator() (image_view_gray16 const& image) const; +template void webp_saver::operator() (image_view_gray32f const& image) const; } // end ns diff --git a/src/miniz_png.cpp b/src/miniz_png.cpp index d968d1dae..485337992 100644 --- a/src/miniz_png.cpp +++ b/src/miniz_png.cpp @@ -362,10 +362,10 @@ const mz_uint8 PNGWriter::IEND_tpl[] = { }; template void PNGWriter::writeIDAT(image_data_gray8 const& image); -template void PNGWriter::writeIDAT >(image_view const& image); +template void PNGWriter::writeIDAT(image_view_gray8 const& image); template void PNGWriter::writeIDAT(image_data_rgba8 const& image); -template void PNGWriter::writeIDAT >(image_view const& image); +template void PNGWriter::writeIDAT(image_view_rgba8 const& image); template void PNGWriter::writeIDATStripAlpha(image_data_rgba8 const& image); -template void PNGWriter::writeIDATStripAlpha >(image_view const& image); +template void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); }} From d7f758e073f8495343ec5d8e92993e14414fa3c9 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 9 Jan 2015 16:51:04 -0500 Subject: [PATCH 16/91] Undo change to localize --- localize.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localize.sh b/localize.sh index 1e79ded61..1db825b48 100755 --- a/localize.sh +++ b/localize.sh @@ -6,7 +6,7 @@ if [ ${UNAME} = 'Darwin' ]; then else export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH} fi -export PYTHONPATH="${CURRENT_DIR}/bindings/python/" #:$PYTHONPATH +export PYTHONPATH="${CURRENT_DIR}/bindings/python/":$PYTHONPATH export MAPNIK_FONT_DIRECTORY="${CURRENT_DIR}/fonts/dejavu-fonts-ttf-2.34/ttf/" export MAPNIK_INPUT_PLUGINS_DIRECTORY="${CURRENT_DIR}/plugins/input/" export PATH="${CURRENT_DIR}/utils/mapnik-config":${PATH} From 2379c396c32f6b161e3a8fe67ef905a9cb696d4d Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 12 Jan 2015 15:06:39 -0600 Subject: [PATCH 17/91] Removed unrequired save_as_jpeg in image_util.hpp --- include/mapnik/image_util.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 8501d578d..2bee70bdb 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -114,13 +114,6 @@ void save_as_png(T const& image, std::string const& filename, rgba_palette const& palette); -#if defined(HAVE_JPEG) -template -void save_as_jpeg(std::string const& filename, - int quality, - T const& image); -#endif - inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); From 4b25c755a7106490cd3a5c0bc84f5be328e8a21b Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 13 Jan 2015 11:43:20 -0600 Subject: [PATCH 18/91] Added is_solid to image_utils. It is currently built to support the eventual use of image_view_any and image_data_any, but for a limited time supports the passing of image_view_rgba8 and image_data_rgba8. Ref #2633 --- bindings/python/mapnik_image.cpp | 19 +-------- bindings/python/mapnik_image_view.cpp | 18 +------- include/mapnik/image_util.hpp | 4 +- src/image_util.cpp | 61 +++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index b81b7ae39..6048de0ef 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -121,24 +121,7 @@ bool painted(mapnik::image_32 const& im) bool is_solid(mapnik::image_32 const& im) { - if (im.width() > 0 && im.height() > 0) - { - mapnik::image_data_rgba8 const & data = im.data(); - mapnik::image_data_rgba8::pixel_type const* first_row = data.getRow(0); - mapnik::image_data_rgba8::pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < im.height(); ++y) - { - mapnik::image_data_rgba8::pixel_type const * row = data.getRow(y); - for (unsigned x = 0; x < im.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; + return mapnik::is_solid(im.data()); } unsigned get_pixel(mapnik::image_32 const& im, int x, int y) diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index 8894a96eb..82ca74c8e 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -89,23 +89,7 @@ PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& forma bool is_solid(image_view_rgba8 const& view) { - if (view.width() > 0 && view.height() > 0) - { - mapnik::image_view_rgba8::pixel_type const* first_row = view.getRow(0); - mapnik::image_view_rgba8::pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < view.height(); ++y) - { - mapnik::image_view_rgba8::pixel_type const * row = view.getRow(y); - for (unsigned x = 0; x < view.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; + mapnik::is_solid(view); } void save_view1(image_view_rgba8 const& view, diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 2bee70bdb..58d3a0359 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -110,9 +110,7 @@ MAPNIK_DECL void save_to_stream ); template -void save_as_png(T const& image, - std::string const& filename, - rgba_palette const& palette); +MAPNIK_DECL bool is_solid (T const& image); inline bool is_png(std::string const& filename) { diff --git a/src/image_util.cpp b/src/image_util.cpp index 8f6c00e13..ce1eaf7ed 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -182,6 +182,67 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } +namespace detail { + +struct is_solid_visitor +{ + template + bool operator() (T const & data) + { + using pixel_type = typename T::pixel_type; + if (data.width() > 0 && data.height() > 0) + { + pixel_type const* first_row = data.getRow(0); + pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type const * row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; + } +}; + +template bool is_solid_visitor::operator() (image_data_rgba8 const& data); +template bool is_solid_visitor::operator() (image_data_gray8 const& data); +template bool is_solid_visitor::operator() (image_data_gray16 const& data); +template bool is_solid_visitor::operator() (image_data_gray32f const& data); +template bool is_solid_visitor::operator() (image_view_rgba8 const& data); +template bool is_solid_visitor::operator() (image_view_gray8 const& data); +template bool is_solid_visitor::operator() (image_view_gray16 const& data); +template bool is_solid_visitor::operator() (image_view_gray32f const& data); + +} // end detail ns + +template +bool is_solid(T const& image) +{ + return util::apply_visitor(detail::is_solid_visitor(), image); +} + +// Temporary until image_data_rgba8 is removed from passing +template <> +bool is_solid(image_data_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + +// Temporary until image_view_rgba8 is removed from passing +template <> +bool is_solid(image_view_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + template void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&); From 4184f75011397f24401f31ba5588bf685ee5472e Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 14 Jan 2015 12:42:30 -0600 Subject: [PATCH 19/91] Moved premultiply and demultiply out of image_32 and other parts of the code. The image_data object is now responsible for keeping track of its own premultiplied_alpha status. Created a new utility method in image_util to preform premultiplication. Added visitor pattern to several different methods as well to prepare for image_data_any including compositing. Ref #2633 --- bindings/python/mapnik_image.cpp | 23 +- include/mapnik/graphics.hpp | 10 - include/mapnik/image_compositing.hpp | 3 +- include/mapnik/image_data.hpp | 24 +- include/mapnik/image_data_any.hpp | 14 + include/mapnik/image_filter.hpp | 4 +- include/mapnik/image_reader.hpp | 1 - include/mapnik/image_util.hpp | 6 + include/mapnik/raster.hpp | 7 +- .../process_raster_symbolizer.hpp | 18 +- .../input/pgraster/pgraster_wkb_reader.cpp | 10 +- plugins/input/raster/raster_featureset.cpp | 1 - src/agg/agg_renderer.cpp | 9 +- src/agg/process_raster_symbolizer.cpp | 2 +- src/graphics.cpp | 22 +- src/image_compositing.cpp | 66 +++- src/image_util.cpp | 302 ++++++++++++++++-- src/image_util_jpeg.cpp | 6 + src/jpeg_reader.cpp | 3 +- src/marker_cache.cpp | 11 +- src/png_reader.cpp | 1 - src/tiff_reader.cpp | 15 +- src/webp_reader.cpp | 1 - tests/cxx/tiff_io.cpp | 38 +-- 24 files changed, 445 insertions(+), 152 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index b81b7ae39..ef6fb4c37 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -211,9 +211,24 @@ void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float op im.set_rectangle_alpha2(im2.data(),x,y,opacity); } +bool premultiplied(image_32 &im) +{ + return im.data().get_premultiplied(); +} + +void premultiply(image_32 & im) +{ + mapnik::premultiply_alpha(im.data()); +} + +void demultiply(image_32 & im) +{ + mapnik::demultiply_alpha(im.data()); +} + void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity) { - mapnik::composite(dst.data(),src.data(),mode,opacity,0,0,false); + mapnik::composite(dst.data(),src.data(),mode,opacity,0,0); } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) @@ -311,9 +326,9 @@ void export_image() arg("mode")=mapnik::src_over, arg("opacity")=1.0f )) - .def("premultiplied",&image_32::premultiplied) - .def("premultiply",&image_32::premultiply) - .def("demultiply",&image_32::demultiply) + .def("premultiplied",&premultiplied) + .def("premultiply",&premultiply) + .def("demultiply",&demultiply) .def("set_pixel",&set_pixel) .def("get_pixel",&get_pixel) .def("clear",&image_32::clear) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index c1fe52414..2f40f93a6 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -48,7 +48,6 @@ private: image_data_rgba8 data_; boost::optional background_; bool painted_; - bool premultiplied_; public: using pixel_type = typename image_data_rgba8::pixel_type; image_32(int width,int height); @@ -65,11 +64,6 @@ public: return painted_; } - bool premultiplied() const - { - return premultiplied_; - } - inline void clear() { std::fill(data_.getData(), data_.getData() + data_.width() * data_.height(), 0); @@ -79,10 +73,6 @@ public: void set_background(const color& c); - void premultiply(); - - void demultiply(); - void set_grayscale_to_alpha(); void set_color_to_alpha(color const& c); diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index c72f62daa..b41d14b2b 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -87,8 +87,7 @@ MAPNIK_DECL void composite(T & dst, T const& src, composite_mode_e mode, float opacity=1, int dx=0, - int dy=0, - bool premultiply_src=false); + int dy=0); } #endif // MAPNIK_IMAGE_COMPOSITING_HPP diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image_data.hpp index 833a0f16e..09367db85 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image_data.hpp @@ -122,10 +122,11 @@ public: using pixel_type = T; static constexpr std::size_t pixel_size = sizeof(pixel_type); - image_data(int width, int height, bool initialize = true) + image_data(int width, int height, bool initialize = true, bool premultiplied = false) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), - pData_(reinterpret_cast(buffer_.data())) + pData_(reinterpret_cast(buffer_.data())), + premultiplied_alpha_(premultiplied) { if (pData_ && initialize) std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), 0); } @@ -133,13 +134,15 @@ public: image_data(image_data const& rhs) : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), - pData_(reinterpret_cast(buffer_.data())) + pData_(reinterpret_cast(buffer_.data())), + premultiplied_alpha_(rhs.premultiplied_alpha_) {} image_data(image_data && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), - buffer_(std::move(rhs.buffer_)), - pData_(reinterpret_cast(buffer_.data())) + buffer_(std::move(rhs.buffer_)), + pData_(reinterpret_cast(buffer_.data())), + premultiplied_alpha_(std::move(rhs.premultiplied_alpha_)) { rhs.dimensions_ = { 0, 0 }; rhs.pData_ = nullptr; @@ -241,10 +244,21 @@ public: std::copy(buf, buf + (x1 - x0), pData_ + row * dimensions_.width() + x0); } + inline bool get_premultiplied() const + { + return premultiplied_alpha_; + } + + inline void set_premultiplied(bool set) + { + premultiplied_alpha_ = set; + } + private: detail::image_dimensions dimensions_; detail::buffer buffer_; pixel_type *pData_; + bool premultiplied_alpha_; }; using image_data_rgba8 = image_data; diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index 336b4220c..50a8c5c2c 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -34,6 +34,7 @@ struct image_data_null unsigned char* getBytes() { return nullptr;} std::size_t width() const { return 0; } std::size_t height() const { return 0; } + bool get_premultiplied() const { return false; } }; using image_data_base = util::variant + bool operator()(T const& data) const + { + return data.get_premultiplied(); + } +}; } // namespace detail struct image_data_any : image_data_base @@ -109,6 +118,11 @@ struct image_data_any : image_data_base { return util::apply_visitor(detail::get_height_visitor(),*this); } + + bool get_premultiplied() const + { + return util::apply_visitor(detail::get_premultiplied_visitor(),*this); + } }; } diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index 064e94a43..ccebf7ec3 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -391,11 +391,11 @@ template void apply_filter(Src & src, Filter const& filter) { { - src.demultiply(); + demultiply_alpha(src.data()); double_buffer tb(src); apply_convolution_3x3(tb.src_view, tb.dst_view, filter); } // ensure ~double_buffer() is called before premultiplying - src.premultiply(); + premultiply_alpha(src.data()); } template diff --git a/include/mapnik/image_reader.hpp b/include/mapnik/image_reader.hpp index 31a12f4f0..178bfb628 100644 --- a/include/mapnik/image_reader.hpp +++ b/include/mapnik/image_reader.hpp @@ -59,7 +59,6 @@ struct MAPNIK_DECL image_reader : private util::noncopyable virtual unsigned width() const = 0; virtual unsigned height() const = 0; virtual bool has_alpha() const = 0; - virtual bool premultiplied_alpha() const = 0; virtual boost::optional > bounding_box() const = 0; virtual void read(unsigned x,unsigned y,image_data_rgba8& image) = 0; virtual image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0; diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 2bee70bdb..c00129b1b 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -109,6 +109,12 @@ MAPNIK_DECL void save_to_stream std::string const& type ); +template +MAPNIK_DECL void premultiply_alpha(T & image); + +template +MAPNIK_DECL void demultiply_alpha(T & image); + template void save_as_png(T const& image, std::string const& filename, diff --git a/include/mapnik/raster.hpp b/include/mapnik/raster.hpp index 8fafd27b2..6b5fbb663 100644 --- a/include/mapnik/raster.hpp +++ b/include/mapnik/raster.hpp @@ -39,18 +39,15 @@ public: box2d ext_; image_data_any data_; double filter_factor_; - bool premultiplied_alpha_; boost::optional nodata_; template raster(box2d const& ext, ImageData && data, - double filter_factor, - bool premultiplied_alpha = false) + double filter_factor) : ext_(ext), data_(std::move(data)), - filter_factor_(filter_factor), - premultiplied_alpha_(premultiplied_alpha) {} + filter_factor_(filter_factor) {} void set_nodata(double nodata) { diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 7229c60f2..eb950e9ee 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -24,6 +24,7 @@ #define MAPNIK_RENDERER_COMMON_PROCESS_RASTER_SYMBOLIZER_HPP // mapnik +#include #include #include #include @@ -204,22 +205,7 @@ void render_raster_symbolizer(raster_symbolizer const& sym, // only premultiply rgba8 images if (source->data_.is()) { - bool premultiply_source = !source->premultiplied_alpha_; - auto is_premultiplied = get_optional(sym, keys::premultiplied, feature, common.vars_); - if (is_premultiplied) - { - if (*is_premultiplied) premultiply_source = false; - else premultiply_source = true; - } - if (premultiply_source) - { - agg::rendering_buffer buffer(source->data_.getBytes(), - source->data_.width(), - source->data_.height(), - source->data_.width() * 4); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); - } + mapnik::premultiply_alpha(source->data_); } if (!prj_trans.equal()) diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp index d2e77048c..2932a52b0 100644 --- a/plugins/input/pgraster/pgraster_wkb_reader.cpp +++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp @@ -199,7 +199,7 @@ mapnik::raster_ptr read_data_band(mapnik::box2d const& bbox, data[off] = val; } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0, true); + mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); if ( hasnodata ) raster->set_nodata(val); return raster; } @@ -271,7 +271,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d const& bbox, uint16_t width, uint16_t height, bool hasnodata, T reader) { - mapnik::image_data_rgba8 image(width,height); + mapnik::image_data_rgba8 image(width,height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) // TODO: set to transparent instead? image.set(0xffffffff); @@ -292,7 +292,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d const& bbox, data[off+2] = val; } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0, true); + mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); if ( hasnodata ) raster->set_nodata(val); return raster; } @@ -352,7 +352,7 @@ mapnik::raster_ptr pgraster_wkb_reader::read_grayscale(mapnik::box2d con mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d const& bbox, uint16_t width, uint16_t height) { - mapnik::image_data_rgba8 image(width, height); + mapnik::image_data_rgba8 image(width, height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) image.set(0xffffffff); @@ -400,7 +400,7 @@ mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d const& b } } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0, true); + mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); raster->set_nodata(0xffffffff); return raster; } diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 6f5fa0376..d0e8b6b2b 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -116,7 +116,6 @@ feature_ptr raster_featureset::next() intersect = t.backward(feature_raster_extent); mapnik::image_data_any data = reader->read(x_off, y_off, width, height); mapnik::raster_ptr raster = std::make_shared(intersect, std::move(data), 1.0); - raster->premultiplied_alpha_ = reader->premultiplied_alpha(); feature->set_raster(raster); } } diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index d1ce80ca0..d8ddbf382 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -145,7 +145,7 @@ void agg_renderer::setup(Map const &m) { for (unsigned y=0;y::end_style_processing(feature_type_style const& st) composite(pixmap_.data(), current_buffer_->data(), *st.comp_op(), st.get_opacity(), -common_.t_.offset(), - -common_.t_.offset(), false); + -common_.t_.offset()); } else if (blend_from || st.get_opacity() < 1.0) { composite(pixmap_.data(), current_buffer_->data(), src_over, st.get_opacity(), -common_.t_.offset(), - -common_.t_.offset(), false); + -common_.t_.offset()); } } // apply any 'direct' image filters @@ -376,8 +376,7 @@ void agg_renderer::render_marker(pixel_position const& pos, composite(current_buffer_->data(), **marker.get_bitmap_data(), comp_op, opacity, std::floor(pos.x - cx + .5), - std::floor(pos.y - cy + .5), - false); + std::floor(pos.y - cy + .5)); } else { diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 4af75bbd6..3bfb6c20a 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -55,7 +55,7 @@ void agg_renderer::process(raster_symbolizer const& sym, [&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { composite(current_buffer_->data(), target, - comp_op, opacity, start_x, start_y, false); + comp_op, opacity, start_x, start_y); } ); } diff --git a/src/graphics.cpp b/src/graphics.cpp index 901b5fa50..b75df096b 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -40,14 +40,12 @@ namespace mapnik { image_32::image_32(int width,int height) : data_(width,height), - painted_(false), - premultiplied_(false) {} + painted_(false) {} image_32::image_32(image_32 const& rhs) : data_(rhs.data_), - painted_(rhs.painted_), - premultiplied_(rhs.premultiplied_) {} + painted_(rhs.painted_) {} image_32::~image_32() {} @@ -123,22 +121,6 @@ boost::optional const& image_32::get_background() const return background_; } -void image_32::premultiply() -{ - agg::rendering_buffer buffer(data_.getBytes(),data_.width(),data_.height(),data_.width() * 4); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); - premultiplied_ = true; -} - -void image_32::demultiply() -{ - agg::rendering_buffer buffer(data_.getBytes(),data_.width(),data_.height(),data_.width() * 4); - agg::pixfmt_rgba32_pre pixf(buffer); - pixf.demultiply(); - premultiplied_ = false; -} - void image_32::composite_pixel(unsigned op, int x,int y, unsigned c, unsigned cover, double opacity) { using color_type = agg::rgba8; diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 75e9884d2..41192cb6a 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -23,6 +23,7 @@ // mapnik #include #include +#include // boost #pragma GCC diagnostic push @@ -145,14 +146,13 @@ struct rendering_buffer image_data_type const& data_; }; -} +} // end detail ns template <> MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, composite_mode_e mode, float opacity, int dx, - int dy, - bool premultiply_src) + int dy) { using color = agg::rgba8; using order = agg::order_rgba; @@ -166,7 +166,7 @@ MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, pixfmt_type pixf(dst_buffer); pixf.comp_op(static_cast(mode)); agg::pixfmt_alpha_blend_rgba pixf_mask(src_buffer); - if (premultiply_src) pixf_mask.premultiply(); + if (!src.get_premultiplied()) pixf_mask.premultiply(); renderer_type ren(pixf); ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity)); } @@ -175,8 +175,7 @@ template <> 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) + int dy) { using const_rendering_buffer = detail::rendering_buffer; using src_pixfmt_type = agg::pixfmt_alpha_blend_gray, const_rendering_buffer, 1, 0>; @@ -191,4 +190,59 @@ MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f const& s ren.copy_from(pixf_mask,0,dx,dy); } +namespace detail { + +struct composite_visitor +{ + composite_visitor(image_data_any const& src, + composite_mode_e mode, + float opacity, + int dx, + int dy) + : src_(src), + mode_(mode), + opacity_(opacity), + dx_(dx), + dy_(dy) {} + + template + void operator() (T & dst); + + private: + image_data_any const& src_; + composite_mode_e mode_; + float opacity_; + int dx_; + int dy_; +}; + +template +void composite_visitor::operator() (T & dst) +{ + throw std::runtime_error("Error: Composite with " + std::string(typeid(dst).name()) + " is not supported"); +} + +template <> +void composite_visitor::operator() (image_data_rgba8 & dst) +{ + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); +} + +template <> +void composite_visitor::operator() (image_data_gray32f & dst) +{ + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); +} + +} // end ns + +template <> +MAPNIK_DECL void composite(image_data_any & dst, image_data_any const& src, composite_mode_e mode, + float opacity, + int dx, + int dy) +{ + util::apply_visitor(detail::composite_visitor(src, mode, opacity, dx, dy), dst); +} + } diff --git a/src/image_util.cpp b/src/image_util.cpp index 8f6c00e13..9a59eee71 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,11 @@ // boost #include +// agg +#include "agg_rendering_buffer.h" +#include "agg_pixfmt_rgba.h" +#include "agg_color_rgba.h" + // stl #include #include @@ -75,7 +81,7 @@ void save_to_file(T const& image, std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) { - save_to_stream(image, file, type, palette); + save_to_stream(image, file, type, palette); } else throw ImageWriterException("Could not write file to " + filename ); } @@ -88,7 +94,7 @@ void save_to_file(T const& image, std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) { - save_to_stream(image, file, type); + save_to_stream(image, file, type); } else throw ImageWriterException("Could not write file to " + filename ); } @@ -98,6 +104,67 @@ void save_to_stream(T const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver_pal visitor(stream, t, palette); + mapnik::util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + throw ImageWriterException("palettes are not currently supported when writing to tiff format (yet)"); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + throw ImageWriterException("palettes are not currently supported when writing to jpeg format"); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_data_any and image_view_any are the only +// items using this template +template <> +void save_to_stream(image_data_rgba8 const& image, + std::ostream & stream, + std::string const& type, + rgba_palette const& palette) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver_pal visitor(stream, t, palette); + visitor(image); + //mapnik::util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + throw ImageWriterException("palettes are not currently supported when writing to tiff format (yet)"); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + throw ImageWriterException("palettes are not currently supported when writing to jpeg format"); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_data_any and image_view_any are the only +// items using this template +template <> +void save_to_stream(image_view_rgba8 const& image, + std::ostream & stream, + std::string const& type, + rgba_palette const& palette) { if (stream && image.width() > 0 && image.height() > 0) { @@ -126,6 +193,82 @@ template void save_to_stream(T const& image, std::ostream & stream, std::string const& type) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver visitor(stream, t); + util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + tiff_saver visitor(stream, t); + util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + jpeg_saver visitor(stream, t); + util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "webp")) + { + webp_saver visitor(stream, t); + util::apply_visitor(visitor, image); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_data_any and image_view_any are the only +// items using this template +template <> +void save_to_stream(image_data_rgba8 const& image, + std::ostream & stream, + std::string const& type) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + tiff_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + jpeg_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "webp")) + { + webp_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_data_any and image_view_any are the only +// items using this template +template <> +void save_to_stream(image_view_rgba8 const& image, + std::ostream & stream, + std::string const& type) { if (stream && image.width() > 0 && image.height() > 0) { @@ -182,50 +325,157 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } +// image_data_rgba8 template void save_to_file(image_data_rgba8 const&, - std::string const&, - std::string const&); + std::string const&, + std::string const&); template void save_to_file(image_data_rgba8 const&, - std::string const&, - std::string const&, - rgba_palette const& palette); + std::string const&, + std::string const&, + rgba_palette const& palette); template void save_to_file(image_data_rgba8 const&, - std::string const&); + std::string const&); template void save_to_file(image_data_rgba8 const&, - std::string const&, - rgba_palette const& palette); + std::string const&, + rgba_palette const& palette); template std::string save_to_string(image_data_rgba8 const&, - std::string const&); + std::string const&); template std::string save_to_string(image_data_rgba8 const&, - std::string const&, - rgba_palette const& palette); + std::string const&, + rgba_palette const& palette); + +// image_view_rgba8 +template void save_to_file (image_view_rgba8 const&, + std::string const&, + std::string const&); template void save_to_file (image_view_rgba8 const&, - std::string const&, - std::string const&); + std::string const&, + std::string const&, + rgba_palette const& palette); template void save_to_file (image_view_rgba8 const&, - std::string const&, - std::string const&, - rgba_palette const& palette); + std::string const&); template void save_to_file (image_view_rgba8 const&, - std::string const&); - -template void save_to_file (image_view_rgba8 const&, - std::string const&, - rgba_palette const& palette); + std::string const&, + rgba_palette const& palette); template std::string save_to_string (image_view_rgba8 const&, - std::string const&); + std::string const&); template std::string save_to_string (image_view_rgba8 const&, - std::string const&, - rgba_palette const& palette); + std::string const&, + rgba_palette const& palette); +// image_data_any +template void save_to_file(image_data_any const&, + std::string const&, + std::string const&); + +template void save_to_file(image_data_any const&, + std::string const&, + std::string const&, + rgba_palette const& palette); + +template void save_to_file(image_data_any const&, + std::string const&); + +template void save_to_file(image_data_any const&, + std::string const&, + rgba_palette const& palette); + +template std::string save_to_string(image_data_any const&, + std::string const&); + +template std::string save_to_string(image_data_any const&, + std::string const&, + rgba_palette const& palette); + + +namespace detail { + +struct premultiply_visitor +{ + template + void operator() (T & data) + { + throw std::runtime_error("Error: Premultiply with " + std::string(typeid(data).name()) + " is not supported"); + } + +}; + +template <> +void premultiply_visitor::operator() (image_data_rgba8 & data) +{ + if (!data.get_premultiplied()) + { + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.width() * 4); + agg::pixfmt_rgba32 pixf(buffer); + pixf.premultiply(); + data.set_premultiplied(true); + } } + +struct demultiply_visitor +{ + template + void operator() (T & data) + { + throw std::runtime_error("Error: Premultiply with " + std::string(typeid(data).name()) + " is not supported"); + } + +}; + +template <> +void demultiply_visitor::operator() (image_data_rgba8 & data) +{ + if (data.get_premultiplied()) + { + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.width() * 4); + agg::pixfmt_rgba32_pre pixf(buffer); + pixf.demultiply(); + data.set_premultiplied(false); + } +} + +} // end detail ns + +template +void premultiply_alpha(T & image) +{ + util::apply_visitor(detail::premultiply_visitor(), image); +} + +template void premultiply_alpha (image_data_any &); + +// Temporary, can be removed once image_view_any and image_data_any are the only ones passed +template <> +void premultiply_alpha(image_data_rgba8 & image) +{ + detail::premultiply_visitor visit; + visit(image); +} + +template +void demultiply_alpha(T & image) +{ + util::apply_visitor(detail::demultiply_visitor(), image); +} + +template void demultiply_alpha (image_data_any &); + +// Temporary, can be removed once image_view_any and image_data_any are the only ones passed +template <> +void demultiply_alpha(image_data_rgba8 & image) +{ + detail::demultiply_visitor visit; + visit(image); +} + +} // end ns diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index d44c13974..d096a44fc 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -76,6 +76,12 @@ void jpeg_saver::operator() (image_view_rgba8 const& image) co process_rgba8_jpeg(image, t_, stream_); } +template<> +void jpeg_saver::operator() (image_data_null const& image) const +{ + throw ImageWriterException("Can not save a null image to jpeg"); +} + template void jpeg_saver::operator() (T const& image) const { diff --git a/src/jpeg_reader.cpp b/src/jpeg_reader.cpp index 48ac83e19..d6935572c 100644 --- a/src/jpeg_reader.cpp +++ b/src/jpeg_reader.cpp @@ -85,7 +85,6 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return false; } - inline bool premultiplied_alpha() const final { return true; } void read(unsigned x,unsigned y,image_data_rgba8& image) final; image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: @@ -323,7 +322,7 @@ void jpeg_reader::read(unsigned x0, unsigned y0, image_data_rgba8& image) template image_data_any jpeg_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height); + image_data_rgba8 data(width,height, true, true); read(x, y, data); return image_data_any(std::move(data)); } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index c7d1b005f..de42f1552 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -210,14 +210,13 @@ boost::optional marker_cache::find(std::string const& uri, unsigned width = reader->width(); unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); - mapnik::image_ptr image(std::make_shared(width,height)); - reader->read(0,0,*image); - if (!reader->premultiplied_alpha()) + image_data_any im = reader->read(0,0,width,height); + if (!im.is()) { - agg::rendering_buffer buffer(image->getBytes(),image->width(),image->height(),image->width() * 4); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); + throw std::runtime_error("Error: Only image_data_rgba8 types are supported currenctly by markers"); } + mapnik::premultiply_alpha(im); + mapnik::image_ptr image(std::make_shared(std::move(util::get(im)))); marker_ptr mark(std::make_shared(image)); result.reset(mark); if (update_cache) diff --git a/src/png_reader.cpp b/src/png_reader.cpp index 318a67b47..21cd38fc0 100644 --- a/src/png_reader.cpp +++ b/src/png_reader.cpp @@ -80,7 +80,6 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - bool premultiplied_alpha() const final { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html void read(unsigned x,unsigned y,image_data_rgba8& image) final; image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index b81df4b68..bfcf54b3a 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -153,7 +153,6 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - bool premultiplied_alpha() const final; void read(unsigned x,unsigned y,image_data_rgba8& image) final; image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; // methods specific to tiff reader @@ -377,12 +376,6 @@ boost::optional > tiff_reader::bounding_box() const return bbox_; } -template -bool tiff_reader::premultiplied_alpha() const -{ - return premultiplied_alpha_; -} - template void tiff_reader::read(unsigned x,unsigned y,image_data_rgba8& image) { @@ -525,7 +518,7 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un TIFF* tif = open(stream_); if (tif) { - image_data_rgba8 data(width, height); + image_data_rgba8 data(width, height, true, premultiplied_alpha_); std::size_t element_size = sizeof(detail::rgb8); std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size; const std::unique_ptr scanline(new detail::rgb8[size_to_allocate]); @@ -550,13 +543,13 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un } case 16: { - image_data_rgba8 data(width,height); + image_data_rgba8 data(width,height,true,premultiplied_alpha_); read(x0, y0, data); return image_data_any(std::move(data)); } case 32: { - image_data_rgba8 data(width,height); + image_data_rgba8 data(width,height,true,premultiplied_alpha_); read(x0, y0, data); return image_data_any(std::move(data)); } @@ -574,7 +567,7 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un //PHOTOMETRIC_ITULAB = 10; //PHOTOMETRIC_LOGL = 32844; //PHOTOMETRIC_LOGLUV = 32845; - image_data_rgba8 data(width,height); + image_data_rgba8 data(width,height, true, premultiplied_alpha_); read(x0, y0, data); return image_data_any(std::move(data)); } diff --git a/src/webp_reader.cpp b/src/webp_reader.cpp index 6add17485..ff31e8996 100644 --- a/src/webp_reader.cpp +++ b/src/webp_reader.cpp @@ -124,7 +124,6 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - bool premultiplied_alpha() const final { return false; } void read(unsigned x,unsigned y,image_data_rgba8& image) final; image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index 37cfdddd4..302e7e5ce 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -26,25 +26,19 @@ REQUIRE( reader2->width() == 256 ); \ REQUIRE( reader2->height() == 256 ); \ -#define TIFF_ASSERT_ALPHA \ +#define TIFF_ASSERT_ALPHA( data ) \ REQUIRE( tiff_reader.has_alpha() == true ); \ - REQUIRE( tiff_reader.premultiplied_alpha() == false ); \ REQUIRE( reader->has_alpha() == true ); \ - REQUIRE( reader->premultiplied_alpha() == false ); \ REQUIRE( tiff_reader2.has_alpha() == true ); \ - REQUIRE( tiff_reader2.premultiplied_alpha() == false ); \ REQUIRE( reader2->has_alpha() == true ); \ - REQUIRE( reader2->premultiplied_alpha() == false ); \ + REQUIRE( data.get_premultiplied() == false ); \ -#define TIFF_ASSERT_NO_ALPHA \ +#define TIFF_ASSERT_NO_ALPHA( data ) \ REQUIRE( tiff_reader.has_alpha() == false ); \ - REQUIRE( tiff_reader.premultiplied_alpha() == false ); \ REQUIRE( reader->has_alpha() == false ); \ - REQUIRE( reader->premultiplied_alpha() == false ); \ REQUIRE( tiff_reader2.has_alpha() == false ); \ - REQUIRE( tiff_reader2.premultiplied_alpha() == false ); \ REQUIRE( reader2->has_alpha() == false ); \ - REQUIRE( reader2->premultiplied_alpha() == false ); \ + REQUIRE( data.get_premultiplied() == false ); \ #define TIFF_ASSERT_SIZE( data,reader ) \ REQUIRE( data.width() == reader->width() ); \ @@ -83,7 +77,7 @@ SECTION("scan rgb8 striped") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -113,7 +107,7 @@ SECTION("scan rgb8 tiled") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -129,7 +123,7 @@ SECTION("rgba8 striped") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_ALPHA + TIFF_ASSERT_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -145,7 +139,7 @@ SECTION("rgba8 tiled") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_ALPHA + TIFF_ASSERT_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -161,7 +155,7 @@ SECTION("rgb8 striped") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -177,7 +171,7 @@ SECTION("rgb8 tiled") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -193,7 +187,7 @@ SECTION("gray8 striped") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -209,7 +203,7 @@ SECTION("gray8 tiled") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -225,7 +219,7 @@ SECTION("gray16 striped") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -241,7 +235,7 @@ SECTION("gray16 tiled") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -257,7 +251,7 @@ SECTION("gray32f striped") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -273,7 +267,7 @@ SECTION("gray32f tiled") { mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL } From cbc76f7361a0a041122ce758a15b5cbca3aa2438 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 14 Jan 2015 15:24:16 -0600 Subject: [PATCH 20/91] Some minor corrections to allow for the source to build properly with out linking errors with vis to hidden. --- include/mapnik/graphics.hpp | 10 ----- include/mapnik/image.hpp | 2 +- include/mapnik/image_data_any.hpp | 1 + include/mapnik/image_util.hpp | 3 ++ .../process_raster_symbolizer.hpp | 5 +++ src/image.cpp | 7 ++-- src/image_util.cpp | 38 +++++++++++++++++-- 7 files changed, 48 insertions(+), 18 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 2f40f93a6..e563df8e7 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -94,21 +94,11 @@ public: return data_.getBytes(); } - inline const unsigned char* getBytes() const - { - return data_.getBytes(); - } - inline unsigned char* raw_data() { return data_.getBytes(); } - inline unsigned char* getBytes() - { - return data_.getBytes(); - } - inline image_view_rgba8 get_view(unsigned x,unsigned y, unsigned w,unsigned h) { return image_view_rgba8(x,y,w,h,data_); diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index d9e6d5243..ed2a1d1bc 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -27,7 +27,7 @@ namespace mapnik { -class image +class MAPNIK_DECL image { public: image() = default; diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index 50a8c5c2c..241e65db0 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -35,6 +35,7 @@ struct image_data_null std::size_t width() const { return 0; } std::size_t height() const { return 0; } bool get_premultiplied() const { return false; } + void set_premultiplied(bool) const {} }; using image_data_base = util::variant MAPNIK_DECL void demultiply_alpha(T & image); +template +MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status); + template void save_as_png(T const& image, std::string const& filename, diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index eb950e9ee..911f1b309 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -205,6 +205,11 @@ void render_raster_symbolizer(raster_symbolizer const& sym, // only premultiply rgba8 images if (source->data_.is()) { + auto is_premultiplied = get_optional(sym, keys::premultiplied, feature, common.vars_); + if (is_premultiplied && *is_premultiplied) + { + mapnik::set_premultiplied_alpha(source->data_, true); + } mapnik::premultiply_alpha(source->data_); } diff --git a/src/image.cpp b/src/image.cpp index f7728fe62..f30d025f2 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -52,7 +52,7 @@ image image::read_from_file(std::string const& filename) return image(); } } - +/* namespace detail { struct save_to_file_visitor @@ -94,11 +94,12 @@ struct save_to_file_visitor std::string const& format_; }; -} +}*/ void image::save_to_file(std::string const& filename, std::string const& format) { - util::apply_visitor(detail::save_to_file_visitor(filename, format), data_); + mapnik::save_to_file(data_, filename, format); + //util::apply_visitor(detail::save_to_file_visitor(filename, format), data_); } } diff --git a/src/image_util.cpp b/src/image_util.cpp index 9a59eee71..f71fe334f 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -444,10 +444,24 @@ void demultiply_visitor::operator() (image_data_rgba8 & data) } } +struct set_premultiplied_visitor +{ + set_premultiplied_visitor(bool status) + : status_(status) {} + + template + void operator() (T & data) + { + data.set_premultiplied(status_); + } + private: + bool status_; +}; + } // end detail ns template -void premultiply_alpha(T & image) +MAPNIK_DECL void premultiply_alpha(T & image) { util::apply_visitor(detail::premultiply_visitor(), image); } @@ -456,14 +470,14 @@ template void premultiply_alpha (image_data_any &); // Temporary, can be removed once image_view_any and image_data_any are the only ones passed template <> -void premultiply_alpha(image_data_rgba8 & image) +MAPNIK_DECL void premultiply_alpha(image_data_rgba8 & image) { detail::premultiply_visitor visit; visit(image); } template -void demultiply_alpha(T & image) +MAPNIK_DECL void demultiply_alpha(T & image) { util::apply_visitor(detail::demultiply_visitor(), image); } @@ -472,10 +486,26 @@ template void demultiply_alpha (image_data_any &); // Temporary, can be removed once image_view_any and image_data_any are the only ones passed template <> -void demultiply_alpha(image_data_rgba8 & image) +MAPNIK_DECL void demultiply_alpha(image_data_rgba8 & image) { detail::demultiply_visitor visit; visit(image); } +template +MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status) +{ + util::apply_visitor(detail::set_premultiplied_visitor(status), image); +} + +template void set_premultiplied_alpha (image_data_any &, bool); + +// Temporary, can be removed once image_view_any and image_data_any are the only ones passed +template <> +MAPNIK_DECL void set_premultiplied_alpha(image_data_rgba8 & image, bool status) +{ + detail::set_premultiplied_visitor visit(status); + visit(image); +} + } // end ns From 202a0e8e5fb5bb901fec53af8dd586a7a92dbb48 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 14 Jan 2015 18:29:00 -0600 Subject: [PATCH 21/91] Added a lot of premultiply_alpha functions to attempt to have proper premultiplication of data prior to compositing. There still seem to be some errors in the resulting images, but I am not quite sure what they are yet. --- bindings/python/mapnik_image.cpp | 2 ++ include/mapnik/tiff_io.hpp | 15 +++++++++++---- src/agg/agg_renderer.cpp | 11 +++++++---- src/agg/process_raster_symbolizer.cpp | 2 ++ src/graphics.cpp | 3 +-- src/image_compositing.cpp | 10 +++++++++- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index ef6fb4c37..4459edd21 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -228,6 +228,8 @@ void demultiply(image_32 & im) void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity) { + mapnik::premultiply_alpha(dst.data()); + mapnik::premultiply_alpha(src.data()); mapnik::composite(dst.data(),src.data(),mode,opacity,0,0); } diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 33dbf4a11..8ce71e433 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -192,15 +192,22 @@ struct tag_setter throw ImageWriterException("Could not write TIFF - unknown image type provided"); } - inline void operator() (image_data_rgba8 const&) const + inline void operator() (image_data_rgba8 const& data) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 4); - //uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; - uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; - TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); + if (data.get_premultiplied()) + { + uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; + TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); + } + else + { + uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; + TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); + } if (config_.compression == COMPRESSION_DEFLATE || config_.compression == COMPRESSION_ADOBE_DEFLATE || config_.compression == COMPRESSION_LZW) diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index d8ddbf382..fd15b646d 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -145,6 +145,8 @@ void agg_renderer::setup(Map const &m) { for (unsigned y=0;y::start_map_processing(Map const& map) template void agg_renderer::end_map_processing(Map const& ) { - - agg::rendering_buffer buf(pixmap_.raw_data(),common_.width_,common_.height_, common_.width_ * 4); - agg::pixfmt_rgba32_pre pixf(buf); - pixf.demultiply(); + mapnik::demultiply_alpha(pixmap_.data()); MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End map processing"; } @@ -280,6 +279,8 @@ void agg_renderer::end_style_processing(feature_type_style const& st) util::apply_visitor(visitor, filter_tag); } } + mapnik::premultiply_alpha(pixmap_.data()); + mapnik::premultiply_alpha(current_buffer_->data()); if (st.comp_op()) { composite(pixmap_.data(), current_buffer_->data(), @@ -373,6 +374,8 @@ void agg_renderer::render_marker(pixel_position const& pos, { double cx = 0.5 * width; double cy = 0.5 * height; + mapnik::premultiply_alpha(current_buffer_->data()); + mapnik::premultiply_alpha(**marker.get_bitmap_data()); composite(current_buffer_->data(), **marker.get_bitmap_data(), comp_op, opacity, std::floor(pos.x - cx + .5), diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 3bfb6c20a..099462b6f 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -54,6 +54,8 @@ void agg_renderer::process(raster_symbolizer const& sym, sym, feature, prj_trans, common_, [&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { + premultiply_alpha(target); + premultiply_alpha(current_buffer_->data()); composite(current_buffer_->data(), target, comp_op, opacity, start_x, start_y); } diff --git a/src/graphics.cpp b/src/graphics.cpp index 16e57fe3e..20f159f2b 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -49,8 +49,7 @@ image_32::image_32(image_32 const& rhs) image_32::image_32(image_data_rgba8 && data) : data_(std::move(data)), - painted_(false), - premultiplied_(false) {} + painted_(false) {} image_32::~image_32() {} diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 41192cb6a..ac1823f6e 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -166,7 +166,15 @@ MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, pixfmt_type pixf(dst_buffer); pixf.comp_op(static_cast(mode)); agg::pixfmt_alpha_blend_rgba pixf_mask(src_buffer); - if (!src.get_premultiplied()) pixf_mask.premultiply(); + // DEBUGGING ONLY REMOVE + if (!src.get_premultiplied()) + { + throw std::runtime_error("SOURCE MUST BE PREMULTIPLIED FOR COMPOSITING!"); + } + if (!dst.get_premultiplied()) + { + throw std::runtime_error("DESTINATION MUST BE PREMULTIPLIED FOR COMPOSITING!"); + } renderer_type ren(pixf); ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity)); } From 1f25bae0f4d26d67303cc4a38653a5769116e0f8 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:03:35 -0800 Subject: [PATCH 22/91] fix compile of svg2png --- utils/svg2png/svg2png.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index ab3c6285b..7b73c49ed 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -181,7 +181,7 @@ int main (int argc,char** argv) svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox); boost::algorithm::ireplace_last(svg_name,".svg",".png"); - im.demultiply(); + demultiply_alpha(im.data()); mapnik::save_to_file(im.data(),svg_name,"png"); if (auto_open) { From 364fb4961b1befc07740c6bd2a0f315a0627dbb9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:04:05 -0800 Subject: [PATCH 23/91] fix handling of premultiplied pixels during rendering --- include/mapnik/marker.hpp | 3 ++- .../mapnik/renderer_common/process_raster_symbolizer.hpp | 6 ++++-- src/agg/agg_renderer.cpp | 8 ++------ src/agg/process_raster_symbolizer.cpp | 2 -- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index 63fe16c18..160ff0fd3 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include #include #include #include @@ -56,7 +57,7 @@ public: marker() { // create default OGC 4x4 black pixel - bitmap_data_ = boost::optional(std::make_shared(4,4)); + bitmap_data_ = boost::optional(std::make_shared(4,4,true,true)); (*bitmap_data_)->set(0xff000000); } diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 911f1b309..5e171b9b2 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -72,7 +72,7 @@ struct image_data_dispatcher void operator() (image_data_null const& data_in) const {} //no-op void operator() (image_data_rgba8 const& data_in) const { - image_data_rgba8 data_out(width_, height_); + image_data_rgba8 data_out(width_, height_, true, true); scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } @@ -86,6 +86,7 @@ struct image_data_dispatcher image_data_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); + premultiply_alpha(dst); composite_(dst, comp_op_, opacity_, start_x_, start_y_); } private: @@ -138,7 +139,7 @@ struct image_data_warp_dispatcher void operator() (image_data_rgba8 const& data_in) const { - image_data_rgba8 data_out(width_, height_); + image_data_rgba8 data_out(width_, height_, true, true); warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } @@ -153,6 +154,7 @@ struct image_data_warp_dispatcher image_data_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); + premultiply_alpha(dst); composite_(dst, comp_op_, opacity_, start_x_, start_y_); } private: diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index fd15b646d..f11a02330 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -111,6 +111,7 @@ agg_renderer::agg_renderer(Map const& m, T0 & pixmap, std::shared_ptr template void agg_renderer::setup(Map const &m) { + mapnik::set_premultiplied_alpha(pixmap_.data(), true); boost::optional const& bg = m.background(); if (bg) { @@ -145,8 +146,6 @@ void agg_renderer::setup(Map const &m) { for (unsigned y=0;y::start_style_processing(feature_type_style const& st) ras_ptr->clip_box(0,0,common_.width_,common_.height_); } current_buffer_ = internal_buffer_.get(); + set_premultiplied_alpha(current_buffer_->data(),true); } else { @@ -279,8 +279,6 @@ void agg_renderer::end_style_processing(feature_type_style const& st) util::apply_visitor(visitor, filter_tag); } } - mapnik::premultiply_alpha(pixmap_.data()); - mapnik::premultiply_alpha(current_buffer_->data()); if (st.comp_op()) { composite(pixmap_.data(), current_buffer_->data(), @@ -374,8 +372,6 @@ void agg_renderer::render_marker(pixel_position const& pos, { double cx = 0.5 * width; double cy = 0.5 * height; - mapnik::premultiply_alpha(current_buffer_->data()); - mapnik::premultiply_alpha(**marker.get_bitmap_data()); composite(current_buffer_->data(), **marker.get_bitmap_data(), comp_op, opacity, std::floor(pos.x - cx + .5), diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 099462b6f..3bfb6c20a 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -54,8 +54,6 @@ void agg_renderer::process(raster_symbolizer const& sym, sym, feature, prj_trans, common_, [&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { - premultiply_alpha(target); - premultiply_alpha(current_buffer_->data()); composite(current_buffer_->data(), target, comp_op, opacity, start_x, start_y); } From e03739e316b3ad357eff56616178caac61b8be51 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:10:39 -0800 Subject: [PATCH 24/91] fix is_solid return --- bindings/python/mapnik_image_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index 82ca74c8e..4d448e40a 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -89,7 +89,7 @@ PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& forma bool is_solid(image_view_rgba8 const& view) { - mapnik::is_solid(view); + return mapnik::is_solid(view); } void save_view1(image_view_rgba8 const& view, From d0d899a9dd8e502485d6d3e17ee1cd4b11b819b4 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:19:45 -0800 Subject: [PATCH 25/91] fix linking error with saving image --- include/mapnik/image.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index d9e6d5243..d9ee28334 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -24,10 +24,11 @@ #define MAPNIK_IMAGE_HPP #include +#include namespace mapnik { -class image +class MAPNIK_DECL image { public: image() = default; From 508521d5e56c447ea207447f384a8037b5f2fd9e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:20:15 -0800 Subject: [PATCH 26/91] move is_solid to hpp for now to avoid linking errors --- include/mapnik/image_util.hpp | 52 ++++++++++++++++++++++++++++- src/image_util.cpp | 61 ----------------------------------- 2 files changed, 51 insertions(+), 62 deletions(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 58d3a0359..dd664415e 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -27,6 +27,7 @@ #include #include #include +#include // boost #pragma GCC diagnostic push @@ -109,8 +110,57 @@ MAPNIK_DECL void save_to_stream std::string const& type ); +namespace detail { + +struct is_solid_visitor +{ + template + inline bool operator() (T const & data) + { + using pixel_type = typename T::pixel_type; + if (data.width() > 0 && data.height() > 0) + { + pixel_type const* first_row = data.getRow(0); + pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type const * row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; + } +}; + +} template -MAPNIK_DECL bool is_solid (T const& image); +inline bool is_solid (T const& image) +{ + return util::apply_visitor(detail::is_solid_visitor(), image); +} + +// Temporary until image_data_rgba8 is removed from passing +template <> +inline bool is_solid(image_data_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + +// Temporary until image_view_rgba8 is removed from passing +template <> +inline bool is_solid(image_view_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + inline bool is_png(std::string const& filename) { diff --git a/src/image_util.cpp b/src/image_util.cpp index ce1eaf7ed..8f6c00e13 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -182,67 +182,6 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } -namespace detail { - -struct is_solid_visitor -{ - template - bool operator() (T const & data) - { - using pixel_type = typename T::pixel_type; - if (data.width() > 0 && data.height() > 0) - { - pixel_type const* first_row = data.getRow(0); - pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < data.height(); ++y) - { - pixel_type const * row = data.getRow(y); - for (unsigned x = 0; x < data.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; - } -}; - -template bool is_solid_visitor::operator() (image_data_rgba8 const& data); -template bool is_solid_visitor::operator() (image_data_gray8 const& data); -template bool is_solid_visitor::operator() (image_data_gray16 const& data); -template bool is_solid_visitor::operator() (image_data_gray32f const& data); -template bool is_solid_visitor::operator() (image_view_rgba8 const& data); -template bool is_solid_visitor::operator() (image_view_gray8 const& data); -template bool is_solid_visitor::operator() (image_view_gray16 const& data); -template bool is_solid_visitor::operator() (image_view_gray32f const& data); - -} // end detail ns - -template -bool is_solid(T const& image) -{ - return util::apply_visitor(detail::is_solid_visitor(), image); -} - -// Temporary until image_data_rgba8 is removed from passing -template <> -bool is_solid(image_data_rgba8 const& image) -{ - detail::is_solid_visitor visitor; - return visitor(image); -} - -// Temporary until image_view_rgba8 is removed from passing -template <> -bool is_solid(image_view_rgba8 const& image) -{ - detail::is_solid_visitor visitor; - return visitor(image); -} - template void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&); From 7ce7416999618b06d039e33361a077034c2bc0c0 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 13 Jan 2015 11:43:20 -0600 Subject: [PATCH 27/91] Added is_solid to image_utils. It is currently built to support the eventual use of image_view_any and image_data_any, but for a limited time supports the passing of image_view_rgba8 and image_data_rgba8. Ref #2633 --- bindings/python/mapnik_image.cpp | 19 +-------- bindings/python/mapnik_image_view.cpp | 18 +------- include/mapnik/image_util.hpp | 4 +- src/image_util.cpp | 61 +++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 4459edd21..7577878c3 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -121,24 +121,7 @@ bool painted(mapnik::image_32 const& im) bool is_solid(mapnik::image_32 const& im) { - if (im.width() > 0 && im.height() > 0) - { - mapnik::image_data_rgba8 const & data = im.data(); - mapnik::image_data_rgba8::pixel_type const* first_row = data.getRow(0); - mapnik::image_data_rgba8::pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < im.height(); ++y) - { - mapnik::image_data_rgba8::pixel_type const * row = data.getRow(y); - for (unsigned x = 0; x < im.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; + return mapnik::is_solid(im.data()); } unsigned get_pixel(mapnik::image_32 const& im, int x, int y) diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index 8894a96eb..82ca74c8e 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -89,23 +89,7 @@ PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& forma bool is_solid(image_view_rgba8 const& view) { - if (view.width() > 0 && view.height() > 0) - { - mapnik::image_view_rgba8::pixel_type const* first_row = view.getRow(0); - mapnik::image_view_rgba8::pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < view.height(); ++y) - { - mapnik::image_view_rgba8::pixel_type const * row = view.getRow(y); - for (unsigned x = 0; x < view.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; + mapnik::is_solid(view); } void save_view1(image_view_rgba8 const& view, diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 0cec4782c..31e2cf551 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -119,9 +119,7 @@ template MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status); template -void save_as_png(T const& image, - std::string const& filename, - rgba_palette const& palette); +MAPNIK_DECL bool is_solid (T const& image); inline bool is_png(std::string const& filename) { diff --git a/src/image_util.cpp b/src/image_util.cpp index f71fe334f..85242add4 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -325,6 +325,67 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } +namespace detail { + +struct is_solid_visitor +{ + template + bool operator() (T const & data) + { + using pixel_type = typename T::pixel_type; + if (data.width() > 0 && data.height() > 0) + { + pixel_type const* first_row = data.getRow(0); + pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type const * row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; + } +}; + +template bool is_solid_visitor::operator() (image_data_rgba8 const& data); +template bool is_solid_visitor::operator() (image_data_gray8 const& data); +template bool is_solid_visitor::operator() (image_data_gray16 const& data); +template bool is_solid_visitor::operator() (image_data_gray32f const& data); +template bool is_solid_visitor::operator() (image_view_rgba8 const& data); +template bool is_solid_visitor::operator() (image_view_gray8 const& data); +template bool is_solid_visitor::operator() (image_view_gray16 const& data); +template bool is_solid_visitor::operator() (image_view_gray32f const& data); + +} // end detail ns + +template +bool is_solid(T const& image) +{ + return util::apply_visitor(detail::is_solid_visitor(), image); +} + +// Temporary until image_data_rgba8 is removed from passing +template <> +bool is_solid(image_data_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + +// Temporary until image_view_rgba8 is removed from passing +template <> +bool is_solid(image_view_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + // image_data_rgba8 template void save_to_file(image_data_rgba8 const&, std::string const&, From 40c1649b0e211608c3b10b78dd1fa41d5d130aad Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:10:39 -0800 Subject: [PATCH 28/91] fix is_solid return --- bindings/python/mapnik_image_view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index 82ca74c8e..4d448e40a 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -89,7 +89,7 @@ PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& forma bool is_solid(image_view_rgba8 const& view) { - mapnik::is_solid(view); + return mapnik::is_solid(view); } void save_view1(image_view_rgba8 const& view, From 61bc70511747843b3a64e7fadc31db2d6ae5a065 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:19:45 -0800 Subject: [PATCH 29/91] fix linking error with saving image --- include/mapnik/image.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index ed2a1d1bc..d9ee28334 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -24,6 +24,7 @@ #define MAPNIK_IMAGE_HPP #include +#include namespace mapnik { From cf646030f33c1c49b6caf8bf7297a0e87439081b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 14 Jan 2015 21:20:15 -0800 Subject: [PATCH 30/91] move is_solid to hpp for now to avoid linking errors --- include/mapnik/image_util.hpp | 1 + src/image_util.cpp | 121 +++++++++++++++++----------------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 31e2cf551..2c018a0bc 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -27,6 +27,7 @@ #include #include #include +#include // boost #pragma GCC diagnostic push diff --git a/src/image_util.cpp b/src/image_util.cpp index 85242add4..c01161497 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -325,67 +325,6 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } -namespace detail { - -struct is_solid_visitor -{ - template - bool operator() (T const & data) - { - using pixel_type = typename T::pixel_type; - if (data.width() > 0 && data.height() > 0) - { - pixel_type const* first_row = data.getRow(0); - pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < data.height(); ++y) - { - pixel_type const * row = data.getRow(y); - for (unsigned x = 0; x < data.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; - } -}; - -template bool is_solid_visitor::operator() (image_data_rgba8 const& data); -template bool is_solid_visitor::operator() (image_data_gray8 const& data); -template bool is_solid_visitor::operator() (image_data_gray16 const& data); -template bool is_solid_visitor::operator() (image_data_gray32f const& data); -template bool is_solid_visitor::operator() (image_view_rgba8 const& data); -template bool is_solid_visitor::operator() (image_view_gray8 const& data); -template bool is_solid_visitor::operator() (image_view_gray16 const& data); -template bool is_solid_visitor::operator() (image_view_gray32f const& data); - -} // end detail ns - -template -bool is_solid(T const& image) -{ - return util::apply_visitor(detail::is_solid_visitor(), image); -} - -// Temporary until image_data_rgba8 is removed from passing -template <> -bool is_solid(image_data_rgba8 const& image) -{ - detail::is_solid_visitor visitor; - return visitor(image); -} - -// Temporary until image_view_rgba8 is removed from passing -template <> -bool is_solid(image_view_rgba8 const& image) -{ - detail::is_solid_visitor visitor; - return visitor(image); -} - // image_data_rgba8 template void save_to_file(image_data_rgba8 const&, std::string const&, @@ -458,6 +397,66 @@ template std::string save_to_string(image_data_any const&, std::string const&, rgba_palette const& palette); +namespace detail { + +struct is_solid_visitor +{ + template + bool operator() (T const & data) + { + using pixel_type = typename T::pixel_type; + if (data.width() > 0 && data.height() > 0) + { + pixel_type const* first_row = data.getRow(0); + pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type const * row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; + } +}; + +template bool is_solid_visitor::operator() (image_data_rgba8 const& data); +template bool is_solid_visitor::operator() (image_data_gray8 const& data); +template bool is_solid_visitor::operator() (image_data_gray16 const& data); +template bool is_solid_visitor::operator() (image_data_gray32f const& data); +template bool is_solid_visitor::operator() (image_view_rgba8 const& data); +template bool is_solid_visitor::operator() (image_view_gray8 const& data); +template bool is_solid_visitor::operator() (image_view_gray16 const& data); +template bool is_solid_visitor::operator() (image_view_gray32f const& data); + +} // end detail ns + +template +MAPNIK_DECL bool is_solid(T const& image) +{ + return util::apply_visitor(detail::is_solid_visitor(), image); +} + +// Temporary until image_data_rgba8 is removed from passing +template <> +MAPNIK_DECL bool is_solid(image_data_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + +// Temporary until image_view_rgba8 is removed from passing +template <> +MAPNIK_DECL bool is_solid(image_view_rgba8 const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} namespace detail { From 73d9c60168832a579fd993db2c0c3c04f7d07284 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 15 Jan 2015 10:53:21 -0600 Subject: [PATCH 31/91] Small fix for is solid to work with image_view_any and image_data_any properly. --- src/image_util.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/image_util.cpp b/src/image_util.cpp index c01161497..359ba06a6 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -434,6 +435,12 @@ template bool is_solid_visitor::operator() (image_view_gray8 c template bool is_solid_visitor::operator() (image_view_gray16 const& data); template bool is_solid_visitor::operator() (image_view_gray32f const& data); +template<> +bool is_solid_visitor::operator() (image_data_null const&) +{ + return true; +} + } // end detail ns template @@ -442,6 +449,9 @@ MAPNIK_DECL bool is_solid(T const& image) return util::apply_visitor(detail::is_solid_visitor(), image); } +template bool is_solid (image_data_any const&); +template bool is_solid (image_view_any const&); + // Temporary until image_data_rgba8 is removed from passing template <> MAPNIK_DECL bool is_solid(image_data_rgba8 const& image) From 4d3145991d8066031a9cbad41712ab02cba5cda1 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 15 Jan 2015 11:00:58 -0600 Subject: [PATCH 32/91] Removed some commented out code in src/image.cpp --- src/image.cpp | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/src/image.cpp b/src/image.cpp index f30d025f2..6e71b80c9 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -52,54 +52,10 @@ image image::read_from_file(std::string const& filename) return image(); } } -/* -namespace detail { - -struct save_to_file_visitor -{ - save_to_file_visitor(std::string const& filename, std::string const& format) - : filename_(filename), - format_(format) {} - - void operator() (image_data_rgba8 const& data) const - { - save_to_file(data,filename_, format_); - } - - void operator() (image_data_gray16 const& data) const - { - if (format_ == "tiff") // only TIFF supported - { - std::ofstream file (filename_.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); - if (file) - { - tiff_config config; - save_as_tiff(file, data, config); - } - else throw ImageWriterException("Could not write file to " + filename_ ); - } - else - { - throw std::runtime_error("Error: saving gray16 image as " + format_ + " is not supported"); - } - } - - template - void operator() (T const& data) const - { - throw std::runtime_error("Error: saving " + std::string(typeid(data).name()) + " as " + format_ + " is not supported"); - } - - std::string const& filename_; - std::string const& format_; -}; - -}*/ void image::save_to_file(std::string const& filename, std::string const& format) { mapnik::save_to_file(data_, filename, format); - //util::apply_visitor(detail::save_to_file_visitor(filename, format), data_); } } From 1f540b42c68c600973157e76e7dc9b5e9b332e4b Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 15 Jan 2015 13:01:32 -0600 Subject: [PATCH 33/91] Removed the set_rectangle_alpha code from image_32. Added new blend using composite to python bindings to replace it by doing src_over with composite. Ref #2633 --- bindings/python/mapnik_image.cpp | 6 ++- include/mapnik/graphics.hpp | 91 -------------------------------- 2 files changed, 4 insertions(+), 93 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 7577878c3..f26a091c9 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -189,9 +189,11 @@ std::shared_ptr frombuffer(PyObject * obj) } -void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float opacity) +void blend (image_32 & im, unsigned x, unsigned y, image_32 & im2, float opacity) { - im.set_rectangle_alpha2(im2.data(),x,y,opacity); + mapnik::premultiply_alpha(im.data()); + mapnik::premultiply_alpha(im2.data()); + mapnik::composite(im.data(),im2.data(),mapnik::src_over,opacity,x,y); } bool premultiplied(image_32 &im) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 3b13145c6..b1531cab1 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -157,97 +157,6 @@ public: } } - inline void set_rectangle_alpha(int x0,int y0,const image_data_rgba8& data) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0 + data.width(),y0 + data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - for (int x = box.minx(); x < box.maxx(); ++x) - { - unsigned rgba0 = row_to[x]; - unsigned rgba1 = row_from[x-x0]; - unsigned a1 = (rgba1 >> 24) & 0xff; - if (a1 == 0) continue; - if (a1 == 0xff) - { - row_to[x] = rgba1; - continue; - } - unsigned r1 = rgba1 & 0xff; - unsigned g1 = (rgba1 >> 8 ) & 0xff; - unsigned b1 = (rgba1 >> 16) & 0xff; - - unsigned a0 = (rgba0 >> 24) & 0xff; - unsigned r0 = (rgba0 & 0xff) * a0; - unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0; - unsigned b0 = ((rgba0 >> 16) & 0xff) * a0; - - a0 = ((a1 + a0) << 8) - a0*a1; - - r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0); - g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0); - b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0); - a0 = a0 >> 8; - row_to[x] = (a0 << 24)| (b0 << 16) | (g0 << 8) | (r0) ; - } - } - } - } - - inline void set_rectangle_alpha2(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0 + data.width(),y0 + data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - for (int x = box.minx(); x < box.maxx(); ++x) - { - unsigned rgba0 = row_to[x]; - unsigned rgba1 = row_from[x-x0]; - unsigned a1 = int( ((rgba1 >> 24) & 0xff) * opacity ); - if (a1 == 0) continue; - if (a1 == 0xff) - { - row_to[x] = rgba1; - continue; - } - unsigned r1 = rgba1 & 0xff; - unsigned g1 = (rgba1 >> 8 ) & 0xff; - unsigned b1 = (rgba1 >> 16) & 0xff; - - unsigned a0 = (rgba0 >> 24) & 0xff; - unsigned r0 = rgba0 & 0xff ; - unsigned g0 = (rgba0 >> 8 ) & 0xff; - unsigned b0 = (rgba0 >> 16) & 0xff; - - unsigned atmp = a1 + a0 - ((a1 * a0 + 255) >> 8); - if (atmp) - { - r0 = byte((r1 * a1 + (r0 * a0) - ((r0 * a0 * a1 + 255) >> 8)) / atmp); - g0 = byte((g1 * a1 + (g0 * a0) - ((g0 * a0 * a1 + 255) >> 8)) / atmp); - b0 = byte((b1 * a1 + (b0 * a0) - ((b0 * a0 * a1 + 255) >> 8)) / atmp); - } - a0 = byte(atmp); - - row_to[x] = (a0 << 24)| (b0 << 16) | (g0 << 8) | (r0) ; - } - } - } - } - template inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity) { From 3b1c99ff1b3b714c9be7c90b11347f15044ed13f Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 15 Jan 2015 17:57:21 -0600 Subject: [PATCH 34/91] Moved set_alpha to src/image_util.cpp and out of image_32. Added a boolean response to premultiply_alpha and demultiply_alpha so that if it is changed in set_alpha and other locations like the python bindings for composite that the image can be restored to its original state. Removed blend from python bindings. Ref #2633 --- bindings/python/mapnik_image.cpp | 38 ++++++----- include/mapnik/graphics.hpp | 2 - include/mapnik/image_util.hpp | 14 +++- src/graphics.cpp | 22 ------- src/image_util.cpp | 109 +++++++++++++++++++++++++++---- tests/python_tests/image_test.py | 12 +++- 6 files changed, 139 insertions(+), 58 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index f26a091c9..fe4a88a7e 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -188,12 +188,9 @@ std::shared_ptr frombuffer(PyObject * obj) throw mapnik::image_reader_exception("Failed to load image from buffer" ); } - -void blend (image_32 & im, unsigned x, unsigned y, image_32 & im2, float opacity) +void set_alpha(image_32 & im, float opacity) { - mapnik::premultiply_alpha(im.data()); - mapnik::premultiply_alpha(im2.data()); - mapnik::composite(im.data(),im2.data(),mapnik::src_over,opacity,x,y); + mapnik::set_alpha(im.data(), opacity); } bool premultiplied(image_32 &im) @@ -201,21 +198,29 @@ bool premultiplied(image_32 &im) return im.data().get_premultiplied(); } -void premultiply(image_32 & im) +bool premultiply(image_32 & im) { - mapnik::premultiply_alpha(im.data()); + return mapnik::premultiply_alpha(im.data()); } -void demultiply(image_32 & im) +bool demultiply(image_32 & im) { - mapnik::demultiply_alpha(im.data()); + return mapnik::demultiply_alpha(im.data()); } -void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity) +void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) { - mapnik::premultiply_alpha(dst.data()); - mapnik::premultiply_alpha(src.data()); - mapnik::composite(dst.data(),src.data(),mode,opacity,0,0); + bool demultiply_dst = mapnik::premultiply_alpha(dst.data()); + bool demultiply_src = mapnik::premultiply_alpha(src.data()); + mapnik::composite(dst.data(),src.data(),mode,opacity,dx,dy); + if (demultiply_dst) + { + mapnik::demultiply_alpha(dst.data()); + } + if (demultiply_src) + { + mapnik::demultiply_alpha(src.data()); + } } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) @@ -305,13 +310,14 @@ void export_image() &image_32::set_background, "The background color of the image.") .def("set_grayscale_to_alpha",&image_32::set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") .def("set_color_to_alpha",&image_32::set_color_to_alpha, "Set a given color to the alpha channel of the Image") - .def("set_alpha",&image_32::set_alpha, "Set the overall alpha channel of the Image") - .def("blend",&blend) + .def("set_alpha",&set_alpha, "Set the overall alpha channel of the Image") .def("composite",&composite, ( arg("self"), arg("image"), arg("mode")=mapnik::src_over, - arg("opacity")=1.0f + arg("opacity")=1.0f, + arg("dx")=0, + arg("dy")=0 )) .def("premultiplied",&premultiplied) .def("premultiply",&premultiply) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index b1531cab1..b864e07c4 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -78,8 +78,6 @@ public: void set_color_to_alpha(color const& c); - void set_alpha(float opacity); - inline const image_data_rgba8& data() const { return data_; diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 2c018a0bc..df932e377 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -28,6 +28,7 @@ #include #include #include +#include // boost #pragma GCC diagnostic push @@ -111,10 +112,10 @@ MAPNIK_DECL void save_to_stream ); template -MAPNIK_DECL void premultiply_alpha(T & image); +MAPNIK_DECL bool premultiply_alpha(T & image); template -MAPNIK_DECL void demultiply_alpha(T & image); +MAPNIK_DECL bool demultiply_alpha(T & image); template MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status); @@ -122,6 +123,15 @@ MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status); template MAPNIK_DECL bool is_solid (T const& image); +template +MAPNIK_DECL void set_alpha (T & image, float opacity); + +template +MAPNIK_DECL void set_grayscale_to_alpha (T const& image); + +template +MAPNIK_DECL void set_color_to_alpha (T const& image, color const& c); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/graphics.cpp b/src/graphics.cpp index 20f159f2b..c484f7d1f 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -92,28 +92,6 @@ void image_32::set_color_to_alpha(const color& c) } } -void image_32::set_alpha(float opacity) -{ - for (unsigned int y = 0; y < data_.height(); ++y) - { - unsigned int* row_to = data_.getRow(y); - for (unsigned int x = 0; x < data_.width(); ++x) - { - unsigned rgba = row_to[x]; - unsigned a0 = (rgba >> 24) & 0xff; - unsigned a1 = int( ((rgba >> 24) & 0xff) * opacity ); - //unsigned a1 = opacity; - if (a0 == a1) continue; - - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; - - row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; - } - } -} - void image_32::set_background(const color& c) { background_=c; diff --git a/src/image_util.cpp b/src/image_util.cpp index 359ba06a6..1d7219b3d 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -473,7 +474,7 @@ namespace detail { struct premultiply_visitor { template - void operator() (T & data) + bool operator() (T & data) { throw std::runtime_error("Error: Premultiply with " + std::string(typeid(data).name()) + " is not supported"); } @@ -481,7 +482,7 @@ struct premultiply_visitor }; template <> -void premultiply_visitor::operator() (image_data_rgba8 & data) +bool premultiply_visitor::operator() (image_data_rgba8 & data) { if (!data.get_premultiplied()) { @@ -489,13 +490,15 @@ void premultiply_visitor::operator() (image_data_rgba8 & data) agg::pixfmt_rgba32 pixf(buffer); pixf.premultiply(); data.set_premultiplied(true); + return true; } + return false; } struct demultiply_visitor { template - void operator() (T & data) + bool operator() (T & data) { throw std::runtime_error("Error: Premultiply with " + std::string(typeid(data).name()) + " is not supported"); } @@ -503,7 +506,7 @@ struct demultiply_visitor }; template <> -void demultiply_visitor::operator() (image_data_rgba8 & data) +bool demultiply_visitor::operator() (image_data_rgba8 & data) { if (data.get_premultiplied()) { @@ -511,7 +514,9 @@ void demultiply_visitor::operator() (image_data_rgba8 & data) agg::pixfmt_rgba32_pre pixf(buffer); pixf.demultiply(); data.set_premultiplied(false); + return true; } + return false; } struct set_premultiplied_visitor @@ -531,35 +536,35 @@ struct set_premultiplied_visitor } // end detail ns template -MAPNIK_DECL void premultiply_alpha(T & image) +MAPNIK_DECL bool premultiply_alpha(T & image) { - util::apply_visitor(detail::premultiply_visitor(), image); + return util::apply_visitor(detail::premultiply_visitor(), image); } -template void premultiply_alpha (image_data_any &); +template bool premultiply_alpha (image_data_any &); // Temporary, can be removed once image_view_any and image_data_any are the only ones passed template <> -MAPNIK_DECL void premultiply_alpha(image_data_rgba8 & image) +MAPNIK_DECL bool premultiply_alpha(image_data_rgba8 & image) { detail::premultiply_visitor visit; - visit(image); + return visit(image); } template -MAPNIK_DECL void demultiply_alpha(T & image) +MAPNIK_DECL bool demultiply_alpha(T & image) { - util::apply_visitor(detail::demultiply_visitor(), image); + return util::apply_visitor(detail::demultiply_visitor(), image); } -template void demultiply_alpha (image_data_any &); +template bool demultiply_alpha (image_data_any &); // Temporary, can be removed once image_view_any and image_data_any are the only ones passed template <> -MAPNIK_DECL void demultiply_alpha(image_data_rgba8 & image) +MAPNIK_DECL bool demultiply_alpha(image_data_rgba8 & image) { detail::demultiply_visitor visit; - visit(image); + return visit(image); } template @@ -578,4 +583,80 @@ MAPNIK_DECL void set_premultiplied_alpha(image_data_rgba8 & im visit(image); } +namespace detail { + +struct visitor_set_alpha +{ + visitor_set_alpha(float opacity) + : opacity_(opacity) {} + + template + void operator() (T & data) + { + throw std::runtime_error("Error: set_alpha with " + std::string(typeid(data).name()) + " is not supported"); + } + + private: + float opacity_; + +}; + +template <> +void visitor_set_alpha::operator() (image_data_rgba8 & data) +{ + using pixel_type = typename image_data_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) + { + pixel_type* row_to = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_to[x]; + pixel_type a0 = (rgba >> 24) & 0xff; + pixel_type a1 = pixel_type( ((rgba >> 24) & 0xff) * opacity_ ); + //unsigned a1 = opacity; + if (a0 == a1) continue; + + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; + } + } +} + +template <> +void visitor_set_alpha::operator() (image_data_null &) +{ + throw std::runtime_error("Can not set alpha for null image"); +} + +} // end detail ns + +template<> +MAPNIK_DECL void set_alpha (image_data_any & data, float opacity) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_alpha(opacity), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +// TEMPORARY can be removed once image_data_any is only way it is being passed. +template<> +MAPNIK_DECL void set_alpha (image_data_rgba8 & data, float opacity) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_alpha visit(opacity); + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + } // end ns diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index 6e0fa66b7..ac94f76c8 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -15,9 +15,17 @@ def setup(): def test_image_premultiply(): im = mapnik.Image(256,256) eq_(im.premultiplied(),False) - im.premultiply() + # Premultiply should return true that it worked + eq_(im.premultiply(), True) eq_(im.premultiplied(),True) - im.demultiply() + # Premultipling again should return false as nothing should happen + eq_(im.premultiply(), False) + eq_(im.premultiplied(),True) + # Demultiply should return true that it worked + eq_(im.demultiply(), True) + eq_(im.premultiplied(),False) + # Demultiply again should not work and return false as it did nothing + eq_(im.demultiply(), False) eq_(im.premultiplied(),False) @raises(RuntimeError) From 33ccc123559d3e81cca1f64a4fb683edfb9d0fa8 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 15 Jan 2015 20:26:20 -0600 Subject: [PATCH 35/91] Moved set_color_to_alpha and set_grayscale_to_alpha to image_util. Ref # 2633 --- bindings/python/mapnik_image.cpp | 15 +++- include/mapnik/graphics.hpp | 4 - include/mapnik/image_util.hpp | 4 +- src/graphics.cpp | 39 --------- src/image_util.cpp | 134 +++++++++++++++++++++++++++++-- 5 files changed, 143 insertions(+), 53 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index fe4a88a7e..9fcf78235 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -36,6 +36,7 @@ // mapnik #include +#include #include #include #include @@ -188,6 +189,16 @@ std::shared_ptr frombuffer(PyObject * obj) throw mapnik::image_reader_exception("Failed to load image from buffer" ); } +void set_grayscale_to_alpha(image_32 & im) +{ + mapnik::set_grayscale_to_alpha(im.data()); +} + +void set_color_to_alpha(image_32 & im, mapnik::color const& c) +{ + mapnik::set_color_to_alpha(im.data(), c); +} + void set_alpha(image_32 & im, float opacity) { mapnik::set_alpha(im.data(), opacity); @@ -308,8 +319,8 @@ void export_image() .add_property("background",make_function (&image_32::get_background,return_value_policy()), &image_32::set_background, "The background color of the image.") - .def("set_grayscale_to_alpha",&image_32::set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") - .def("set_color_to_alpha",&image_32::set_color_to_alpha, "Set a given color to the alpha channel of the Image") + .def("set_grayscale_to_alpha",&set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") + .def("set_color_to_alpha",&set_color_to_alpha, "Set a given color to the alpha channel of the Image") .def("set_alpha",&set_alpha, "Set the overall alpha channel of the Image") .def("composite",&composite, ( arg("self"), diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index b864e07c4..e1815813c 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -74,10 +74,6 @@ public: void set_background(const color& c); - void set_grayscale_to_alpha(); - - void set_color_to_alpha(color const& c); - inline const image_data_rgba8& data() const { return data_; diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index df932e377..e4b39adb7 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -127,10 +127,10 @@ template MAPNIK_DECL void set_alpha (T & image, float opacity); template -MAPNIK_DECL void set_grayscale_to_alpha (T const& image); +MAPNIK_DECL void set_grayscale_to_alpha (T & image); template -MAPNIK_DECL void set_color_to_alpha (T const& image, color const& c); +MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); inline bool is_png(std::string const& filename) { diff --git a/src/graphics.cpp b/src/graphics.cpp index c484f7d1f..205c2c74d 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -53,45 +53,6 @@ image_32::image_32(image_data_rgba8 && data) image_32::~image_32() {} -void image_32::set_grayscale_to_alpha() -{ - for (unsigned int y = 0; y < data_.height(); ++y) - { - unsigned int* row_from = data_.getRow(y); - for (unsigned int x = 0; x < data_.width(); ++x) - { - unsigned rgba = row_from[x]; - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; - - // magic numbers for grayscale - unsigned a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); - - row_from[x] = (a << 24)| (255 << 16) | (255 << 8) | (255) ; - } - } -} - -void image_32::set_color_to_alpha(const color& c) -{ - for (unsigned y = 0; y < data_.height(); ++y) - { - unsigned int* row_from = data_.getRow(y); - for (unsigned x = 0; x < data_.width(); ++x) - { - unsigned rgba = row_from[x]; - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; - if (r == c.red() && g == c.green() && b == c.blue()) - { - row_from[x] = 0; - } - } - } -} - void image_32::set_background(const color& c) { background_=c; diff --git a/src/image_util.cpp b/src/image_util.cpp index 1d7219b3d..fb7adaa02 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -625,12 +625,6 @@ void visitor_set_alpha::operator() (image_data_rgba8 & data) } } -template <> -void visitor_set_alpha::operator() (image_data_null &) -{ - throw std::runtime_error("Can not set alpha for null image"); -} - } // end detail ns template<> @@ -659,4 +653,132 @@ MAPNIK_DECL void set_alpha (image_data_rgba8 & data, float opa } } +namespace detail { + +struct visitor_set_grayscale_to_alpha +{ + template + void operator() (T & data) + { + throw std::runtime_error("Error: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported"); + } +}; + +template <> +void visitor_set_grayscale_to_alpha::operator() (image_data_rgba8 & data) +{ + using pixel_type = typename image_data_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + // magic numbers for grayscale + pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); + + row_from[x] = (a << 24)| (255 << 16) | (255 << 8) | (255) ; + } + } +} + +} // end detail ns + +template<> +MAPNIK_DECL void set_grayscale_to_alpha (image_data_any & data) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_grayscale_to_alpha(), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +// TEMPORARY can be removed once image_data_any is only way it is being passed. +template<> +MAPNIK_DECL void set_grayscale_to_alpha (image_data_rgba8 & data) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_grayscale_to_alpha visit; + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +namespace detail { + +struct visitor_set_color_to_alpha +{ + visitor_set_color_to_alpha(color const& c) + : c_(c) {} + + template + void operator() (T & data) + { + throw std::runtime_error("Error: set_color_to_alpha with " + std::string(typeid(data).name()) + " is not supported"); + } + + private: + color const& c_; + +}; + +template <> +void visitor_set_color_to_alpha::operator() (image_data_rgba8 & data) +{ + using pixel_type = typename image_data_rgba8::pixel_type; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + if (r == c_.red() && g == c_.green() && b == c_.blue()) + { + row_from[x] = 0; + } + } + } +} + +} // end detail ns + +template<> +MAPNIK_DECL void set_color_to_alpha (image_data_any & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_color_to_alpha(c), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +// TEMPORARY can be removed once image_data_any is only way it is being passed. +template<> +MAPNIK_DECL void set_color_to_alpha (image_data_rgba8 & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_color_to_alpha visit(c); + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + } // end ns From 5bc83eee49c5c935508d784bac620d47364e94ba Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 15 Jan 2015 21:03:42 -0600 Subject: [PATCH 36/91] Added a new test for set_color_to_alpha --- tests/python_tests/image_test.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index ac94f76c8..94c8e8853 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -5,7 +5,7 @@ import sys import os, mapnik from timeit import Timer, time from nose.tools import * -from utilities import execution_path, run_all +from utilities import execution_path, run_all, get_unique_colors def setup(): # All of the paths used are relative, if we run the tests @@ -28,6 +28,13 @@ def test_image_premultiply(): eq_(im.demultiply(), False) eq_(im.premultiplied(),False) +def test_set_color_to_alpha(): + im = mapnik.Image(256,256) + im.background = mapnik.Color('rgba(12,12,12,255)') + eq_(get_unique_colors(im), ['rgba(12,12,12,255)']) + im.set_color_to_alpha(mapnik.Color('rgba(12,12,12,0)')) + eq_(get_unique_colors(im), ['rgba(0,0,0,0)']) + @raises(RuntimeError) def test_negative_image_dimensions(): # TODO - this may have regressed in https://github.com/mapnik/mapnik/commit/4f3521ac24b61fc8ae8fd344a16dc3a5fdf15af7 From aebb6fee5859ef33e242b2bc842443f6fd5fc146 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 16 Jan 2015 13:06:52 -0600 Subject: [PATCH 37/91] Removed the background and set/get background from image_32 class. Removed clear method from image_32. Added new fill method for image_data_any, that allows many generic types to fill an image. Ref #2633 --- bindings/python/mapnik_image.cpp | 16 +++- include/mapnik/graphics.hpp | 10 --- include/mapnik/image_data_any.hpp | 4 +- include/mapnik/image_util.hpp | 3 + src/agg/agg_renderer.cpp | 8 +- src/graphics.cpp | 11 --- src/image_util.cpp | 82 +++++++++++++++++++ tests/cpp_tests/map_request_test.cpp | 4 +- tests/python_tests/buffer_clear_test.py | 2 +- tests/python_tests/compositing_test.py | 4 +- tests/python_tests/grayscale_test.py | 2 +- .../python_tests/image_encoding_speed_test.py | 2 +- tests/python_tests/image_test.py | 6 +- tests/python_tests/image_tiff_test.py | 10 +-- tests/python_tests/png_encoding_test.py | 4 +- tests/python_tests/render_test.py | 12 +-- tests/python_tests/webp_encoding_test.py | 4 +- 17 files changed, 129 insertions(+), 55 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 9fcf78235..3b6156c7f 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -125,6 +125,11 @@ bool is_solid(mapnik::image_32 const& im) return mapnik::is_solid(im.data()); } +void background(mapnik::image_32 & im, mapnik::color const& c) +{ + mapnik::fill(im.data(), c); +} + unsigned get_pixel(mapnik::image_32 const& im, int x, int y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) @@ -219,6 +224,11 @@ bool demultiply(image_32 & im) return mapnik::demultiply_alpha(im.data()); } +void clear(image_32 & im) +{ + mapnik::fill(im.data(), 0); +} + void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) { bool demultiply_dst = mapnik::premultiply_alpha(dst.data()); @@ -316,9 +326,7 @@ void export_image() .def("view",&image_32::get_view) .def("painted",&painted) .def("is_solid",&is_solid) - .add_property("background",make_function - (&image_32::get_background,return_value_policy()), - &image_32::set_background, "The background color of the image.") + .def("background",&background, "Set the background color of the image.") .def("set_grayscale_to_alpha",&set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") .def("set_color_to_alpha",&set_color_to_alpha, "Set a given color to the alpha channel of the Image") .def("set_alpha",&set_alpha, "Set the overall alpha channel of the Image") @@ -335,7 +343,7 @@ void export_image() .def("demultiply",&demultiply) .def("set_pixel",&set_pixel) .def("get_pixel",&get_pixel) - .def("clear",&image_32::clear) + .def("clear",&clear) //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3 .def("tostring",&tostring1) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index e1815813c..dccbdaeea 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -46,7 +46,6 @@ class MAPNIK_DECL image_32 { private: image_data_rgba8 data_; - boost::optional background_; bool painted_; public: using pixel_type = typename image_data_rgba8::pixel_type; @@ -65,15 +64,6 @@ public: return painted_; } - inline void clear() - { - std::fill(data_.getData(), data_.getData() + data_.width() * data_.height(), 0); - } - - boost::optional const& get_background() const; - - void set_background(const color& c); - inline const image_data_rgba8& data() const { return data_; diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index 241e65db0..072688c46 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -29,13 +29,15 @@ namespace mapnik { struct image_data_null -{ +{ + using pixel_type = uint8_t; unsigned char const* getBytes() const { return nullptr; } unsigned char* getBytes() { return nullptr;} std::size_t width() const { return 0; } std::size_t height() const { return 0; } bool get_premultiplied() const { return false; } void set_premultiplied(bool) const {} + void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image_data"); } }; using image_data_base = util::variant MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); +template +MAPNIK_DECL void fill (T1 & data, T2 const& c); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index f11a02330..f34c6aee4 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -119,11 +119,11 @@ void agg_renderer::setup(Map const &m) { mapnik::color bg_color = *bg; bg_color.premultiply(); - pixmap_.set_background(bg_color); + mapnik::fill(pixmap_.data(), bg_color); } else { - pixmap_.set_background(*bg); + mapnik::fill(pixmap_.data(),*bg); } } @@ -237,7 +237,7 @@ void agg_renderer::start_style_processing(feature_type_style const& st) } else { - internal_buffer_->set_background(color(0,0,0,0)); // fill with transparent colour + mapnik::fill(internal_buffer_->data(), 0); // fill with transparent colour } } else @@ -248,7 +248,7 @@ void agg_renderer::start_style_processing(feature_type_style const& st) } else { - internal_buffer_->set_background(color(0,0,0,0)); // fill with transparent colour + mapnik::fill(internal_buffer_->data(), 0); // fill with transparent colour } common_.t_.set_offset(0); ras_ptr->clip_box(0,0,common_.width_,common_.height_); diff --git a/src/graphics.cpp b/src/graphics.cpp index 205c2c74d..fdeae0007 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -53,17 +53,6 @@ image_32::image_32(image_data_rgba8 && data) image_32::~image_32() {} -void image_32::set_background(const color& c) -{ - background_=c; - data_.set(background_->rgba()); -} - -boost::optional const& image_32::get_background() const -{ - return background_; -} - void image_32::composite_pixel(unsigned op, int x,int y, unsigned c, unsigned cover, double opacity) { using color_type = agg::rgba8; diff --git a/src/image_util.cpp b/src/image_util.cpp index fb7adaa02..3da3c7fc2 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -781,4 +781,86 @@ MAPNIK_DECL void set_color_to_alpha (image_data_rgba8 & data, } } +namespace detail { + +template +struct visitor_fill +{ + visitor_fill(T1 const& val) + : val_(val) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val = static_cast(val_); + data.set(val); + } + + private: + T1 const& val_; +}; + +template<> +struct visitor_fill +{ + visitor_fill(color const& val) + : val_(val) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val = static_cast(val_.rgba()); + data.set(val); + } + + private: + color const& val_; +}; + +} // end detail ns + +// For all the generic data types. +template +MAPNIK_DECL void fill (T1 & data, T2 const& val) +{ + util::apply_visitor(detail::visitor_fill(val), data); +} + +template void fill(image_data_any &, color const&); +template void fill(image_data_any &, uint32_t const&); +template void fill(image_data_any &, int32_t const&); +template void fill(image_data_any &, uint16_t const&); +template void fill(image_data_any &, int16_t const&); +template void fill(image_data_any &, uint8_t const&); +template void fill(image_data_any &, int8_t const&); +template void fill(image_data_any &, float const&); +template void fill(image_data_any &, double const&); + + +// Temporary remove these later! +template <> +MAPNIK_DECL void fill (image_data_rgba8 & data , color const& val) +{ + detail::visitor_fill visitor(val); + visitor(data); +} + +// Temporary remove these later! +template <> +MAPNIK_DECL void fill (image_data_rgba8 & data , uint32_t const& val) +{ + detail::visitor_fill visitor(val); + visitor(data); +} + +// Temporary remove these later! +template <> +MAPNIK_DECL void fill (image_data_rgba8 & data , int32_t const& val) +{ + detail::visitor_fill visitor(val); + visitor(data); +} + } // end ns diff --git a/tests/cpp_tests/map_request_test.cpp b/tests/cpp_tests/map_request_test.cpp index b7f2deb64..52159d0d4 100644 --- a/tests/cpp_tests/map_request_test.cpp +++ b/tests/cpp_tests/map_request_test.cpp @@ -92,7 +92,7 @@ int main(int argc, char** argv) //BOOST_TEST(compare_images(actual1,expected)); // reset image - im.clear(); + mapnik::fill(im.data(), 0); // set up a mapnik::request object mapnik::request req(m.width(),m.height(),m.get_current_extent()); @@ -109,7 +109,7 @@ int main(int argc, char** argv) //BOOST_TEST(compare_images(actual2,expected)); // reset image - im.clear(); + mapnik::fill(im.data(), 0); // render with apply_to_layer api and mapnik::request params passed to apply_to_layer mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); diff --git a/tests/python_tests/buffer_clear_test.py b/tests/python_tests/buffer_clear_test.py index 495acff3b..c48130731 100644 --- a/tests/python_tests/buffer_clear_test.py +++ b/tests/python_tests/buffer_clear_test.py @@ -15,7 +15,7 @@ def test_clearing_image_data(): bytes = im.tostring() eq_(im.tostring(),bytes) # set background, then clear - im.background = mapnik.Color('green') + im.background(mapnik.Color('green')) eq_(im.tostring()!=bytes,True) # clear image, should now equal original im.clear() diff --git a/tests/python_tests/compositing_test.py b/tests/python_tests/compositing_test.py index bf10ff7be..fc05525e6 100644 --- a/tests/python_tests/compositing_test.py +++ b/tests/python_tests/compositing_test.py @@ -241,10 +241,10 @@ def test_background_image_with_alpha_and_background_color_against_composited_con mapnik.render(m,im) # create and composite the expected result im1 = mapnik.Image(10,10) - im1.background = mapnik.Color('rgba(255,255,255,.5)') + im1.background(mapnik.Color('rgba(255,255,255,.5)')) im1.premultiply() im2 = mapnik.Image(10,10) - im2.background = mapnik.Color('rgba(255,255,0,.5)') + im2.background(mapnik.Color('rgba(255,255,0,.5)')) im2.premultiply() im1.composite(im2) im1.demultiply() diff --git a/tests/python_tests/grayscale_test.py b/tests/python_tests/grayscale_test.py index de1fa4716..cce8c6e31 100644 --- a/tests/python_tests/grayscale_test.py +++ b/tests/python_tests/grayscale_test.py @@ -4,7 +4,7 @@ from utilities import execution_path, run_all def test_grayscale_conversion(): im = mapnik.Image(2,2) - im.background = mapnik.Color('white') + im.background(mapnik.Color('white')) im.set_grayscale_to_alpha() pixel = im.get_pixel(0,0) eq_((pixel >> 24) & 0xff,255); diff --git a/tests/python_tests/image_encoding_speed_test.py b/tests/python_tests/image_encoding_speed_test.py index 51dedc44d..6fa9f8f06 100644 --- a/tests/python_tests/image_encoding_speed_test.py +++ b/tests/python_tests/image_encoding_speed_test.py @@ -88,7 +88,7 @@ def do_encoding(): def solid(): return eval('image.tostring("%s")' % c) solid_im = mapnik.Image(512,512) - solid_im.background = mapnik.Color("#f2efe9") + solid_im.background(mapnik.Color("#f2efe9")) for c in combinations: t = Timer(solid) run(solid,solid_im,c,t) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index 94c8e8853..a4b944bb9 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -30,7 +30,7 @@ def test_image_premultiply(): def test_set_color_to_alpha(): im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(12,12,12,255)') + im.background(mapnik.Color('rgba(12,12,12,255)')) eq_(get_unique_colors(im), ['rgba(12,12,12,255)']) im.set_color_to_alpha(mapnik.Color('rgba(12,12,12,0)')) eq_(get_unique_colors(im), ['rgba(0,0,0,0)']) @@ -43,7 +43,7 @@ def test_negative_image_dimensions(): def test_jpeg_round_trip(): filepath = '/tmp/mapnik-jpeg-io.jpeg' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'jpeg') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -59,7 +59,7 @@ def test_jpeg_round_trip(): def test_png_round_trip(): filepath = '/tmp/mapnik-png-io.png' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'png') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index ad37103be..036d22ff4 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -15,7 +15,7 @@ def setup(): def test_tiff_round_trip_scanline(): filepath = '/tmp/mapnik-tiff-io-scanline.tiff' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) org_str = len(im.tostring()) im.save(filepath,'tiff:method=scanline') im2 = mapnik.Image.open(filepath) @@ -33,7 +33,7 @@ def test_tiff_round_trip_scanline(): def test_tiff_round_trip_stripped(): filepath = '/tmp/mapnik-tiff-io-stripped.tiff' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) org_str = len(im.tostring()) im.save(filepath,'tiff:method=stripped') im2 = mapnik.Image.open(filepath) @@ -51,7 +51,7 @@ def test_tiff_round_trip_stripped(): def test_tiff_round_trip_rows_stripped(): filepath = '/tmp/mapnik-tiff-io-stripped.tiff' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) org_str = len(im.tostring()) im.save(filepath,'tiff:method=stripped:rows_per_strip=8') im2 = mapnik.Image.open(filepath) @@ -71,7 +71,7 @@ def test_tiff_round_trip_buffered_tiled(): filepath2 = '/tmp/mapnik-tiff-io-buffered-tiled2.tiff' im = mapnik.Image(255,267) #im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'tiff:method=tiled:tile_width=32:tile_height=32') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -91,7 +91,7 @@ def test_tiff_round_trip_buffered_tiled(): def test_tiff_round_trip_tiled(): filepath = '/tmp/mapnik-tiff-io-tiled.tiff' im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.background(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'tiff:method=tiled') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) diff --git a/tests/python_tests/png_encoding_test.py b/tests/python_tests/png_encoding_test.py index 82adf1e3f..89bb02ad8 100644 --- a/tests/python_tests/png_encoding_test.py +++ b/tests/python_tests/png_encoding_test.py @@ -61,7 +61,7 @@ if mapnik.has_png(): '%s (actual) not == to %s (expected)' % (actual,expected)) # solid image - im.background = mapnik.Color('green'); + im.background(mapnik.Color('green')) for opt in opts: expected = gen_filepath('blank',opt) actual = os.path.join(tmp_dir,os.path.basename(expected)) @@ -91,7 +91,7 @@ if mapnik.has_png(): def test_transparency_levels(): # create partial transparency image im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(255,255,255,.5)') + im.background(mapnik.Color('rgba(255,255,255,.5)')) c2 = mapnik.Color('rgba(255,255,0,.2)') c3 = mapnik.Color('rgb(0,255,255)') for y in range(0,im.height()/2): diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index aa5054a46..5fa4dd463 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -25,7 +25,7 @@ def test_simplest_render(): def test_render_image_to_string(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.background(mapnik.Color('black')) eq_(im.painted(),False) eq_(im.is_solid(),True) s = im.tostring() @@ -33,7 +33,7 @@ def test_render_image_to_string(): def test_non_solid_image(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.background(mapnik.Color('black')) eq_(im.painted(),False) eq_(im.is_solid(),True) # set one pixel to a different color @@ -43,7 +43,7 @@ def test_non_solid_image(): def test_non_solid_image_view(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.background(mapnik.Color('black')) view = im.view(0,0,256,256) eq_(view.is_solid(),True) # set one pixel to a different color @@ -61,13 +61,13 @@ def test_setting_alpha(): im1 = mapnik.Image(w,h) # white, half transparent c1 = mapnik.Color('rgba(255,255,255,.5)') - im1.background = c1 + im1.background(c1) eq_(im1.painted(),False) eq_(im1.is_solid(),True) # pure white im2 = mapnik.Image(w,h) c2 = mapnik.Color('rgba(255,255,255,1)') - im2.background = c2 + im2.background(c2) im2.set_alpha(c1.a/255.0) eq_(im2.painted(),False) eq_(im2.is_solid(),True) @@ -75,7 +75,7 @@ def test_setting_alpha(): def test_render_image_to_file(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.background(mapnik.Color('black')) if mapnik.has_jpeg(): im.save('test.jpg') im.save('test.png', 'png') diff --git a/tests/python_tests/webp_encoding_test.py b/tests/python_tests/webp_encoding_test.py index d01459436..8f2ebf630 100644 --- a/tests/python_tests/webp_encoding_test.py +++ b/tests/python_tests/webp_encoding_test.py @@ -84,7 +84,7 @@ if mapnik.has_webp(): for opt in opts: im = mapnik.Image(256,256) - im.background = mapnik.Color('green') + im.background(mapnik.Color('green')) expected = gen_filepath('solid',opt) actual = os.path.join(tmp_dir,os.path.basename(expected)) if generate or not os.path.exists(expected): @@ -125,7 +125,7 @@ if mapnik.has_webp(): try: # create partial transparency image im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(255,255,255,.5)') + im.background(mapnik.Color('rgba(255,255,255,.5)')) c2 = mapnik.Color('rgba(255,255,0,.2)') c3 = mapnik.Color('rgb(0,255,255)') for y in range(0,im.height()/2): From a7b8ca28882dc6de2680fa6ac7ea0cbc85ad25f8 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 16 Jan 2015 15:36:53 -0600 Subject: [PATCH 38/91] Moved set_rectangle out of image_32 into image_util. Ref #2633 --- include/mapnik/graphics.hpp | 24 ---------- include/mapnik/image_util.hpp | 3 ++ src/image_util.cpp | 84 +++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index dccbdaeea..6faae9927 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -117,30 +117,6 @@ public: return data_.height(); } - inline void set_rectangle(int x0,int y0,image_data_rgba8 const& data) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0+data.width(),y0+data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - - for (int x = box.minx(); x < box.maxx(); ++x) - { - if (row_from[x-x0] & 0xff000000) - { - row_to[x] = row_from[x-x0]; - } - } - } - } - } - template inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity) { diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index c96e879cc..8b7f1e0c2 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -135,6 +135,9 @@ MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); template MAPNIK_DECL void fill (T1 & data, T2 const& c); +template +MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/image_util.cpp b/src/image_util.cpp index 3da3c7fc2..761d2f2cf 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -863,4 +863,88 @@ MAPNIK_DECL void fill (image_data_rgba8 & data , int3 visitor(data); } +namespace detail { + +struct visitor_set_rectangle +{ + visitor_set_rectangle(image_data_any const & src, int x0, int y0) + : src_(src), x0_(x0), y0_(y0) {} + + template + void operator() (T & dst) + { + using pixel_type = typename T::pixel_type; + T src = util::get(src_); + box2d ext0(0,0,dst.width(),dst.height()); + box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); + + if (ext0.intersects(ext1)) + { + box2d box = ext0.intersect(ext1); + for (std::size_t y = box.miny(); y < box.maxy(); ++y) + { + pixel_type* row_to = dst.getRow(y); + pixel_type const * row_from = src.getRow(y-y0_); + + for (std::size_t x = box.minx(); x < box.maxx(); ++x) + { + row_to[x] = row_from[x-x0_]; + } + } + } + } + private: + image_data_any const& src_; + int x0_; + int y0_; +}; + +template <> +void visitor_set_rectangle::operator() (image_data_rgba8 & dst) +{ + using pixel_type = typename image_data_rgba8::pixel_type; + image_data_rgba8 src = util::get(src_); + box2d ext0(0,0,dst.width(),dst.height()); + box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); + + if (ext0.intersects(ext1)) + { + box2d box = ext0.intersect(ext1); + for (std::size_t y = box.miny(); y < box.maxy(); ++y) + { + pixel_type* row_to = dst.getRow(y); + pixel_type const * row_from = src.getRow(y-y0_); + + for (std::size_t x = box.minx(); x < box.maxx(); ++x) + { + if (row_from[x-x0_] & 0xff000000) // Don't change if alpha == 0 + { + row_to[x] = row_from[x-x0_]; + } + } + } + } +} + +template<> +void visitor_set_rectangle::operator() (image_data_null &) +{ + throw std::runtime_error("Set rectangle not support for null images"); +} + +} // end detail ns + +template +void set_rectangle (T & dst, T const& src, int x, int y) +{ + detail::visitor_set_rectangle visit(src, x, y); + visit(dst); +} + +template <> +void set_rectangle (image_data_any & dst, image_data_any const& src, int x, int y) +{ + util::apply_visitor(detail::visitor_set_rectangle(src, x, y), dst); +} + } // end ns From 0b2c4e57cf1a8c1ae0716b74e119567e41ee6bcc Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 16 Jan 2015 16:04:02 -0600 Subject: [PATCH 39/91] Merge_rectangle has met the wood chipper. Ref #2633 --- include/mapnik/graphics.hpp | 41 ------------------------------------- 1 file changed, 41 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 6faae9927..64a246d4a 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -117,47 +117,6 @@ public: return data_.height(); } - template - inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0 + data.width(),y0 + data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - for (int x = box.minx(); x < box.maxx(); ++x) - { - unsigned rgba0 = row_to[x]; - unsigned rgba1 = row_from[x-x0]; - unsigned a1 = int( ((rgba1 >> 24) & 0xff) * opacity ); - if (a1 == 0) continue; - unsigned r1 = rgba1 & 0xff; - unsigned g1 = (rgba1 >> 8 ) & 0xff; - unsigned b1 = (rgba1 >> 16) & 0xff; - - unsigned a0 = (rgba0 >> 24) & 0xff; - unsigned r0 = rgba0 & 0xff ; - unsigned g0 = (rgba0 >> 8 ) & 0xff; - unsigned b0 = (rgba0 >> 16) & 0xff; - - unsigned a = (a1 * 255 + (255 - a1) * a0 + 127)/255; - - MergeMethod::mergeRGB(r0,g0,b0,r1,g1,b1); - - r0 = (r1*a1 + (((255 - a1) * a0 + 127)/255) * r0 + 127)/a; - g0 = (g1*a1 + (((255 - a1) * a0 + 127)/255) * g0 + 127)/a; - b0 = (b1*a1 + (((255 - a1) * a0 + 127)/255) * b0 + 127)/a; - - row_to[x] = (a << 24)| (b0 << 16) | (g0 << 8) | (r0) ; - } - } - } - } }; } From 1470bea9cb106f6c0296fea184062677cd619ddd Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 16 Jan 2015 16:48:43 -0600 Subject: [PATCH 40/91] Migrated composite_pixel out of image_32, it is now in image_utils. Ref #2633 --- include/mapnik/graphics.hpp | 2 - include/mapnik/image_util.hpp | 9 +++++ src/graphics.cpp | 19 ---------- src/image_util.cpp | 71 ++++++++++++++++++++++++++++++++++- src/text/renderer.cpp | 23 ++++++------ 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 64a246d4a..2fa5e5770 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -105,8 +105,6 @@ public: } } - void composite_pixel(unsigned op, int x,int y,unsigned c, unsigned cover, double opacity); - inline unsigned width() const { return data_.width(); diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 8b7f1e0c2..9691a3438 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -138,6 +138,15 @@ MAPNIK_DECL void fill (T1 & data, T2 const& c); template MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); +template +MAPNIK_DECL bool check_bounds (T const& data, int x, int y) +{ + return (x >= 0 && x < static_cast(data.width()) && y >= 0 && y < static_cast(data.height())); +} + +template +MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/graphics.cpp b/src/graphics.cpp index fdeae0007..48664835b 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -53,23 +53,4 @@ image_32::image_32(image_data_rgba8 && data) image_32::~image_32() {} -void image_32::composite_pixel(unsigned op, int x,int y, unsigned c, unsigned cover, double opacity) -{ - using color_type = agg::rgba8; - using value_type = color_type::value_type; - using order_type = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba; - - if (checkBounds(x,y)) - { - unsigned rgba = data_(x,y); - unsigned ca = (unsigned)(((c >> 24) & 0xff) * opacity); - unsigned cb = (c >> 16 ) & 0xff; - unsigned cg = (c >> 8) & 0xff; - unsigned cr = (c & 0xff); - blender_type::blend_pix(op, (value_type*)&rgba, cr, cg, cb, ca, cover); - data_(x,y) = rgba; - } -} - } diff --git a/src/image_util.cpp b/src/image_util.cpp index 761d2f2cf..b8978d936 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -935,16 +935,83 @@ void visitor_set_rectangle::operator() (image_data_null &) } // end detail ns template -void set_rectangle (T & dst, T const& src, int x, int y) +MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x, int y) { detail::visitor_set_rectangle visit(src, x, y); visit(dst); } template <> -void set_rectangle (image_data_any & dst, image_data_any const& src, int x, int y) +MAPNIK_DECL void set_rectangle (image_data_any & dst, image_data_any const& src, int x, int y) { util::apply_visitor(detail::visitor_set_rectangle(src, x, y), dst); } +namespace detail +{ + +struct visitor_composite_pixel +{ + // Obviously c variable would only work for rgba8 currently, but didn't want to + // make this a template class until new rgba types exist. + visitor_composite_pixel(unsigned op, int x,int y, unsigned c, unsigned cover, double opacity) + : opacity_(opacity), + op_(op), + x_(x), + y_(y), + c_(c), + cover_(cover) {} + + template + void operator() (T & data) + { + throw std::runtime_error("Composite pixel is not supported for this data type"); + } + + private: + double opacity_; + unsigned op_; + int x_; + int y_; + int c_; + unsigned cover_; + +}; + +template<> +void visitor_composite_pixel::operator() (image_data_rgba8 & data) +{ + using color_type = agg::rgba8; + using value_type = color_type::value_type; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba; + + if (mapnik::check_bounds(data, x_, y_)) + { + unsigned rgba = data(x_,y_); + unsigned ca = (unsigned)(((c_ >> 24) & 0xff) * opacity_); + unsigned cb = (c_ >> 16 ) & 0xff; + unsigned cg = (c_ >> 8) & 0xff; + unsigned cr = (c_ & 0xff); + blender_type::blend_pix(op_, (value_type*)&rgba, cr, cg, cb, ca, cover_); + data(x_,y_) = rgba; + } +} + +} // end detail ns + +template +MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +{ + util::apply_visitor(detail::visitor_composite_pixel(op, x, y, c, cover, opacity), data); +} + +// Temporary delete later +template <> +MAPNIK_DECL void composite_pixel(image_data_rgba8 & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +{ + detail::visitor_composite_pixel visitor(op, x, y, c, cover, opacity); + visitor(data); +} + } // end ns diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index b57c2d8ef..c44010ac6 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace mapnik { @@ -102,7 +103,7 @@ void composite_bitmap(T & pixmap, FT_Bitmap *bitmap, unsigned rgba, int x, int y unsigned gray=bitmap->buffer[q*bitmap->width+p]; if (gray) { - pixmap.composite_pixel(comp_op, i, j, rgba, gray, opacity); + mapnik::composite_pixel(pixmap.data(), comp_op, i, j, rgba, gray, opacity); } } } @@ -291,17 +292,17 @@ void agg_text_renderer::render_halo(FT_Bitmap *bitmap, int gray = bitmap->buffer[y*bitmap->width+x]; if (gray) { - pixmap_.composite_pixel(comp_op, x+x1-1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1, y+y1-1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1+1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1-1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1, y+y1-1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1-1, y+y1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1, y+y1, rgba, gray, opacity); - pixmap_.composite_pixel(comp_op, x+x1+1, y+y1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1-1, y+y1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1, y+y1, rgba, gray, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+1, y+y1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1-1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1, y+y1+1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1+1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1-1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1, y+y1+1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); } } } @@ -317,7 +318,7 @@ void agg_text_renderer::render_halo(FT_Bitmap *bitmap, { for (int n=-halo_radius; n <=halo_radius; ++n) for (int m=-halo_radius; m <= halo_radius; ++m) - pixmap_.composite_pixel(comp_op, x+x1+m, y+y1+n, rgba, gray, opacity); + mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+m, y+y1+n, rgba, gray, opacity); } } } From a002139e186c4a85ad7ab3ef1b7130f6ec5df347 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 16 Jan 2015 18:26:56 -0600 Subject: [PATCH 41/91] Added set_pixel to visitor pattern and moved it to image_util. Added exception throwing in composite only if debug flags are on. Ref #2633 --- bindings/python/mapnik_image.cpp | 2 +- include/mapnik/graphics.hpp | 15 ----- include/mapnik/image_data_any.hpp | 1 + include/mapnik/image_util.hpp | 7 ++- src/agg/agg_renderer.cpp | 8 +-- src/agg/process_debug_symbolizer.cpp | 19 +++--- src/image_compositing.cpp | 3 +- src/image_util.cpp | 92 ++++++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 32 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 3b6156c7f..684ebeeea 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -144,7 +144,7 @@ unsigned get_pixel(mapnik::image_32 const& im, int x, int y) void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c) { - im.setPixel(x, y, c.rgba()); + mapnik::set_pixel(im.data(), x, y, c); } std::shared_ptr open_from_file(std::string const& filename) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 2fa5e5770..1ea190283 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -89,22 +89,7 @@ public: return image_view_rgba8(x,y,w,h,data_); } -private: - - inline bool checkBounds(int x, int y) const - { - return (x >= 0 && x < static_cast(data_.width()) && y >= 0 && y < static_cast(data_.height())); - } - public: - inline void setPixel(int x,int y,unsigned int rgba) - { - if (checkBounds(x,y)) - { - data_(x,y)=rgba; - } - } - inline unsigned width() const { return data_.width(); diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index 072688c46..32133813c 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -38,6 +38,7 @@ struct image_data_null bool get_premultiplied() const { return false; } void set_premultiplied(bool) const {} void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image_data"); } + pixel_type& operator() (std::size_t, std::size_t) { throw std::runtime_error("Can not set or get values for null image_data"); } }; using image_data_base = util::variant MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); template -MAPNIK_DECL bool check_bounds (T const& data, int x, int y) +MAPNIK_DECL bool check_bounds (T const& data, std::size_t x, std::size_t y) { - return (x >= 0 && x < static_cast(data.width()) && y >= 0 && y < static_cast(data.height())); + return (x < static_cast(data.width()) && y < static_cast(data.height())); } template MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); +template +MAPNIK_DECL void set_pixel(T1 & data, std::size_t x, std::size_t y, T2 const& val); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index f34c6aee4..9274a6f01 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -507,13 +507,13 @@ void agg_renderer::draw_geo_extent(box2d const& extent, mapnik::c unsigned rgba = color.rgba(); for (double x=x0; x #include #include +#include namespace mapnik { @@ -38,13 +39,13 @@ void draw_rect(image_32 &pixmap, box2d const& box) unsigned color1 = 0xff0000ff; for (int x=x0; x::process(debug_symbolizer const& sym, if (cmd == SEG_CLOSE) continue; prj_trans.backward(x,y,z); common_.t_.forward(&x,&y); - pixmap_.setPixel(x,y,0xff0000ff); - pixmap_.setPixel(x-1,y-1,0xff0000ff); - pixmap_.setPixel(x+1,y+1,0xff0000ff); - pixmap_.setPixel(x-1,y+1,0xff0000ff); - pixmap_.setPixel(x+1,y-1,0xff0000ff); + mapnik::set_pixel(pixmap_.data(),x,y,0xff0000ff); + mapnik::set_pixel(pixmap_.data(),x-1,y-1,0xff0000ff); + mapnik::set_pixel(pixmap_.data(),x+1,y+1,0xff0000ff); + mapnik::set_pixel(pixmap_.data(),x-1,y+1,0xff0000ff); + mapnik::set_pixel(pixmap_.data(),x+1,y-1,0xff0000ff); } } } diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index ac1823f6e..181702c12 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -166,7 +166,7 @@ MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, pixfmt_type pixf(dst_buffer); pixf.comp_op(static_cast(mode)); agg::pixfmt_alpha_blend_rgba pixf_mask(src_buffer); - // DEBUGGING ONLY REMOVE +#ifdef MAPNIK_DEBUG if (!src.get_premultiplied()) { throw std::runtime_error("SOURCE MUST BE PREMULTIPLIED FOR COMPOSITING!"); @@ -175,6 +175,7 @@ MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, { throw std::runtime_error("DESTINATION MUST BE PREMULTIPLIED FOR COMPOSITING!"); } +#endif renderer_type ren(pixf); ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity)); } diff --git a/src/image_util.cpp b/src/image_util.cpp index b8978d936..83681e5ec 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -1014,4 +1014,96 @@ MAPNIK_DECL void composite_pixel(image_data_rgba8 & data, unsi visitor(data); } +namespace detail { + +template +struct visitor_set_pixel +{ + visitor_set_pixel(std::size_t x, std::size_t y, T1 const& val) + : val_(val), x_(x), y_(y) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val = static_cast(val_); + if (check_bounds(data, x_, y_)) + { + data(x_, y_) = val; + } + } + + private: + T1 const& val_; + std::size_t x_; + std::size_t y_; +}; + +template<> +struct visitor_set_pixel +{ + visitor_set_pixel(std::size_t x, std::size_t y, color const& val) + : val_(val), x_(x), y_(y) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val = static_cast(val_.rgba()); + if (check_bounds(data, x_, y_)) + { + data(x_, y_) = val; + } + } + + private: + color const& val_; + std::size_t x_; + std::size_t y_; +}; + +} // end detail ns + +// For all the generic data types. +template +MAPNIK_DECL void set_pixel (T1 & data, std::size_t x, std::size_t y, T2 const& val) +{ + util::apply_visitor(detail::visitor_set_pixel(x, y, val), data); +} + +template void set_pixel(image_data_any &, std::size_t, std::size_t, color const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, uint32_t const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, int32_t const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, uint16_t const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, int16_t const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, uint8_t const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, int8_t const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, float const&); +template void set_pixel(image_data_any &, std::size_t, std::size_t, double const&); + + +// Temporary remove these later! +template <> +MAPNIK_DECL void set_pixel (image_data_rgba8 & data, std::size_t x, std::size_t y, color const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +// Temporary remove these later! +template <> +MAPNIK_DECL void set_pixel (image_data_rgba8 & data, std::size_t x, std::size_t y, uint32_t const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +// Temporary remove these later! +template <> +MAPNIK_DECL void set_pixel (image_data_rgba8 & data, std::size_t x, std::size_t y, int32_t const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + } // end ns From aa03cf4f7cc6df0fdf0bf5924d79a60a18b9bfa8 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 16 Jan 2015 22:15:33 -0600 Subject: [PATCH 42/91] Implemented a new get_pixel method to go along with the set_pixel method in image_util. Ref #2633 --- bindings/python/mapnik_image.cpp | 5 +- include/mapnik/image_data_any.hpp | 9 ++- include/mapnik/image_util.hpp | 3 + src/image_util.cpp | 98 +++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 684ebeeea..5991dbc24 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -130,12 +130,11 @@ void background(mapnik::image_32 & im, mapnik::color const& c) mapnik::fill(im.data(), c); } -unsigned get_pixel(mapnik::image_32 const& im, int x, int y) +uint32_t get_pixel(mapnik::image_32 const& im, int x, int y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) { - mapnik::image_data_rgba8 const & data = im.data(); - return data(x,y); + return mapnik::get_pixel(im.data(), x, y); } PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); boost::python::throw_error_already_set(); diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index 32133813c..69b37a76e 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -38,7 +38,14 @@ struct image_data_null bool get_premultiplied() const { return false; } void set_premultiplied(bool) const {} void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image_data"); } - pixel_type& operator() (std::size_t, std::size_t) { throw std::runtime_error("Can not set or get values for null image_data"); } + pixel_type& operator() (std::size_t, std::size_t) + { + throw std::runtime_error("Can not set or get values for null image_data"); + } + pixel_type const& operator() (std::size_t, std::size_t) const + { + throw std::runtime_error("Can not set or get values for null image_data"); + } }; using image_data_base = util::variant MAPNIK_DECL void set_pixel(T1 & data, std::size_t x, std::size_t y, T2 const& val); +template +MAPNIK_DECL T2 get_pixel(T1 const& data, std::size_t x, std::size_t y); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/image_util.cpp b/src/image_util.cpp index 83681e5ec..40c3e90f0 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -1106,4 +1106,102 @@ MAPNIK_DECL void set_pixel (image_data_rgba8 & data, visitor(data); } +namespace detail { + +template +struct visitor_get_pixel +{ + visitor_get_pixel(std::size_t x, std::size_t y) + : x_(x), y_(y) {} + + template + T1 operator() (T2 const& data) + { + if (check_bounds(data, x_, y_)) + { + return static_cast(data(x_, y_)); + } + else + { + throw std::runtime_error("Out of range for dataset with get pixel"); + } + } + + private: + std::size_t x_; + std::size_t y_; +}; + +template<> +struct visitor_get_pixel +{ + visitor_get_pixel(std::size_t x, std::size_t y) + : x_(x), y_(y) {} + + template + color operator() (T2 const& data) + { + if (check_bounds(data, x_, y_)) + { + uint32_t val = static_cast(data(x_, y_)); + return color(static_cast(val), + static_cast((val >>= 8)), + static_cast((val >>= 8)), + static_cast((val >>= 8))); + } + else + { + throw std::runtime_error("Out of range for dataset with get pixel"); + } + } + + private: + std::size_t x_; + std::size_t y_; +}; + +} // end detail ns + +// For all the generic data types. +template +MAPNIK_DECL T2 get_pixel (T1 const& data, std::size_t x, std::size_t y) +{ + return util::apply_visitor(detail::visitor_get_pixel(x, y), data); +} + +template color get_pixel(image_data_any const&, std::size_t, std::size_t); +template uint32_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template int32_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template uint16_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template int16_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template uint8_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template int8_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template float get_pixel(image_data_any const&, std::size_t, std::size_t); +template double get_pixel(image_data_any const&, std::size_t, std::size_t); + + +// Temporary remove these later! +template <> +MAPNIK_DECL color get_pixel (image_data_rgba8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +// Temporary remove these later! +template <> +MAPNIK_DECL uint32_t get_pixel (image_data_rgba8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +// Temporary remove these later! +template <> +MAPNIK_DECL int32_t get_pixel (image_data_rgba8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + } // end ns From 2439f1b298f1912b290af88f8954afa2b3b7a9a3 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 20 Jan 2015 10:48:33 -0600 Subject: [PATCH 43/91] A whole lot of changes. #Ref 2633 --- bindings/python/mapnik_image.cpp | 125 ++++++------ bindings/python/mapnik_image_view.cpp | 29 ++- bindings/python/mapnik_python.cpp | 37 ++-- include/mapnik/agg_renderer.hpp | 7 +- include/mapnik/cairo/cairo_context.hpp | 4 +- include/mapnik/cairo/cairo_renderer.hpp | 2 +- include/mapnik/graphics.hpp | 4 +- include/mapnik/image_data.hpp | 34 +++- include/mapnik/image_data_any.hpp | 85 ++++++++ include/mapnik/image_filter.hpp | 8 +- include/mapnik/image_util.hpp | 46 ++++- include/mapnik/image_view_any.hpp | 27 +++ include/mapnik/marker.hpp | 13 +- include/mapnik/marker_cache.hpp | 1 - include/mapnik/marker_helpers.hpp | 4 +- .../process_group_symbolizer.hpp | 4 +- .../mapnik/renderer_common/render_pattern.hpp | 3 +- include/mapnik/text/glyph_positions.hpp | 2 + src/agg/agg_renderer.cpp | 60 ++++-- src/agg/process_building_symbolizer.cpp | 14 +- src/agg/process_debug_symbolizer.cpp | 33 ++- src/agg/process_dot_symbolizer.cpp | 14 +- src/agg/process_group_symbolizer.cpp | 117 ++++++++++- src/agg/process_line_pattern_symbolizer.cpp | 14 +- src/agg/process_line_symbolizer.cpp | 5 +- src/agg/process_markers_symbolizer.cpp | 4 +- src/agg/process_point_symbolizer.cpp | 3 +- .../process_polygon_pattern_symbolizer.cpp | 14 +- src/agg/process_text_symbolizer.cpp | 7 +- src/build.py | 1 + src/cairo/cairo_context.cpp | 61 ++++++ src/cairo/process_line_pattern_symbolizer.cpp | 32 ++- src/cairo/process_markers_symbolizer.cpp | 2 +- .../process_polygon_pattern_symbolizer.cpp | 38 +++- src/feature_style_processor.cpp | 3 +- src/grid/grid_renderer.cpp | 2 +- src/grid/process_group_symbolizer.cpp | 2 +- src/image_util.cpp | 188 ++++++++++++------ src/marker_cache.cpp | 42 +++- .../process_group_symbolizer.cpp | 4 +- src/renderer_common/render_pattern.cpp | 121 ++++++++++- src/text/renderer.cpp | 26 +-- 42 files changed, 951 insertions(+), 291 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 5991dbc24..d0e2abdf0 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,6 @@ using mapnik::image; using mapnik::image_data_any; -using mapnik::image_32; using mapnik::image_reader; using mapnik::get_image_reader; using mapnik::type_from_filename; @@ -62,22 +62,21 @@ using mapnik::save_to_file; using namespace boost::python; // output 'raw' pixels -PyObject* tostring1( image_32 const& im) +PyObject* tostring1( image_data_any const& im) { - int size = im.width() * im.height() * 4; return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize #else ::PyString_FromStringAndSize #endif - ((const char*)im.raw_data(),size); + ((const char*)im.getBytes(),im.getSize()); } // encode (png,jpeg) -PyObject* tostring2(image_32 const & im, std::string const& format) +PyObject* tostring2(image_data_any const & im, std::string const& format) { - std::string s = mapnik::save_to_string(im.data(), format); + std::string s = mapnik::save_to_string(im, format); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -87,9 +86,9 @@ PyObject* tostring2(image_32 const & im, std::string const& format) (s.data(),s.size()); } -PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* tostring3(image_data_any const & im, std::string const& format, mapnik::rgba_palette const& pal) { - std::string s = mapnik::save_to_string(im.data(), format, pal); + std::string s = mapnik::save_to_string(im, format, pal); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -100,53 +99,58 @@ PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba } -void save_to_file1(mapnik::image_32 const& im, std::string const& filename) +void save_to_file1(mapnik::image_data_any const& im, std::string const& filename) { - save_to_file(im.data(),filename); + save_to_file(im,filename); } -void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std::string const& type) +void save_to_file2(mapnik::image_data_any const& im, std::string const& filename, std::string const& type) { - save_to_file(im.data(),filename,type); + save_to_file(im,filename,type); } -void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) +void save_to_file3(mapnik::image_data_any const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) { - save_to_file(im.data(),filename,type,pal); + save_to_file(im,filename,type,pal); } -bool painted(mapnik::image_32 const& im) +mapnik::image_view_any get_view(mapnik::image_data_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) +{ + return mapnik::create_view(data,x,y,w,h); +} + +bool painted(mapnik::image_data_any const& im) { return im.painted(); } -bool is_solid(mapnik::image_32 const& im) +bool is_solid(mapnik::image_data_any const& im) { - return mapnik::is_solid(im.data()); + return mapnik::is_solid(im); } -void background(mapnik::image_32 & im, mapnik::color const& c) +void background(mapnik::image_data_any & im, mapnik::color const& c) { - mapnik::fill(im.data(), c); + mapnik::fill(im, c); } -uint32_t get_pixel(mapnik::image_32 const& im, int x, int y) +uint32_t get_pixel(mapnik::image_data_any const& im, int x, int y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) { - return mapnik::get_pixel(im.data(), x, y); + return mapnik::get_pixel(im, x, y); } PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); boost::python::throw_error_already_set(); return 0; } -void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c) +void set_pixel(mapnik::image_data_any & im, unsigned x, unsigned y, mapnik::color const& c) { - mapnik::set_pixel(im.data(), x, y, c); + mapnik::set_pixel(im, x, y, c); } -std::shared_ptr open_from_file(std::string const& filename) +std::shared_ptr open_from_file(std::string const& filename) { boost::optional type = type_from_filename(filename); if (type) @@ -154,29 +158,24 @@ std::shared_ptr open_from_file(std::string const& filename) std::unique_ptr reader(get_image_reader(filename,*type)); if (reader.get()) { - - std::shared_ptr image_ptr = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,image_ptr->data()); - return image_ptr; + return std::make_shared(std::move(reader->read(0,0,reader->width(),reader->height()))); } throw mapnik::image_reader_exception("Failed to load: " + filename); } throw mapnik::image_reader_exception("Unsupported image format:" + filename); } -std::shared_ptr fromstring(std::string const& str) +std::shared_ptr fromstring(std::string const& str) { std::unique_ptr reader(get_image_reader(str.c_str(),str.size())); if (reader.get()) { - std::shared_ptr image_ptr = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,image_ptr->data()); - return image_ptr; + return std::make_shared(std::move(reader->read(0,0,reader->width(), reader->height()))); } throw mapnik::image_reader_exception("Failed to load image from buffer" ); } -std::shared_ptr frombuffer(PyObject * obj) +std::shared_ptr frombuffer(PyObject * obj) { void const* buffer=0; Py_ssize_t buffer_len; @@ -185,71 +184,69 @@ std::shared_ptr frombuffer(PyObject * obj) std::unique_ptr reader(get_image_reader(reinterpret_cast(buffer),buffer_len)); if (reader.get()) { - std::shared_ptr image_ptr = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,image_ptr->data()); - return image_ptr; + return std::make_shared(reader->read(0,0,reader->width(),reader->height())); } } throw mapnik::image_reader_exception("Failed to load image from buffer" ); } -void set_grayscale_to_alpha(image_32 & im) +void set_grayscale_to_alpha(image_data_any & im) { - mapnik::set_grayscale_to_alpha(im.data()); + mapnik::set_grayscale_to_alpha(im); } -void set_color_to_alpha(image_32 & im, mapnik::color const& c) +void set_color_to_alpha(image_data_any & im, mapnik::color const& c) { - mapnik::set_color_to_alpha(im.data(), c); + mapnik::set_color_to_alpha(im, c); } -void set_alpha(image_32 & im, float opacity) +void set_alpha(image_data_any & im, float opacity) { - mapnik::set_alpha(im.data(), opacity); + mapnik::set_alpha(im, opacity); } -bool premultiplied(image_32 &im) +bool premultiplied(image_data_any &im) { - return im.data().get_premultiplied(); + return im.get_premultiplied(); } -bool premultiply(image_32 & im) +bool premultiply(image_data_any & im) { - return mapnik::premultiply_alpha(im.data()); + return mapnik::premultiply_alpha(im); } -bool demultiply(image_32 & im) +bool demultiply(image_data_any & im) { - return mapnik::demultiply_alpha(im.data()); + return mapnik::demultiply_alpha(im); } -void clear(image_32 & im) +void clear(image_data_any & im) { - mapnik::fill(im.data(), 0); + mapnik::fill(im, 0); } -void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) +void composite(image_data_any & dst, image_data_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) { - bool demultiply_dst = mapnik::premultiply_alpha(dst.data()); - bool demultiply_src = mapnik::premultiply_alpha(src.data()); - mapnik::composite(dst.data(),src.data(),mode,opacity,dx,dy); + bool demultiply_dst = mapnik::premultiply_alpha(dst); + bool demultiply_src = mapnik::premultiply_alpha(src); + mapnik::composite(dst,src,mode,opacity,dx,dy); if (demultiply_dst) { - mapnik::demultiply_alpha(dst.data()); + mapnik::demultiply_alpha(dst); } if (demultiply_src) { - mapnik::demultiply_alpha(src.data()); + mapnik::demultiply_alpha(src); } } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) -std::shared_ptr from_cairo(PycairoSurface* py_surface) +std::shared_ptr from_cairo(PycairoSurface* py_surface) { mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); - std::shared_ptr image_ptr = std::make_shared(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); - cairo_image_to_rgba8(image_ptr->data(), surface); - return image_ptr; + mapnik::image_data_rgba8 image = mapnik::image_data_rgba8(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); + cairo_image_to_rgba8(image, surface); + return std::make_shared(std::move(image)); } #endif @@ -319,10 +316,10 @@ void export_image() .def("save",&image::save_to_file) ; - class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) - .def("width",&image_32::width) - .def("height",&image_32::height) - .def("view",&image_32::get_view) + class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) + .def("width",&image_data_any::width) + .def("height",&image_data_any::height) + .def("view",&get_view) .def("painted",&painted) .def("is_solid",&is_solid) .def("background",&background, "Set the background color of the image.") diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index 4d448e40a..bac81b918 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -37,22 +37,19 @@ // mapnik #include #include +#include #include #include #include -using mapnik::image_view_rgba8; +using mapnik::image_view_any; using mapnik::save_to_file; // output 'raw' pixels -PyObject* view_tostring1(image_view_rgba8 const& view) +PyObject* view_tostring1(image_view_any const& view) { std::ostringstream ss(std::ios::out|std::ios::binary); - for (unsigned i=0;i(view.getRow(i)), - view.width() * sizeof(image_view_rgba8::pixel_type)); - } + mapnik::view_to_string(view, ss); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -63,7 +60,7 @@ PyObject* view_tostring1(image_view_rgba8 const& view) } // encode (png,jpeg) -PyObject* view_tostring2(image_view_rgba8 const & view, std::string const& format) +PyObject* view_tostring2(image_view_any const & view, std::string const& format) { std::string s = save_to_string(view, format); return @@ -75,7 +72,7 @@ PyObject* view_tostring2(image_view_rgba8 const & view, std::string const& forma (s.data(),s.size()); } -PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* view_tostring3(image_view_any const & view, std::string const& format, mapnik::rgba_palette const& pal) { std::string s = save_to_string(view, format, pal); return @@ -87,25 +84,25 @@ PyObject* view_tostring3(image_view_rgba8 const & view, std::string const& forma (s.data(),s.size()); } -bool is_solid(image_view_rgba8 const& view) +bool is_solid(image_view_any const& view) { return mapnik::is_solid(view); } -void save_view1(image_view_rgba8 const& view, +void save_view1(image_view_any const& view, std::string const& filename) { save_to_file(view,filename); } -void save_view2(image_view_rgba8 const& view, +void save_view2(image_view_any const& view, std::string const& filename, std::string const& type) { save_to_file(view,filename,type); } -void save_view3(image_view_rgba8 const& view, +void save_view3(image_view_any const& view, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) @@ -117,9 +114,9 @@ void save_view3(image_view_rgba8 const& view, void export_image_view() { using namespace boost::python; - class_("ImageView","A view into an image.",no_init) - .def("width",&image_view_rgba8::width) - .def("height",&image_view_rgba8::height) + class_("ImageView","A view into an image.",no_init) + .def("width",&image_view_any::width) + .def("height",&image_view_any::height) .def("is_solid",&is_solid) .def("tostring",&view_tostring1) .def("tostring",&view_tostring2) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 649d20126..927ae6688 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -102,6 +102,7 @@ void export_logger(); #include #include #include +#include #include #include #include @@ -190,18 +191,18 @@ bool python_thread::thread_support = true; boost::thread_specific_ptr python_thread::state; void render(mapnik::Map const& map, - mapnik::image_32& image, + mapnik::image_data_any& image, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::agg_renderer ren(map,image,scale_factor,offset_x, offset_y); + mapnik::agg_renderer ren(map,image,scale_factor,offset_x, offset_y); ren.apply(); } void render_with_vars(mapnik::Map const& map, - mapnik::image_32& image, + mapnik::image_data_any& image, boost::python::dict const& d, double scale_factor = 1.0, unsigned offset_x = 0u, @@ -211,25 +212,25 @@ void render_with_vars(mapnik::Map const& map, mapnik::request req(map.width(),map.height(),map.get_current_extent()); req.set_buffer_size(map.buffer_size()); python_unblock_auto_block b; - mapnik::agg_renderer ren(map,req,vars,image,scale_factor,offset_x,offset_y); + mapnik::agg_renderer ren(map,req,vars,image,scale_factor,offset_x,offset_y); ren.apply(); } void render_with_detector( mapnik::Map const& map, - mapnik::image_32 &image, + mapnik::image_data_any &image, std::shared_ptr detector, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::agg_renderer ren(map,image,detector,scale_factor,offset_x,offset_y); + mapnik::agg_renderer ren(map,image,detector,scale_factor,offset_x,offset_y); ren.apply(); } void render_layer2(mapnik::Map const& map, - mapnik::image_32& image, + mapnik::image_data_any& image, unsigned layer_idx, double scale_factor, unsigned offset_x, @@ -246,7 +247,7 @@ void render_layer2(mapnik::Map const& map, python_unblock_auto_block b; mapnik::layer const& layer = layers[layer_idx]; - mapnik::agg_renderer ren(map,image,scale_factor,offset_x,offset_y); + mapnik::agg_renderer ren(map,image,scale_factor,offset_x,offset_y); std::set names; ren.apply(layer,names); } @@ -351,9 +352,9 @@ void render_tile_to_file(mapnik::Map const& map, std::string const& file, std::string const& format) { - mapnik::image_32 image(width,height); + mapnik::image_data_any image(width,height); render(map,image,1.0,offset_x, offset_y); - mapnik::save_to_file(image.data(),file,format); + mapnik::save_to_file(image,file,format); } void render_to_file1(mapnik::Map const& map, @@ -386,9 +387,9 @@ void render_to_file1(mapnik::Map const& map, } else { - mapnik::image_32 image(map.width(),map.height()); + mapnik::image_data_any image(map.width(),map.height()); render(map,image,1.0,0,0); - mapnik::save_to_file(image.data(),filename,format); + mapnik::save_to_file(image,filename,format); } } @@ -405,9 +406,9 @@ void render_to_file2(mapnik::Map const& map,std::string const& filename) } else { - mapnik::image_32 image(map.width(),map.height()); + mapnik::image_data_any image(map.width(),map.height()); render(map,image,1.0,0,0); - mapnik::save_to_file(image.data(),filename); + mapnik::save_to_file(image,filename); } } @@ -443,9 +444,9 @@ void render_to_file3(mapnik::Map const& map, } else { - mapnik::image_32 image(map.width(),map.height()); + mapnik::image_data_any image(map.width(),map.height()); render(map,image,scale_factor,0,0); - mapnik::save_to_file(image.data(),filename,format); + mapnik::save_to_file(image,filename,format); } } @@ -725,7 +726,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("render", &render, render_overloads( "\n" - "Render Map to an AGG image_32 using offsets\n" + "Render Map to an AGG image_data_any using offsets\n" "\n" "Usage:\n" ">>> from mapnik import Map, Image, render, load_map\n" @@ -742,7 +743,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("render_with_detector", &render_with_detector, render_with_detector_overloads( "\n" - "Render Map to an AGG image_32 using a pre-constructed detector.\n" + "Render Map to an AGG image_data_any using a pre-constructed detector.\n" "\n" "Usage:\n" ">>> from mapnik import Map, Image, LabelCollisionDetector, render_with_detector, load_map\n" diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 7e50aea86..6361d4011 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -37,6 +37,7 @@ #include #include #include +#include // stl #include @@ -53,7 +54,6 @@ namespace mapnik { class marker; class proj_transform; struct rasterizer; - class image_32; } namespace mapnik { @@ -171,7 +171,10 @@ private: void setup(Map const& m); }; -extern template class MAPNIK_DECL agg_renderer; +extern template class MAPNIK_DECL agg_renderer; +//extern template class MAPNIK_DECL agg_renderer; +//extern template class MAPNIK_DECL agg_renderer; +//extern template class MAPNIK_DECL agg_renderer; } // namespace mapnik diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index 022d04092..3b5d40b17 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -279,7 +280,6 @@ inline cairo_ptr create_context(cairo_surface_ptr const& surface) class cairo_context : private util::noncopyable { public: - cairo_context(cairo_ptr const& cairo); inline ErrorStatus get_status() const @@ -308,6 +308,8 @@ public: void paint(); void set_pattern(cairo_pattern const& pattern); void set_gradient(cairo_gradient const& pattern, box2d const& bbox); + void add_image(double x, double y, image_data_any & data, double opacity); + void add_image(agg::trans_affine const& tr, image_data_any & data, double opacity); void add_image(double x, double y, image_data_rgba8 & data, double opacity = 1.0); void add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity = 1.0); void set_font_face(cairo_face_manager & manager, face_ptr face); diff --git a/include/mapnik/cairo/cairo_renderer.hpp b/include/mapnik/cairo/cairo_renderer.hpp index 5aedba82f..89bb8058f 100644 --- a/include/mapnik/cairo/cairo_renderer.hpp +++ b/include/mapnik/cairo/cairo_renderer.hpp @@ -165,7 +165,7 @@ public: { return common_.vars_; } - + void render_marker(pixel_position const& pos, marker const& marker, agg::trans_affine const& mtx, diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 1ea190283..9030cc5d5 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -56,12 +56,12 @@ public: void painted(bool painted) { - painted_ = painted; + data_.painted(painted); } bool painted() const { - return painted_; + return data_.painted(); } inline const image_data_rgba8& data() const diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image_data.hpp index 09367db85..24d2eec11 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image_data.hpp @@ -122,11 +122,12 @@ public: using pixel_type = T; static constexpr std::size_t pixel_size = sizeof(pixel_type); - image_data(int width, int height, bool initialize = true, bool premultiplied = false) + image_data(int width, int height, bool initialize = true, bool premultiplied = false, bool painted = false) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), pData_(reinterpret_cast(buffer_.data())), - premultiplied_alpha_(premultiplied) + premultiplied_alpha_(premultiplied), + painted_(painted) { if (pData_ && initialize) std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), 0); } @@ -135,14 +136,16 @@ public: : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), pData_(reinterpret_cast(buffer_.data())), - premultiplied_alpha_(rhs.premultiplied_alpha_) + premultiplied_alpha_(rhs.premultiplied_alpha_), + painted_(rhs.painted_) {} image_data(image_data && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), buffer_(std::move(rhs.buffer_)), pData_(reinterpret_cast(buffer_.data())), - premultiplied_alpha_(std::move(rhs.premultiplied_alpha_)) + premultiplied_alpha_(rhs.premultiplied_alpha_), + painted_(rhs.painted_) { rhs.dimensions_ = { 0, 0 }; rhs.pData_ = nullptr; @@ -254,17 +257,38 @@ public: premultiplied_alpha_ = set; } + inline void painted(bool painted) + { + painted_ = painted; + } + + inline bool painted() const + { + return painted_; + } + private: detail::image_dimensions dimensions_; detail::buffer buffer_; pixel_type *pData_; bool premultiplied_alpha_; + bool painted_; }; using image_data_rgba8 = image_data; using image_data_gray8 = image_data ; using image_data_gray16 = image_data; using image_data_gray32f = image_data; -} + +enum image_dtype +{ + image_dtype_rgba8 = 0, + image_dtype_gray8, + image_dtype_gray16, + image_dtype_gray32f, + image_dtype_null +}; + +} // end ns #endif // MAPNIK_IMAGE_DATA_HPP diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp index 69b37a76e..159b2c4e5 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_data_any.hpp @@ -33,8 +33,11 @@ struct image_data_null using pixel_type = uint8_t; unsigned char const* getBytes() const { return nullptr; } unsigned char* getBytes() { return nullptr;} + unsigned getSize() const { return 0; } + unsigned getRowSize() const { return 0; } std::size_t width() const { return 0; } std::size_t height() const { return 0; } + bool painted() const { return false; } bool get_premultiplied() const { return false; } void set_premultiplied(bool) const {} void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image_data"); } @@ -54,6 +57,15 @@ using image_data_base = util::variant; +// Forward declaring +struct image_data_any; +image_data_any create_image_any(int width, + int height, + image_dtype type = image_dtype_rgba8, + bool initialize = true, + bool premultiplied = false, + bool painted = false); + namespace detail { struct get_bytes_visitor @@ -100,12 +112,47 @@ struct get_premultiplied_visitor return data.get_premultiplied(); } }; + +struct get_painted_visitor +{ + template + bool operator()(T const& data) const + { + return data.painted(); + } +}; + +struct get_any_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getSize(); + } +}; + +struct get_any_row_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getRowSize(); + } +}; } // namespace detail struct image_data_any : image_data_base { image_data_any() = default; + image_data_any(int width, + int height, + image_dtype type = image_dtype_rgba8, + bool initialize = true, + bool premultiplied = false, + bool painted = false) + : image_data_base(std::move(create_image_any(width, height, type, initialize, premultiplied, painted))) {} + template image_data_any(T && data) noexcept : image_data_base(std::move(data)) {} @@ -134,8 +181,46 @@ struct image_data_any : image_data_base { return util::apply_visitor(detail::get_premultiplied_visitor(),*this); } + + bool painted() const + { + return util::apply_visitor(detail::get_painted_visitor(),*this); + } + + unsigned getSize() const + { + return util::apply_visitor(detail::get_any_size_visitor(),*this); + } + + unsigned getRowSize() const + { + return util::apply_visitor(detail::get_any_row_size_visitor(),*this); + } }; +inline image_data_any create_image_any(int width, + int height, + image_dtype type, + bool initialize, + bool premultiplied, + bool painted) +{ + switch (type) + { + case image_dtype_gray8: + return image_data_any(std::move(image_data_gray8(width, height, initialize, premultiplied, painted))); + case image_dtype_gray16: + return image_data_any(std::move(image_data_gray16(width, height, initialize, premultiplied, painted))); + case image_dtype_gray32f: + return image_data_any(std::move(image_data_gray32f(width, height, initialize, premultiplied, painted))); + case image_dtype_null: + return image_data_any(std::move(image_data_null())); + case image_dtype_rgba8: + default: + return image_data_any(std::move(image_data_rgba8(width, height, initialize, premultiplied, painted))); + } } +} // end mapnik ns + #endif // MAPNIK_IMAGE_DATA_ANY_HPP diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index ccebf7ec3..3c2a54d6d 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -139,7 +139,7 @@ boost::gil::rgba8_view_t rgba8_view(Image & img) using boost::gil::interleaved_view; using boost::gil::rgba8_pixel_t; return interleaved_view(img.width(), img.height(), - reinterpret_cast(img.raw_data()), + reinterpret_cast(img.getBytes()), img.width() * sizeof(rgba8_pixel_t)); } @@ -391,17 +391,17 @@ template void apply_filter(Src & src, Filter const& filter) { { - demultiply_alpha(src.data()); + demultiply_alpha(src); double_buffer tb(src); apply_convolution_3x3(tb.src_view, tb.dst_view, filter); } // ensure ~double_buffer() is called before premultiplying - premultiply_alpha(src.data()); + premultiply_alpha(src); } template void apply_filter(Src & src, agg_stack_blur const& op) { - agg::rendering_buffer buf(src.raw_data(),src.width(),src.height(), src.width() * 4); + agg::rendering_buffer buf(src.getBytes(),src.width(),src.height(), src.width() * 4); agg::pixfmt_rgba32_pre pixf(buf); agg::stack_blur_rgba32(pixf,op.rx,op.ry); } diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 785f1a303..fa67d299d 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -26,7 +26,9 @@ // mapnik #include #include +#include #include +#include #include #include @@ -153,6 +155,10 @@ MAPNIK_DECL void set_pixel(T1 & data, std::size_t x, std::size_t y, T2 const& va template MAPNIK_DECL T2 get_pixel(T1 const& data, std::size_t x, std::size_t y); +MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss); + +MAPNIK_DECL image_view_any create_view (image_data_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); @@ -229,38 +235,53 @@ void add_border(T & image) } } - +/* extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, rgba_palette const&); +extern template MAPNIK_DECL void save_to_file(image_data_any const&, + std::string const&, + std::string const&, + rgba_palette const&); + extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&); +extern template MAPNIK_DECL void save_to_file(image_data_any const&, + std::string const&, + std::string const&); + extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, rgba_palette const&); +extern template MAPNIK_DECL void save_to_file(image_data_any const&, + std::string const&, + rgba_palette const&); + extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&); +extern template MAPNIK_DECL void save_to_file(image_data_any const&, + std::string const&); -extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_view_any const&, std::string const&, std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_view_any const&, std::string const&, std::string const&); -extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_view_any const&, std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file (image_view_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_view_any const&, std::string const&); extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, @@ -276,6 +297,21 @@ extern template MAPNIK_DECL std::string save_to_string (image_ extern template MAPNIK_DECL std::string save_to_string (image_view_rgba8 const&, std::string const&, rgba_palette const&); + +extern template MAPNIK_DECL std::string save_to_string(image_data_any const&, + std::string const&); + +extern template MAPNIK_DECL std::string save_to_string(image_data_any const&, + std::string const&, + rgba_palette const&); + +extern template MAPNIK_DECL std::string save_to_string (image_view_any const&, + std::string const&); + +extern template MAPNIK_DECL std::string save_to_string (image_view_any const&, + std::string const&, + rgba_palette const&); +*/ #ifdef _MSC_VER template MAPNIK_DECL void save_to_stream( diff --git a/include/mapnik/image_view_any.hpp b/include/mapnik/image_view_any.hpp index 822986d13..0e4dbd1e9 100644 --- a/include/mapnik/image_view_any.hpp +++ b/include/mapnik/image_view_any.hpp @@ -53,6 +53,23 @@ struct get_view_height_visitor } }; +struct get_view_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getSize(); + } +}; + +struct get_view_row_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getRowSize(); + } +}; } // namespace detail struct image_view_any : image_view_base @@ -72,6 +89,16 @@ struct image_view_any : image_view_base { return util::apply_visitor(detail::get_view_height_visitor(),*this); } + + unsigned getSize() const + { + return util::apply_visitor(detail::get_view_size_visitor(),*this); + } + + unsigned getRowSize() const + { + return util::apply_visitor(detail::get_view_row_size_visitor(),*this); + } }; } diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index 160ff0fd3..d2d26e167 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -46,7 +46,7 @@ namespace mapnik using attr_storage = agg::pod_bvector; using svg_storage_type = mapnik::svg::svg_storage; using svg_path_ptr = std::shared_ptr; -using image_ptr = std::shared_ptr; +using image_ptr = std::shared_ptr; /** * A class to hold either vector or bitmap marker data. This allows these to be treated equally * in the image caches and most of the render paths. @@ -57,11 +57,12 @@ public: marker() { // create default OGC 4x4 black pixel - bitmap_data_ = boost::optional(std::make_shared(4,4,true,true)); - (*bitmap_data_)->set(0xff000000); + image_data_rgba8 image(4,4,true,true); + image.set(0xff000000); + bitmap_data_ = boost::optional(std::make_shared(std::move(image))); } - marker(boost::optional const& data) + marker(boost::optional const& data) : bitmap_data_(data) {} marker(boost::optional const& data) @@ -121,7 +122,7 @@ public: return !!vector_data_; } - boost::optional get_bitmap_data() const + boost::optional get_bitmap_data() const { return bitmap_data_; } @@ -132,7 +133,7 @@ public: } private: - boost::optional bitmap_data_; + boost::optional bitmap_data_; boost::optional vector_data_; }; diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 34907cc80..68cc79155 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -40,7 +40,6 @@ class marker; using marker_ptr = std::shared_ptr; - class MAPNIK_DECL marker_cache : public singleton , private util::noncopyable diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index c7fd8becf..3e9e42e0d 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -118,7 +118,7 @@ protected: template struct raster_markers_dispatch : util::noncopyable { - raster_markers_dispatch(image_data_rgba8 & src, + raster_markers_dispatch(image_data_any & src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -163,7 +163,7 @@ struct raster_markers_dispatch : util::noncopyable virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0; protected: - image_data_rgba8 & src_; + image_data_any & src_; agg::trans_affine const& marker_trans_; symbolizer_base const& sym_; Detector & detector_; diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 348302ef8..c91ad894d 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -130,13 +130,13 @@ struct vector_marker_render_thunk : util::noncopyable struct raster_marker_render_thunk : util::noncopyable { - image_data_rgba8 & src_; + image_data_any & src_; agg::trans_affine tr_; double opacity_; composite_mode_e comp_op_; bool snap_to_pixels_; - raster_marker_render_thunk(image_data_rgba8 & src, + raster_marker_render_thunk(image_data_any & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, diff --git a/include/mapnik/renderer_common/render_pattern.hpp b/include/mapnik/renderer_common/render_pattern.hpp index e694b5454..6173bfd58 100644 --- a/include/mapnik/renderer_common/render_pattern.hpp +++ b/include/mapnik/renderer_common/render_pattern.hpp @@ -37,7 +37,8 @@ namespace mapnik { struct rasterizer; class marker; -std::shared_ptr render_pattern(rasterizer & ras, +template +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity); diff --git a/include/mapnik/text/glyph_positions.hpp b/include/mapnik/text/glyph_positions.hpp index 86c0302ef..884de2786 100644 --- a/include/mapnik/text/glyph_positions.hpp +++ b/include/mapnik/text/glyph_positions.hpp @@ -56,12 +56,14 @@ struct marker_info marker_ptr marker; agg::trans_affine transform; }; + using marker_info_ptr = std::shared_ptr; /** Stores positions of glphys. * * The actual glyphs and their format are stored in text_layout. */ + class glyph_positions { public: diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 9274a6f01..63158bdae 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -43,6 +43,7 @@ #include #include #include +#include // agg #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -111,7 +112,7 @@ agg_renderer::agg_renderer(Map const& m, T0 & pixmap, std::shared_ptr template void agg_renderer::setup(Map const &m) { - mapnik::set_premultiplied_alpha(pixmap_.data(), true); + mapnik::set_premultiplied_alpha(pixmap_, true); boost::optional const& bg = m.background(); if (bg) { @@ -119,11 +120,11 @@ void agg_renderer::setup(Map const &m) { mapnik::color bg_color = *bg; bg_color.premultiply(); - mapnik::fill(pixmap_.data(), bg_color); + mapnik::fill(pixmap_, bg_color); } else { - mapnik::fill(pixmap_.data(),*bg); + mapnik::fill(pixmap_,*bg); } } @@ -146,7 +147,7 @@ void agg_renderer::setup(Map const &m) { for (unsigned y=0;y(*bg_image), m.background_image_comp_op(), m.background_image_opacity(), x*w, y*h); } } } @@ -168,7 +169,7 @@ void agg_renderer::start_map_processing(Map const& map) template void agg_renderer::end_map_processing(Map const& ) { - mapnik::demultiply_alpha(pixmap_.data()); + mapnik::demultiply_alpha(pixmap_); MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End map processing"; } @@ -237,7 +238,7 @@ void agg_renderer::start_style_processing(feature_type_style const& st) } else { - mapnik::fill(internal_buffer_->data(), 0); // fill with transparent colour + mapnik::fill(*internal_buffer_, 0); // fill with transparent colour } } else @@ -248,13 +249,13 @@ void agg_renderer::start_style_processing(feature_type_style const& st) } else { - mapnik::fill(internal_buffer_->data(), 0); // fill with transparent colour + mapnik::fill(*internal_buffer_, 0); // fill with transparent colour } common_.t_.set_offset(0); ras_ptr->clip_box(0,0,common_.width_,common_.height_); } current_buffer_ = internal_buffer_.get(); - set_premultiplied_alpha(current_buffer_->data(),true); + set_premultiplied_alpha(*current_buffer_,true); } else { @@ -273,7 +274,7 @@ void agg_renderer::end_style_processing(feature_type_style const& st) if (st.image_filters().size() > 0) { blend_from = true; - mapnik::filter::filter_visitor visitor(*current_buffer_); + mapnik::filter::filter_visitor visitor(*current_buffer_); for (mapnik::filter::filter_type const& filter_tag : st.image_filters()) { util::apply_visitor(visitor, filter_tag); @@ -281,21 +282,21 @@ void agg_renderer::end_style_processing(feature_type_style const& st) } if (st.comp_op()) { - composite(pixmap_.data(), current_buffer_->data(), + composite(pixmap_, *current_buffer_, *st.comp_op(), st.get_opacity(), -common_.t_.offset(), -common_.t_.offset()); } else if (blend_from || st.get_opacity() < 1.0) { - composite(pixmap_.data(), current_buffer_->data(), + composite(pixmap_, *current_buffer_, src_over, st.get_opacity(), -common_.t_.offset(), -common_.t_.offset()); } } // apply any 'direct' image filters - mapnik::filter::filter_visitor visitor(pixmap_); + mapnik::filter::filter_visitor visitor(pixmap_); for (mapnik::filter::filter_type const& filter_tag : st.direct_image_filters()) { util::apply_visitor(visitor, filter_tag); @@ -326,7 +327,7 @@ void agg_renderer::render_marker(pixel_position const& pos, gamma_ = 1.0; } agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); @@ -372,7 +373,7 @@ void agg_renderer::render_marker(pixel_position const& pos, { double cx = 0.5 * width; double cy = 0.5 * height; - composite(current_buffer_->data(), **marker.get_bitmap_data(), + composite(*current_buffer_, util::get(**marker.get_bitmap_data()), comp_op, opacity, std::floor(pos.x - cx + .5), std::floor(pos.y - cy + .5)); @@ -410,7 +411,7 @@ void agg_renderer::render_marker(pixel_position const& pos, agg::image_filter_bilinear filter_kernel; agg::image_filter_lut filter(filter_kernel, false); - image_data_rgba8 const& src = **marker.get_bitmap_data(); + buffer_type const& src = util::get(**marker.get_bitmap_data()); agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), src.width(), src.height(), @@ -451,7 +452,7 @@ template void agg_renderer::debug_draw_box(box2d const& box, double x, double y, double angle) { - agg::rendering_buffer buf(current_buffer_->raw_data(), + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); @@ -507,18 +508,33 @@ void agg_renderer::draw_geo_extent(box2d const& extent, mapnik::c unsigned rgba = color.rgba(); for (double x=x0; x; -template void agg_renderer::debug_draw_box( +template class agg_renderer; +template void agg_renderer::debug_draw_box( + agg::rendering_buffer& buf, + box2d const& box, + double x, double y, double angle); +template class agg_renderer; +template void agg_renderer::debug_draw_box( + agg::rendering_buffer& buf, + box2d const& box, + double x, double y, double angle); +template class agg_renderer; +template void agg_renderer::debug_draw_box( + agg::rendering_buffer& buf, + box2d const& box, + double x, double y, double angle); +template class agg_renderer; +template void agg_renderer::debug_draw_box( agg::rendering_buffer& buf, box2d const& box, double x, double y, double angle); diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 7a693454f..7d8c94d00 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -23,6 +23,7 @@ // mapnik #include #include +#include #include #include #include @@ -58,7 +59,7 @@ void agg_renderer::process(building_symbolizer const& sym, using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); agg::pixfmt_rgba32_pre pixf(buf); ren_base renb(pixf); @@ -109,7 +110,16 @@ void agg_renderer::process(building_symbolizer const& sym, }); } -template void agg_renderer::process(building_symbolizer const&, +template void agg_renderer::process(building_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(building_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(building_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(building_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index 8237b6243..8e270ff7d 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -24,13 +24,15 @@ #include #include #include +#include #include #include #include namespace mapnik { -void draw_rect(image_32 &pixmap, box2d const& box) +template +void draw_rect(T &pixmap, box2d const& box) { int x0 = static_cast(box.minx()); int x1 = static_cast(box.maxx()); @@ -39,13 +41,13 @@ void draw_rect(image_32 &pixmap, box2d const& box) unsigned color1 = 0xff0000ff; for (int x=x0; x::process(debug_symbolizer const& sym, if (cmd == SEG_CLOSE) continue; prj_trans.backward(x,y,z); common_.t_.forward(&x,&y); - mapnik::set_pixel(pixmap_.data(),x,y,0xff0000ff); - mapnik::set_pixel(pixmap_.data(),x-1,y-1,0xff0000ff); - mapnik::set_pixel(pixmap_.data(),x+1,y+1,0xff0000ff); - mapnik::set_pixel(pixmap_.data(),x-1,y+1,0xff0000ff); - mapnik::set_pixel(pixmap_.data(),x+1,y-1,0xff0000ff); + mapnik::set_pixel(pixmap_,x,y,0xff0000ff); + mapnik::set_pixel(pixmap_,x-1,y-1,0xff0000ff); + mapnik::set_pixel(pixmap_,x+1,y+1,0xff0000ff); + mapnik::set_pixel(pixmap_,x-1,y+1,0xff0000ff); + mapnik::set_pixel(pixmap_,x+1,y-1,0xff0000ff); } } } } -template void agg_renderer::process(debug_symbolizer const&, +template void agg_renderer::process(debug_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(debug_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(debug_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(debug_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index 4b53d3ced..4b08009ce 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ void agg_renderer::process(dot_symbolizer const& sym, double opacity = get(sym, keys::opacity, feature, common_.vars_, 1.0); color const& fill = get(sym, keys::fill, feature, common_.vars_, mapnik::color(128,128,128)); ras_ptr->reset(); - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(),current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(),current_buffer_->width() * 4); using blender_type = agg::comp_op_adaptor_rgba_pre; using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; using renderer_base = agg::renderer_base; @@ -98,7 +99,16 @@ void agg_renderer::process(dot_symbolizer const& sym, } } -template void agg_renderer::process(dot_symbolizer const&, +template void agg_renderer::process(dot_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(dot_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(dot_symbolizer const&, + mapnik::feature_impl &, + proj_transform const&); +template void agg_renderer::process(dot_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index d8b2d3868..ac3fb94f8 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,104 @@ namespace mapnik { * to render it, and the boxes themselves should already be * in the detector from the placement_finder. */ +template struct thunk_renderer { - using renderer_type = agg_renderer; + using renderer_type = agg_renderer; + using buffer_type = typename renderer_type::buffer_type; + using text_renderer_type = agg_text_renderer; + + thunk_renderer(renderer_type &ren, + std::unique_ptr const& ras_ptr, + buffer_type *buf, + renderer_common &common, + pixel_position const &offset) + : ren_(ren), ras_ptr_(ras_ptr), buf_(buf), common_(common), offset_(offset) + {} + + void operator()(vector_marker_render_thunk const &thunk) const + { + using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender + using buf_type = agg::rendering_buffer; + using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_scanline_aa_solid; + using svg_attribute_type = agg::pod_bvector; + using svg_renderer_type = svg::svg_renderer_agg; + ras_ptr_->reset(); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); + pixfmt_comp_type pixf(render_buffer); + pixf.comp_op(static_cast(thunk.comp_op_)); + renderer_base renb(pixf); + svg::vertex_stl_adapter stl_storage(thunk.src_->source()); + svg_path_adapter svg_path(stl_storage); + svg_renderer_type svg_renderer(svg_path, thunk.attrs_); + + agg::trans_affine offset_tr = thunk.tr_; + offset_tr.translate(offset_.x, offset_.y); + render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_); + } + + void operator()(raster_marker_render_thunk const &thunk) const + { + using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender + using buf_type = agg::rendering_buffer; + using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + + ras_ptr_->reset(); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); + pixfmt_comp_type pixf(render_buffer); + pixf.comp_op(static_cast(thunk.comp_op_)); + renderer_base renb(pixf); + + agg::trans_affine offset_tr = thunk.tr_; + offset_tr.translate(offset_.x, offset_.y); + render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); + } + + void operator()(text_render_thunk const &thunk) const + { + text_renderer_type ren(*buf_, thunk.halo_rasterizer_, thunk.comp_op_, thunk.comp_op_, + common_.scale_factor_, common_.font_manager_.get_stroker()); + + render_offset_placements( + thunk.placements_, + offset_, + [&] (glyph_positions_ptr glyphs) + { + if (glyphs->marker()) + { + ren_.render_marker(glyphs->marker_pos(), + *(glyphs->marker()->marker), + glyphs->marker()->transform, + thunk.opacity_, thunk.comp_op_); + } + ren.render(*glyphs); + }); + } + + template + void operator()(T const &) const + { + // TODO: warning if unimplemented? + } + +private: + renderer_type &ren_; + std::unique_ptr const& ras_ptr_; + buffer_type *buf_; + renderer_common &common_; + pixel_position offset_; +}; + +template <> +struct thunk_renderer +{ + using renderer_type = agg_renderer; using buffer_type = renderer_type::buffer_type; using text_renderer_type = agg_text_renderer; @@ -75,7 +171,7 @@ struct thunk_renderer renderer_type, pixfmt_comp_type>; ras_ptr_->reset(); - buf_type render_buffer(buf_->raw_data(), buf_->width(), buf_->height(), buf_->width() * 4); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); pixfmt_comp_type pixf(render_buffer); pixf.comp_op(static_cast(thunk.comp_op_)); renderer_base renb(pixf); @@ -96,14 +192,14 @@ struct thunk_renderer using renderer_base = agg::renderer_base; ras_ptr_->reset(); - buf_type render_buffer(buf_->raw_data(), buf_->width(), buf_->height(), buf_->width() * 4); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); pixfmt_comp_type pixf(render_buffer); pixf.comp_op(static_cast(thunk.comp_op_)); renderer_base renb(pixf); agg::trans_affine offset_tr = thunk.tr_; offset_tr.translate(offset_.x, offset_.y); - render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); + render_raster_marker(renb, *ras_ptr_, util::get(thunk.src_), offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); } void operator()(text_render_thunk const &thunk) const @@ -150,7 +246,7 @@ void agg_renderer::process(group_symbolizer const& sym, sym, feature, common_.vars_, prj_trans, clipping_extent(common_), common_, [&](render_thunk_list const& thunks, pixel_position const& render_offset) { - thunk_renderer ren(*this, ras_ptr, current_buffer_, common_, render_offset); + thunk_renderer ren(*this, ras_ptr, current_buffer_, common_, render_offset); for (render_thunk_ptr const& thunk : thunks) { util::apply_visitor(ren, *thunk); @@ -158,8 +254,17 @@ void agg_renderer::process(group_symbolizer const& sym, }); } -template void agg_renderer::process(group_symbolizer const&, +template void agg_renderer::process(group_symbolizer const&, mapnik::feature_impl &, proj_transform const&); +//template void agg_renderer::process(group_symbolizer const&, +// mapnik::feature_impl &, +// proj_transform const&); +//template void agg_renderer::process(group_symbolizer const&, +// mapnik::feature_impl &, +// proj_transform const&); +//template void agg_renderer::process(group_symbolizer const&, +// mapnik::feature_impl &, +// proj_transform const&); } diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 110a52e2e..ab3c552b9 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -72,19 +73,22 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, if (filename.empty()) return; boost::optional marker_ptr = marker_cache::instance().find(filename, true); if (!marker_ptr || !(*marker_ptr)) return; - boost::optional pat; + boost::optional > pat; // TODO - re-implement at renderer level like polygon_pattern symbolizer value_double opacity = get(sym, feature, common_.vars_); if ((*marker_ptr)->is_bitmap()) { - pat = (*marker_ptr)->get_bitmap_data(); + pat = boost::optional>( + std::make_shared( + std::move(util::get(**(*marker_ptr)->get_bitmap_data()) + ))); } else { agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym, keys::image_transform); if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); + pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); } if (!pat) return; @@ -94,7 +98,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, value_double simplify_tolerance = get(sym, feature, common_.vars_); value_double smooth = get(sym, feature, common_.vars_); - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); pixfmt_type pixf(buf); pixf.comp_op(static_cast(get(sym, feature, common_.vars_))); renderer_base ren_base(pixf); @@ -144,7 +148,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, } } -template void agg_renderer::process(line_pattern_symbolizer const&, +template void agg_renderer::process(line_pattern_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index e35f1000b..65e0e17fc 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -23,6 +23,7 @@ // mapnik #include #include +#include #include #include #include @@ -109,7 +110,7 @@ void agg_renderer::process(line_symbolizer const& sym, gamma_ = gamma; } - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); using color_type = agg::rgba8; using order_type = agg::order_rgba; @@ -223,7 +224,7 @@ void agg_renderer::process(line_symbolizer const& sym, } -template void agg_renderer::process(line_symbolizer const&, +template void agg_renderer::process(line_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 31555bc6e..8a3dc1e50 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -191,7 +191,7 @@ void agg_renderer::process(markers_symbolizer const& sym, gamma_ = gamma; } - buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); + buf_type render_buffer(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); box2d clip_box = clipping_extent(common_); auto renderer_context = std::tie(render_buffer,*ras_ptr,pixmap_); @@ -203,7 +203,7 @@ void agg_renderer::process(markers_symbolizer const& sym, sym, feature, prj_trans, common_, clip_box, renderer_context); } -template void agg_renderer::process(markers_symbolizer const&, +template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 950e9cb58..68a8df15c 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ void agg_renderer::process(point_symbolizer const& sym, }); } -template void agg_renderer::process(point_symbolizer const&, +template void agg_renderer::process(point_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index abcbdf7bd..cb33a04ee 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -64,18 +64,22 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, boost::optional marker_ptr = marker_cache::instance().find(filename, true); if (!marker_ptr || !(*marker_ptr)) return; - boost::optional pat; + boost::optional > pat; if ((*marker_ptr)->is_bitmap()) { - pat = (*marker_ptr)->get_bitmap_data(); + pat = boost::optional>( + std::make_shared( + std::move(util::get(**(*marker_ptr)->get_bitmap_data()) + ))); + //pat = (*marker_ptr)->get_bitmap_data(); } else { agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym, keys::image_transform); if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); + pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); } if (!pat) return; @@ -83,7 +87,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, using clipped_geometry_type = agg::conv_clip_polygon; using path_type = transform_path_adapter; - agg::rendering_buffer buf(current_buffer_->raw_data(), current_buffer_->width(), + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); ras_ptr->reset(); value_double gamma = get(sym, feature, common_.vars_); @@ -180,7 +184,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, } -template void agg_renderer::process(polygon_pattern_symbolizer const&, +template void agg_renderer::process(polygon_pattern_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index b7ed299d4..1a73838a5 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -75,8 +76,12 @@ void agg_renderer::process(text_symbolizer const& sym, } } -template void agg_renderer::process(text_symbolizer const&, +template void agg_renderer::process(text_symbolizer const&, mapnik::feature_impl &, proj_transform const&); +//template void agg_renderer::process(text_symbolizer const&, +// mapnik::feature_impl &, +// proj_transform const&); + } diff --git a/src/build.py b/src/build.py index 6e96f7363..0103aa8a8 100644 --- a/src/build.py +++ b/src/build.py @@ -153,6 +153,7 @@ source = Split( color.cpp conversions.cpp image.cpp + image_convert.cpp image_compositing.cpp image_scaling.cpp box2d.cpp diff --git a/src/cairo/cairo_context.cpp b/src/cairo/cairo_context.cpp index 8f2c60a61..3458cfa75 100644 --- a/src/cairo/cairo_context.cpp +++ b/src/cairo/cairo_context.cpp @@ -32,6 +32,57 @@ #include namespace mapnik { +namespace detail { + +struct visitor_context_add_image_1 +{ + visitor_context_add_image_1(cairo_context & context, double x, double y, double opacity) + : context_(context), x_(x), y_(y), opacity_(opacity) {} + + template + void operator() (T & data) + { + throw std::runtime_error("Cairo currently does not support this image data type."); + } + + private: + cairo_context & context_; + double x_; + double y_; + double opacity_; +}; + +template <> +void visitor_context_add_image_1::operator() (image_data_rgba8 & data) +{ + context_.add_image(x_, y_, data, opacity_); +} + +struct visitor_context_add_image_2 +{ + visitor_context_add_image_2(cairo_context & context, agg::trans_affine const& tr, double opacity) + : context_(context), tr_(tr), opacity_(opacity) {} + + template + void operator() (T & data) + { + throw std::runtime_error("Cairo currently does not support this image data type."); + } + + private: + cairo_context & context_; + agg::trans_affine const& tr_; + double opacity_; +}; + +template <> +void visitor_context_add_image_2::operator() (image_data_rgba8 & data) +{ + context_.add_image(tr_, data, opacity_); +} + +} // end detail ns + cairo_face::cairo_face(std::shared_ptr const& library, face_ptr const& face) : face_(face) { @@ -337,6 +388,16 @@ void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d + std::shared_ptr operator() (T & data) + { + throw std::runtime_error("This data type is not supported by cairo rendering in mapnik."); + } + + private: + float opacity_; +}; + +template <> +std::shared_ptr visitor_create_pattern::operator() (image_data_rgba8 & data) +{ + return std::make_shared(data, opacity_); +} + +} // end detail ns + template void cairo_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -61,12 +87,12 @@ void cairo_renderer::process(line_pattern_symbolizer const& sym, cairo_save_restore guard(context_); context_.set_operator(comp_op); std::shared_ptr pattern; - image_ptr image = nullptr; + std::shared_ptr image = nullptr; // TODO - re-implement at renderer level like polygon_pattern symbolizer double opacity = get(sym, feature, common_.vars_); if ((*marker)->is_bitmap()) { - pattern = std::make_unique(**((*marker)->get_bitmap_data()), opacity); + pattern = util::apply_visitor(detail::visitor_create_pattern(opacity), **((*marker)->get_bitmap_data())); context_.set_line_width(height); } else @@ -75,7 +101,7 @@ void cairo_renderer::process(line_pattern_symbolizer const& sym, agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym, keys::image_transform); if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - image = render_pattern(ras, **marker, image_tr, 1.0); + image = render_pattern(ras, **marker, image_tr, 1.0); pattern = std::make_unique(*image, opacity); width = image->width(); height = image->height(); diff --git a/src/cairo/process_markers_symbolizer.cpp b/src/cairo/process_markers_symbolizer.cpp index d741c64f1..fe80a0106 100644 --- a/src/cairo/process_markers_symbolizer.cpp +++ b/src/cairo/process_markers_symbolizer.cpp @@ -86,7 +86,7 @@ private: template struct raster_markers_dispatch_cairo : public raster_markers_dispatch { - raster_markers_dispatch_cairo(mapnik::image_data_rgba8 & src, + raster_markers_dispatch_cairo(mapnik::image_data_any & src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, diff --git a/src/cairo/process_polygon_pattern_symbolizer.cpp b/src/cairo/process_polygon_pattern_symbolizer.cpp index 1394d6540..99e0e507c 100644 --- a/src/cairo/process_polygon_pattern_symbolizer.cpp +++ b/src/cairo/process_polygon_pattern_symbolizer.cpp @@ -37,6 +37,37 @@ namespace mapnik { +namespace detail +{ + +struct visitor_set_pattern +{ + visitor_set_pattern(cairo_context & context, unsigned offset_x, unsigned offset_y, float opacity) + : context_(context), offset_x_(offset_x), offset_y_(offset_y), opacity_(opacity) {} + + template + void operator() (T & data) + { + throw std::runtime_error("This data type is not supported by cairo rendering in mapnik."); + } + private: + cairo_context & context_; + unsigned offset_x_; + unsigned offset_y_; + float opacity_; +}; + +template <> +void visitor_set_pattern::operator() (image_data_rgba8 & data) +{ + cairo_pattern pattern(data, opacity_); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_origin(offset_x_, offset_y_); + context_.set_pattern(pattern); +} + +} // end detail ns + template void cairo_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -83,15 +114,12 @@ void cairo_renderer::process(polygon_pattern_symbolizer const& sym, if ((*marker)->is_bitmap()) { - cairo_pattern pattern(**((*marker)->get_bitmap_data()), opacity); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x, offset_y); - context_.set_pattern(pattern); + util::apply_visitor(detail::visitor_set_pattern(context_, offset_x, offset_y, opacity), **((*marker)->get_bitmap_data())); } else { mapnik::rasterizer ras; - image_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // + std::shared_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // cairo_pattern pattern(*image, opacity); pattern.set_extend(CAIRO_EXTEND_REPEAT); pattern.set_origin(offset_x, offset_y); diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 42fad26a5..0cb62b704 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #if defined(GRID_RENDERER) #include @@ -55,6 +56,6 @@ template class feature_style_processor template class feature_style_processor >; #endif -template class feature_style_processor >; +template class feature_style_processor >; } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index c72f9d1ca..55f103232 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -165,7 +165,7 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ } else { - image_data_rgba8 const& data = **marker.get_bitmap_data(); + image_data_rgba8 const& data = util::get(**marker.get_bitmap_data()); double width = data.width(); double height = data.height(); double cx = 0.5 * width; diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 2188c0340..c1bbe15eb 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -115,7 +115,7 @@ struct thunk_renderer renderer_type ren(renb); agg::trans_affine offset_tr = thunk.tr_; offset_tr.translate(offset_.x, offset_.y); - render_raster_marker(ren, ras_, thunk.src_, feature_, offset_tr, thunk.opacity_); + render_raster_marker(ren, ras_, util::get(thunk.src_), feature_, offset_tr, thunk.opacity_); pixmap_.add_feature(feature_); } diff --git a/src/image_util.cpp b/src/image_util.cpp index 40c3e90f0..ab54e217a 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -56,7 +56,7 @@ namespace mapnik { template -std::string save_to_string(T const& image, +MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type, rgba_palette const& palette) { @@ -66,7 +66,7 @@ std::string save_to_string(T const& image, } template -std::string save_to_string(T const& image, +MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type) { std::ostringstream ss(std::ios::out|std::ios::binary); @@ -75,7 +75,7 @@ std::string save_to_string(T const& image, } template -void save_to_file(T const& image, +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type, rgba_palette const& palette) @@ -89,7 +89,7 @@ void save_to_file(T const& image, } template -void save_to_file(T const& image, +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type) { @@ -102,7 +102,7 @@ void save_to_file(T const& image, } template -void save_to_stream(T const& image, +MAPNIK_DECL void save_to_stream(T const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) @@ -132,7 +132,7 @@ void save_to_stream(T const& image, // This can be removed once image_data_any and image_view_any are the only // items using this template template <> -void save_to_stream(image_data_rgba8 const& image, +MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) @@ -163,7 +163,7 @@ void save_to_stream(image_data_rgba8 const& image, // This can be removed once image_data_any and image_view_any are the only // items using this template template <> -void save_to_stream(image_view_rgba8 const& image, +MAPNIK_DECL void save_to_stream(image_view_rgba8 const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) @@ -192,7 +192,7 @@ void save_to_stream(image_view_rgba8 const& image, } template -void save_to_stream(T const& image, +MAPNIK_DECL void save_to_stream(T const& image, std::ostream & stream, std::string const& type) { @@ -228,7 +228,7 @@ void save_to_stream(T const& image, // This can be removed once image_data_any and image_view_any are the only // items using this template template <> -void save_to_stream(image_data_rgba8 const& image, +MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, std::ostream & stream, std::string const& type) { @@ -268,7 +268,7 @@ void save_to_stream(image_data_rgba8 const& image, // This can be removed once image_data_any and image_view_any are the only // items using this template template <> -void save_to_stream(image_view_rgba8 const& image, +MAPNIK_DECL void save_to_stream(image_view_rgba8 const& image, std::ostream & stream, std::string const& type) { @@ -306,7 +306,7 @@ void save_to_stream(image_view_rgba8 const& image, } template -void save_to_file(T const& image, std::string const& filename) +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename) { boost::optional type = type_from_filename(filename); if (type) @@ -317,7 +317,7 @@ void save_to_file(T const& image, std::string const& filename) } template -void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) { boost::optional type = type_from_filename(filename); if (type) @@ -328,74 +328,74 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons } // image_data_rgba8 -template void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&); -template void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, std::string const&, rgba_palette const& palette); -template void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&); -template void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&, rgba_palette const& palette); -template std::string save_to_string(image_data_rgba8 const&, +template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, std::string const&); -template std::string save_to_string(image_data_rgba8 const&, +template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, std::string const&, rgba_palette const& palette); -// image_view_rgba8 -template void save_to_file (image_view_rgba8 const&, +// image_view_any +template MAPNIK_DECL void save_to_file (image_view_any const&, std::string const&, std::string const&); -template void save_to_file (image_view_rgba8 const&, +template MAPNIK_DECL void save_to_file (image_view_any const&, std::string const&, std::string const&, rgba_palette const& palette); -template void save_to_file (image_view_rgba8 const&, +template MAPNIK_DECL void save_to_file (image_view_any const&, std::string const&); -template void save_to_file (image_view_rgba8 const&, +template MAPNIK_DECL void save_to_file (image_view_any const&, std::string const&, rgba_palette const& palette); -template std::string save_to_string (image_view_rgba8 const&, +template MAPNIK_DECL std::string save_to_string (image_view_any const&, std::string const&); -template std::string save_to_string (image_view_rgba8 const&, +template MAPNIK_DECL std::string save_to_string (image_view_any const&, std::string const&, rgba_palette const& palette); // image_data_any -template void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_data_any const&, std::string const&, std::string const&); -template void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_data_any const&, std::string const&, std::string const&, rgba_palette const& palette); -template void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_data_any const&, std::string const&); -template void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_data_any const&, std::string const&, rgba_palette const& palette); -template std::string save_to_string(image_data_any const&, +template MAPNIK_DECL std::string save_to_string(image_data_any const&, std::string const&); -template std::string save_to_string(image_data_any const&, +template MAPNIK_DECL std::string save_to_string(image_data_any const&, std::string const&, rgba_palette const& palette); @@ -450,8 +450,8 @@ MAPNIK_DECL bool is_solid(T const& image) return util::apply_visitor(detail::is_solid_visitor(), image); } -template bool is_solid (image_data_any const&); -template bool is_solid (image_view_any const&); +template MAPNIK_DECL bool is_solid (image_data_any const&); +template MAPNIK_DECL bool is_solid (image_view_any const&); // Temporary until image_data_rgba8 is removed from passing template <> @@ -541,7 +541,7 @@ MAPNIK_DECL bool premultiply_alpha(T & image) return util::apply_visitor(detail::premultiply_visitor(), image); } -template bool premultiply_alpha (image_data_any &); +template MAPNIK_DECL bool premultiply_alpha (image_data_any &); // Temporary, can be removed once image_view_any and image_data_any are the only ones passed template <> @@ -557,7 +557,7 @@ MAPNIK_DECL bool demultiply_alpha(T & image) return util::apply_visitor(detail::demultiply_visitor(), image); } -template bool demultiply_alpha (image_data_any &); +template MAPNIK_DECL bool demultiply_alpha (image_data_any &); // Temporary, can be removed once image_view_any and image_data_any are the only ones passed template <> @@ -828,15 +828,15 @@ MAPNIK_DECL void fill (T1 & data, T2 const& val) util::apply_visitor(detail::visitor_fill(val), data); } -template void fill(image_data_any &, color const&); -template void fill(image_data_any &, uint32_t const&); -template void fill(image_data_any &, int32_t const&); -template void fill(image_data_any &, uint16_t const&); -template void fill(image_data_any &, int16_t const&); -template void fill(image_data_any &, uint8_t const&); -template void fill(image_data_any &, int8_t const&); -template void fill(image_data_any &, float const&); -template void fill(image_data_any &, double const&); +template MAPNIK_DECL void fill(image_data_any &, color const&); +template MAPNIK_DECL void fill(image_data_any &, uint32_t const&); +template MAPNIK_DECL void fill(image_data_any &, int32_t const&); +template MAPNIK_DECL void fill(image_data_any &, uint16_t const&); +template MAPNIK_DECL void fill(image_data_any &, int16_t const&); +template MAPNIK_DECL void fill(image_data_any &, uint8_t const&); +template MAPNIK_DECL void fill(image_data_any &, int8_t const&); +template MAPNIK_DECL void fill(image_data_any &, float const&); +template MAPNIK_DECL void fill(image_data_any &, double const&); // Temporary remove these later! @@ -1071,15 +1071,15 @@ MAPNIK_DECL void set_pixel (T1 & data, std::size_t x, std::size_t y, T2 const& v util::apply_visitor(detail::visitor_set_pixel(x, y, val), data); } -template void set_pixel(image_data_any &, std::size_t, std::size_t, color const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, uint32_t const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, int32_t const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, uint16_t const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, int16_t const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, uint8_t const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, int8_t const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, float const&); -template void set_pixel(image_data_any &, std::size_t, std::size_t, double const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, double const&); // Temporary remove these later! @@ -1169,15 +1169,15 @@ MAPNIK_DECL T2 get_pixel (T1 const& data, std::size_t x, std::size_t y) return util::apply_visitor(detail::visitor_get_pixel(x, y), data); } -template color get_pixel(image_data_any const&, std::size_t, std::size_t); -template uint32_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template int32_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template uint16_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template int16_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template uint8_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template int8_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template float get_pixel(image_data_any const&, std::size_t, std::size_t); -template double get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL color get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_data_any const&, std::size_t, std::size_t); // Temporary remove these later! @@ -1204,4 +1204,68 @@ MAPNIK_DECL int32_t get_pixel (image_data_rgba8 const return visitor(data); } +namespace detail +{ + +struct visitor_view_to_string +{ + visitor_view_to_string(std::ostringstream & ss) + : ss_(ss) {} + + template + void operator() (T const& view) + { + for (std::size_t i=0;i(view.getRow(i)), + view.getRowSize()); + } + } + + private: + std::ostringstream & ss_; +}; + +} // end detail ns + + +MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss) +{ + util::apply_visitor(detail::visitor_view_to_string(ss), view); +} + +namespace detail +{ + +struct visitor_create_view +{ + visitor_create_view(unsigned x,unsigned y, unsigned w, unsigned h) + : x_(x), y_(y), w_(w), h_(h) {} + + template + image_view_any operator() (T const& data) + { + image_view view(x_,y_,w_,h_,data); + return image_view_any(view); + } + private: + unsigned x_; + unsigned y_; + unsigned w_; + unsigned h_; +}; + +template <> +image_view_any visitor_create_view::operator() (image_data_null const&) +{ + throw std::runtime_error("Can not make a view from a null image"); +} + +} // end detail ns + +MAPNIK_DECL image_view_any create_view(image_data_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) +{ + return util::apply_visitor(detail::visitor_create_view(x,y,w,h), data); +} + } // end ns diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index de42f1552..2ebc027ef 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -62,9 +62,7 @@ marker_cache::marker_cache() "" "" ""); - boost::optional bitmap_data = boost::optional(std::make_shared(4,4)); - (*bitmap_data)->set(0xff000000); - marker_ptr mark = std::make_shared(bitmap_data); + marker_ptr mark = std::make_shared(); marker_cache_.emplace("image://square",mark); } @@ -120,6 +118,35 @@ bool marker_cache::insert_marker(std::string const& uri, marker_ptr path) return marker_cache_.emplace(uri,path).second; } +namespace detail +{ + +struct visitor_create_marker +{ + template + marker_ptr operator() (T & data) + { + std::shared_ptr image = std::make_shared(std::move(data)); + return std::make_shared(image); + } +}; + +template<> +marker_ptr visitor_create_marker::operator() (image_data_rgba8 & data) +{ + std::shared_ptr image = std::make_shared(std::move(data)); + mapnik::premultiply_alpha(*image); + return std::make_shared(image); +} + +template<> +marker_ptr visitor_create_marker::operator() (image_data_null & data) +{ + throw std::runtime_error("Can not make marker from null image data type"); +} + +} // end detail ns + boost::optional marker_cache::find(std::string const& uri, bool update_cache) { @@ -210,14 +237,7 @@ boost::optional marker_cache::find(std::string const& uri, unsigned width = reader->width(); unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); - image_data_any im = reader->read(0,0,width,height); - if (!im.is()) - { - throw std::runtime_error("Error: Only image_data_rgba8 types are supported currenctly by markers"); - } - mapnik::premultiply_alpha(im); - mapnik::image_ptr image(std::make_shared(std::move(util::get(im)))); - marker_ptr mark(std::make_shared(image)); + marker_ptr mark(util::apply_visitor(detail::visitor_create_marker(), reader->read(0,0,width,height))); result.reset(mark); if (update_cache) { diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index 669de0d09..30de4e1a3 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -39,7 +39,7 @@ vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) {} -raster_marker_render_thunk::raster_marker_render_thunk(image_data_rgba8 & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_data_any & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -97,7 +97,7 @@ private: template struct raster_marker_thunk_dispatch : public raster_markers_dispatch { - raster_marker_thunk_dispatch(image_data_rgba8 & src, + raster_marker_thunk_dispatch(image_data_any & src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index bb404cdb0..0156cf10a 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -30,12 +30,15 @@ #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" +#include "agg_pixfmt_gray.h" #include "agg_color_rgba.h" +#include "agg_color_gray.h" #include "agg_scanline_u.h" namespace mapnik { -std::shared_ptr render_pattern(rasterizer & ras, +template <> +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity) @@ -61,11 +64,123 @@ std::shared_ptr render_pattern(rasterizer & ras, mapnik::svg::svg_renderer_agg, renderer_solid, - agg::pixfmt_rgba32_pre > svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); + pixfmt > svg_renderer(svg_path, + (*marker.get_vector_data())->attributes()); svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); return image; } +template <> +std::shared_ptr render_pattern(rasterizer & ras, + marker const& marker, + agg::trans_affine const& tr, + double opacity) +{ + throw std::runtime_error("Can not return image_data_null type from render pattern"); +} +/* +template <> +std::shared_ptr render_pattern(rasterizer & ras, + marker const& marker, + agg::trans_affine const& tr, + double opacity) +{ + using pixfmt = agg::pixfmt_gray8_pre; + using renderer_base = agg::renderer_base; + using renderer_solid = agg::renderer_scanline_aa_solid; + agg::scanline_u8 sl; + + mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; + mapnik::coord c = bbox.center(); + agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); + mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); + mtx = tr * mtx; + + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width()); + pixfmt pixf(buf); + renderer_base renb(pixf); + + mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + mapnik::svg::svg_path_adapter svg_path(stl_storage); + mapnik::svg::svg_renderer_agg, + renderer_solid, + pixfmt > svg_renderer(svg_path, + (*marker.get_vector_data())->attributes()); + + svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); + return image; +} + +template <> +std::shared_ptr render_pattern(rasterizer & ras, + marker const& marker, + agg::trans_affine const& tr, + double opacity) +{ + using pixfmt = agg::pixfmt_gray16_pre; + using renderer_base = agg::renderer_base; + using renderer_solid = agg::renderer_scanline_aa_solid; + agg::scanline_u8 sl; + + mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; + mapnik::coord c = bbox.center(); + agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); + mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); + mtx = tr * mtx; + + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 2); + pixfmt pixf(buf); + renderer_base renb(pixf); + + mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + mapnik::svg::svg_path_adapter svg_path(stl_storage); + mapnik::svg::svg_renderer_agg, + renderer_solid, + pixfmt > svg_renderer(svg_path, + (*marker.get_vector_data())->attributes()); + + svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); + return image; +} + +template <> +std::shared_ptr render_pattern(rasterizer & ras, + marker const& marker, + agg::trans_affine const& tr, + double opacity) +{ + using pixfmt = agg::pixfmt_gray32_pre; + using renderer_base = agg::renderer_base; + using renderer_solid = agg::renderer_scanline_aa_solid; + agg::scanline_u8 sl; + + mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; + mapnik::coord c = bbox.center(); + agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); + mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); + mtx = tr * mtx; + + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4); + pixfmt pixf(buf); + renderer_base renb(pixf); + + mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + mapnik::svg::svg_path_adapter svg_path(stl_storage); + mapnik::svg::svg_renderer_agg, + renderer_solid, + pixfmt > svg_renderer(svg_path, + (*marker.get_vector_data())->attributes()); + + svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); + return image; +} +*/ + } // namespace mapnik diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index c44010ac6..21c34b8d9 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace mapnik { @@ -103,7 +104,7 @@ void composite_bitmap(T & pixmap, FT_Bitmap *bitmap, unsigned rgba, int x, int y unsigned gray=bitmap->buffer[q*bitmap->width+p]; if (gray) { - mapnik::composite_pixel(pixmap.data(), comp_op, i, j, rgba, gray, opacity); + mapnik::composite_pixel(pixmap, comp_op, i, j, rgba, gray, opacity); } } } @@ -292,17 +293,17 @@ void agg_text_renderer::render_halo(FT_Bitmap *bitmap, int gray = bitmap->buffer[y*bitmap->width+x]; if (gray) { - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1-1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1, y+y1-1, rgba, gray*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1-1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1, y+y1-1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1-1, y+y1, rgba, gray*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1, y+y1, rgba, gray, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+1, y+y1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1-1, y+y1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1, y+y1, rgba, gray, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+1, y+y1, rgba, gray*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1-1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1, y+y1+1, rgba, gray*halo_radius, opacity); - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1-1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1, y+y1+1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); } } } @@ -318,7 +319,7 @@ void agg_text_renderer::render_halo(FT_Bitmap *bitmap, { for (int n=-halo_radius; n <=halo_radius; ++n) for (int m=-halo_radius; m <= halo_radius; ++m) - mapnik::composite_pixel(pixmap_.data(), comp_op, x+x1+m, y+y1+n, rgba, gray, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+m, y+y1+n, rgba, gray, opacity); } } } @@ -358,7 +359,8 @@ grid_text_renderer::grid_text_renderer(pixmap_type &pixmap, : text_renderer(HALO_RASTERIZER_FAST, comp_op, src_over, scale_factor), pixmap_(pixmap) {} -template class agg_text_renderer; +template class agg_text_renderer; +//template class agg_text_renderer; template class grid_text_renderer; } // namespace mapnik From 97869f7dc18c6dba3cf392e0a87e5f80f53abcca Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Sun, 18 Jan 2015 22:16:20 -0800 Subject: [PATCH 44/91] minor include cleanup for image_utils --- include/mapnik/image_util.hpp | 3 --- src/image_util.cpp | 8 +------- src/image_util_tiff.cpp | 2 -- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index fa67d299d..9d249f4e4 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -29,7 +29,6 @@ #include #include #include -#include #include // boost @@ -41,13 +40,11 @@ // stl #include -#include #include namespace mapnik { // fwd declares -class Map; class rgba_palette; class ImageWriterException : public std::exception diff --git a/src/image_util.cpp b/src/image_util.cpp index ab54e217a..e5b403ca5 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -29,17 +29,12 @@ #include #include #include -#include #include #include -#include #include -#include +#include #include -// boost -#include - // agg #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -47,7 +42,6 @@ // stl #include -#include #include #include #include diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index f4a94ffc7..533eeb2a3 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -37,7 +36,6 @@ // stl #include -#include namespace mapnik { From badb0c9a97acd9043208032827c7a3fc7c70abf5 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 20 Jan 2015 18:30:10 -0600 Subject: [PATCH 45/91] This is a complete removal of code that utilizes image_32 in the library. It is a sweeping change that does some of the following: * Changes all agg_renderers to use a image_data_any variant (only image_data_rgba8 is implemented currently) * Changes the marker and marker_cache to use image_data_any images * Changes the symbolizers so that they must be aware of the source data type they are attempting to render and the render type that is expected to be rendered into. * Moves many utilities into image_utils, that were previously in image_32. The kicker is that this still isn't working perfectly yet, but I am commiting so I don't have tears in case everything is lost on my computer. Ref #2633 --- benchmark/compare_images.hpp | 8 +- benchmark/test_png_encoding2.cpp | 10 +- benchmark/test_polygon_clipping.cpp | 8 +- benchmark/test_polygon_clipping_rendering.cpp | 8 +- benchmark/test_rendering.cpp | 8 +- benchmark/test_rendering_shared_map.cpp | 14 +- bindings/python/mapnik_python.cpp | 123 +++++++++++++++-- demo/c++/rundemo.cpp | 4 +- demo/viewer/mapwidget.cpp | 11 +- include/mapnik/agg_renderer.hpp | 3 - include/mapnik/image_convert.hpp | 36 +++++ .../process_group_symbolizer.hpp | 15 ++- .../process_markers_symbolizer.hpp | 1 + src/agg/agg_renderer.cpp | 17 +-- src/agg/process_building_symbolizer.cpp | 10 -- src/agg/process_debug_symbolizer.cpp | 9 -- src/agg/process_dot_symbolizer.cpp | 9 -- src/agg/process_group_symbolizer.cpp | 124 +++--------------- src/agg/process_line_symbolizer.cpp | 2 +- src/agg/process_markers_symbolizer.cpp | 6 +- src/agg/process_point_symbolizer.cpp | 2 +- src/agg/process_polygon_symbolizer.cpp | 4 +- src/agg/process_raster_symbolizer.cpp | 4 +- src/agg/process_shield_symbolizer.cpp | 2 +- src/agg/process_text_symbolizer.cpp | 6 +- src/cairo/process_group_symbolizer.cpp | 4 +- src/cairo/process_markers_symbolizer.cpp | 2 +- src/feature_style_processor.cpp | 2 +- src/grid/process_group_symbolizer.cpp | 19 ++- src/grid/process_markers_symbolizer.cpp | 6 +- src/image_convert.cpp | 62 +++++++++ .../process_group_symbolizer.cpp | 72 +++++++++- src/text/renderer.cpp | 3 +- tests/cpp_tests/exceptions_test.cpp | 4 +- tests/cpp_tests/fontset_runtime_test.cpp | 4 +- tests/cpp_tests/image_io_test.cpp | 10 -- tests/cpp_tests/image_painted_test.cpp | 4 +- tests/cpp_tests/map_request_test.cpp | 32 ++--- utils/nik2img/nik2img.cpp | 6 +- utils/svg2png/svg2png.cpp | 8 +- 40 files changed, 415 insertions(+), 267 deletions(-) create mode 100644 include/mapnik/image_convert.hpp create mode 100644 src/image_convert.cpp diff --git a/benchmark/compare_images.hpp b/benchmark/compare_images.hpp index 60f9f0d1c..b31c62a33 100644 --- a/benchmark/compare_images.hpp +++ b/benchmark/compare_images.hpp @@ -17,19 +17,15 @@ namespace benchmark { { throw mapnik::image_reader_exception("Failed to load: " + dest_fn); } - std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); - reader1->read(0,0,image_ptr1->data()); std::unique_ptr reader2(mapnik::get_image_reader(src_fn,"png")); if (!reader2.get()) { throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); - reader2->read(0,0,image_ptr2->data()); - image_data_rgba8 const& dest = image_ptr1->data(); - image_data_rgba8 const& src = image_ptr2->data(); + image_data_rgba8 const& dest = util::get(reader1->read(0,0,reader1->width(), reader1->height())); + image_data_rgba8 const& src = util::get(reader1->read(0,0,reader1->width(), reader1->height())); unsigned int width = src.width(); unsigned int height = src.height(); diff --git a/benchmark/test_png_encoding2.cpp b/benchmark/test_png_encoding2.cpp index da55bf29e..798d0690a 100644 --- a/benchmark/test_png_encoding2.cpp +++ b/benchmark/test_png_encoding2.cpp @@ -3,7 +3,7 @@ class test : public benchmark::test_case { - std::shared_ptr im_; + std::shared_ptr im_; public: test(mapnik::parameters const& params) : test_case(params) { @@ -13,14 +13,14 @@ public: { throw mapnik::image_reader_exception("Failed to load: " + filename); } - im_ = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,im_->data()); + im_ = std::make_shared(reader->width(),reader->height()); + reader->read(0,0,*im_); } bool validate() const { std::string expected("./benchmark/data/multicolor-hextree-expected.png"); std::string actual("./benchmark/data/multicolor-hextree-actual.png"); - mapnik::save_to_file(im_->data(),actual, "png8:m=h:z=1"); + mapnik::save_to_file(*im_,actual, "png8:m=h:z=1"); return benchmark::compare_images(actual,expected); } bool operator()() const @@ -28,7 +28,7 @@ public: std::string out; for (std::size_t i=0;idata(),"png8:m=h:z=1"); + out = mapnik::save_to_string(*im_,"png8:m=h:z=1"); } } return true; diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index 9b6184b0c..ad3dd3a75 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -37,12 +37,12 @@ void render(mapnik::geometry_type & geom, using path_type = mapnik::transform_path_adapter; using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; - mapnik::image_32 im(256,256); - im.set_background(mapnik::color("white")); + mapnik::image_data_rgba8 im(256,256); + mapnik::fill(im, mapnik::color("white")); mapnik::box2d padded_extent = extent; padded_extent.pad(10); mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0); - agg::rendering_buffer buf(im.raw_data(),im.width(),im.height(), im.width() * 4); + agg::rendering_buffer buf(im.getBytes(),im.width(),im.height(), im.width() * 4); agg::pixfmt_rgba32_plain pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -54,7 +54,7 @@ void render(mapnik::geometry_type & geom, ras.add_path(path); agg::scanline_u8 sl; agg::render_scanlines(ras, sl, ren); - mapnik::save_to_file(im.data(),name); + mapnik::save_to_file(im,name); geom.rewind(0); } diff --git a/benchmark/test_polygon_clipping_rendering.cpp b/benchmark/test_polygon_clipping_rendering.cpp index f4ba0f44b..0de0bb631 100644 --- a/benchmark/test_polygon_clipping_rendering.cpp +++ b/benchmark/test_polygon_clipping_rendering.cpp @@ -22,8 +22,8 @@ public: mapnik::Map m(256,256); mapnik::load_map(m,xml_); m.zoom_to_box(extent_); - mapnik::image_32 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im); + mapnik::image_data_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); ren.apply(); //mapnik::save_to_file(im.data(),"test.png"); return true; @@ -35,8 +35,8 @@ public: m.zoom_to_box(extent_); for (unsigned i=0;i ren(m,im); + mapnik::image_data_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); ren.apply(); } return true; diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp index ffaa100df..c82b1a30d 100644 --- a/benchmark/test_rendering.cpp +++ b/benchmark/test_rendering.cpp @@ -55,8 +55,8 @@ public: } else { m.zoom_all(); } - mapnik::image_32 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im,scale_factor_); + mapnik::image_data_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im,scale_factor_); ren.apply(); if (!preview_.empty()) { std::clog << "preview available at " << preview_ << "\n"; @@ -78,8 +78,8 @@ public: } for (unsigned i=0;i ren(m,im,scale_factor_); + mapnik::image_data_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im,scale_factor_); ren.apply(); } return true; diff --git a/benchmark/test_rendering_shared_map.cpp b/benchmark/test_rendering_shared_map.cpp index c5d5b08f8..0c94b910c 100644 --- a/benchmark/test_rendering_shared_map.cpp +++ b/benchmark/test_rendering_shared_map.cpp @@ -50,7 +50,7 @@ class test : public benchmark::test_case std::shared_ptr m_; double scale_factor_; std::string preview_; - mutable mapnik::image_32 im_; + mutable mapnik::image_data_rgba8 im_; public: test(mapnik::parameters const& params) : test_case(params), @@ -94,14 +94,14 @@ public: mapnik::projection map_proj(m_->srs(),true); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); scale_denom *= scale_factor_; - mapnik::agg_renderer ren(*m_,m_req,variables,im_,scale_factor_); + mapnik::agg_renderer ren(*m_,m_req,variables,im_,scale_factor_); ren.start_map_processing(*m_); std::vector const& layers = m_->layers(); process_layers(ren,m_req,map_proj,layers,scale_denom); ren.end_map_processing(*m_); if (!preview_.empty()) { std::clog << "preview available at " << preview_ << "\n"; - mapnik::save_to_file(im_.data(),preview_); + mapnik::save_to_file(im_,preview_); } return true; } @@ -114,20 +114,20 @@ public: for (unsigned i=0;iwidth(),m_->height()); + mapnik::image_data_rgba8 im(m_->width(),m_->height()); mapnik::attributes variables; m_req.set_buffer_size(m_->buffer_size()); mapnik::projection map_proj(m_->srs(),true); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); scale_denom *= scale_factor_; - mapnik::agg_renderer ren(*m_,m_req,variables,im,scale_factor_); + mapnik::agg_renderer ren(*m_,m_req,variables,im,scale_factor_); ren.start_map_processing(*m_); std::vector const& layers = m_->layers(); process_layers(ren,m_req,map_proj,layers,scale_denom); ren.end_map_processing(*m_); bool diff = false; - mapnik::image_data_rgba8 const& dest = im.data(); - mapnik::image_data_rgba8 const& src = im_.data(); + mapnik::image_data_rgba8 const& dest = im; + mapnik::image_data_rgba8 const& src = im_; for (unsigned int y = 0; y < height_; ++y) { const unsigned int* row_from = src.getRow(y); diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 927ae6688..89e92519d 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -190,6 +190,117 @@ bool python_thread::thread_support = true; #endif boost::thread_specific_ptr python_thread::state; +struct agg_renderer_visitor_1 +{ + agg_renderer_visitor_1(mapnik::Map const& m, double scale_factor, unsigned offset_x, unsigned offset_y) + : m_(m), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; +}; + +template <> +void agg_renderer_visitor_1::operator() (mapnik::image_data_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); + ren.apply(); +} + +struct agg_renderer_visitor_2 +{ + agg_renderer_visitor_2(mapnik::Map const &m, std::shared_ptr detector, + double scale_factor, unsigned offset_x, unsigned offset_y) + : m_(m), detector_(detector), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + std::shared_ptr detector_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; +}; + +template <> +void agg_renderer_visitor_2::operator() (mapnik::image_data_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,pixmap,detector_, scale_factor_,offset_x_, offset_y_); + ren.apply(); +} + +struct agg_renderer_visitor_3 +{ + agg_renderer_visitor_3(mapnik::Map const& m, mapnik::request const& req, mapnik::attributes const& vars, + double scale_factor, unsigned offset_x, unsigned offset_y) + : m_(m), req_(req), vars_(vars), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + mapnik::request const& req_; + mapnik::attributes const& vars_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; + +}; + +template <> +void agg_renderer_visitor_3::operator() (mapnik::image_data_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,req_, vars_, pixmap, scale_factor_, offset_x_, offset_y_); + ren.apply(); +} + +struct agg_renderer_visitor_4 +{ + agg_renderer_visitor_4(mapnik::Map const& m, double scale_factor, unsigned offset_x, unsigned offset_y, + mapnik::layer const& layer, std::set& names) + : m_(m), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y), + layer_(layer), names_(names) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; + mapnik::layer const& layer_; + std::set & names_; +}; + +template <> +void agg_renderer_visitor_4::operator() (mapnik::image_data_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); + ren.apply(layer_, names_); +} + + void render(mapnik::Map const& map, mapnik::image_data_any& image, double scale_factor = 1.0, @@ -197,8 +308,7 @@ void render(mapnik::Map const& map, unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::agg_renderer ren(map,image,scale_factor,offset_x, offset_y); - ren.apply(); + mapnik::util::apply_visitor(agg_renderer_visitor_1(map, scale_factor, offset_x, offset_y), image); } void render_with_vars(mapnik::Map const& map, @@ -212,8 +322,7 @@ void render_with_vars(mapnik::Map const& map, mapnik::request req(map.width(),map.height(),map.get_current_extent()); req.set_buffer_size(map.buffer_size()); python_unblock_auto_block b; - mapnik::agg_renderer ren(map,req,vars,image,scale_factor,offset_x,offset_y); - ren.apply(); + mapnik::util::apply_visitor(agg_renderer_visitor_3(map, req, vars, scale_factor, offset_x, offset_y), image); } void render_with_detector( @@ -225,8 +334,7 @@ void render_with_detector( unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::agg_renderer ren(map,image,detector,scale_factor,offset_x,offset_y); - ren.apply(); + mapnik::util::apply_visitor(agg_renderer_visitor_2(map, detector, scale_factor, offset_x, offset_y), image); } void render_layer2(mapnik::Map const& map, @@ -247,9 +355,8 @@ void render_layer2(mapnik::Map const& map, python_unblock_auto_block b; mapnik::layer const& layer = layers[layer_idx]; - mapnik::agg_renderer ren(map,image,scale_factor,offset_x,offset_y); std::set names; - ren.apply(layer,names); + mapnik::util::apply_visitor(agg_renderer_visitor_4(map, scale_factor, offset_x, offset_y, layer, names), image); } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index 8f568affb..66999fba1 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -306,8 +306,8 @@ int main ( int, char** ) m.zoom_to_box(box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855)); - image_32 buf(m.width(),m.height()); - agg_renderer ren(m,buf); + image_data_rgba8 buf(m.width(),m.height()); + agg_renderer ren(m,buf); ren.apply(); std::string msg("These maps have been rendered using AGG in the current directory:\n"); #ifdef HAVE_JPEG diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 59e396893..1c68eccde 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -42,7 +42,7 @@ #include "mapwidget.hpp" #include "info_dialog.hpp" -using mapnik::image_32; +using mapnik::image_data_rgba8; using mapnik::Map; using mapnik::layer; using mapnik::box2d; @@ -479,7 +479,7 @@ void MapWidget::zoomToLevel(int level) void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&) { - //image_32 image(width,height); + //image_data_rgba8 image(width,height); //agg_renderer renderer(map,image); //renderer.apply(); //image.saveToFile(filename,type); @@ -496,8 +496,8 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix) unsigned width=map.width(); unsigned height=map.height(); - image_32 buf(width,height); - mapnik::agg_renderer ren(map,buf,scaling_factor); + image_data_rgba8 buf(width,height); + mapnik::agg_renderer ren(map,buf,scaling_factor); try { @@ -542,8 +542,7 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) } mapnik::image_data_rgba8 data(map.width(), map.height()); mapnik::cairo_image_to_rgba8(data, image_surface); - image_32 buf(std::move(data)); - QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32); + QImage image((uchar*)data.getBytes(),data.width(),data.height(),QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); #endif } diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 6361d4011..e5aa1b117 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -172,9 +172,6 @@ private: }; extern template class MAPNIK_DECL agg_renderer; -//extern template class MAPNIK_DECL agg_renderer; -//extern template class MAPNIK_DECL agg_renderer; -//extern template class MAPNIK_DECL agg_renderer; } // namespace mapnik diff --git a/include/mapnik/image_convert.hpp b/include/mapnik/image_convert.hpp new file mode 100644 index 000000000..e57bff08d --- /dev/null +++ b/include/mapnik/image_convert.hpp @@ -0,0 +1,36 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_CONVERT_HPP +#define MAPNIK_IMAGE_CONVERT_HPP + +#include + +namespace mapnik +{ + +template +MAPNIK_DECL T2 convert_image(T1 const& data); + +} // end mapnik ns + +#endif // MAPNIK_IMAGE_CONVERT_HPP diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index c91ad894d..23657e1a4 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -128,15 +128,16 @@ struct vector_marker_render_thunk : util::noncopyable snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} }; +template struct raster_marker_render_thunk : util::noncopyable { - image_data_any & src_; + BufferType & src_; agg::trans_affine tr_; double opacity_; composite_mode_e comp_op_; bool snap_to_pixels_; - raster_marker_render_thunk(image_data_any & src, + raster_marker_render_thunk(BufferType & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -150,6 +151,11 @@ struct raster_marker_render_thunk : util::noncopyable snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} }; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; + using helper_ptr = std::unique_ptr; struct text_render_thunk : util::noncopyable @@ -179,7 +185,10 @@ struct text_render_thunk : util::noncopyable // via a static visitor later. using render_thunk = util::variant, + raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, text_render_thunk>; using render_thunk_ptr = std::unique_ptr; using render_thunk_list = std::list; diff --git a/include/mapnik/renderer_common/process_markers_symbolizer.hpp b/include/mapnik/renderer_common/process_markers_symbolizer.hpp index f62687ab9..04ff0bbaa 100644 --- a/include/mapnik/renderer_common/process_markers_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_markers_symbolizer.hpp @@ -43,6 +43,7 @@ void render_markers_symbolizer(markers_symbolizer const& sym, using namespace mapnik::svg; using vector_dispatch_type = VD; using raster_dispatch_type = RD; + using buffer_type = typename std::tuple_element<0,ContextType>::type; std::string filename = get(sym, keys::file, feature, common.vars_, "shape://ellipse"); bool clip = get(sym, feature, common.vars_); diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 63158bdae..d2683e115 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -523,19 +523,4 @@ template void agg_renderer::debug_draw_box const& box, double x, double y, double angle); -template class agg_renderer; -template void agg_renderer::debug_draw_box( - agg::rendering_buffer& buf, - box2d const& box, - double x, double y, double angle); -template class agg_renderer; -template void agg_renderer::debug_draw_box( - agg::rendering_buffer& buf, - box2d const& box, - double x, double y, double angle); -template class agg_renderer; -template void agg_renderer::debug_draw_box( - agg::rendering_buffer& buf, - box2d const& box, - double x, double y, double angle); -} +} // end ns diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 7d8c94d00..d16816f61 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -113,14 +113,4 @@ void agg_renderer::process(building_symbolizer const& sym, template void agg_renderer::process(building_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -template void agg_renderer::process(building_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); -template void agg_renderer::process(building_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); -template void agg_renderer::process(building_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); - } diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index 8e270ff7d..be3e6d9e7 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -95,13 +95,4 @@ void agg_renderer::process(debug_symbolizer const& sym, template void agg_renderer::process(debug_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -template void agg_renderer::process(debug_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); -template void agg_renderer::process(debug_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); -template void agg_renderer::process(debug_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); } diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index 4b08009ce..7fe40a818 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -102,14 +102,5 @@ void agg_renderer::process(dot_symbolizer const& sym, template void agg_renderer::process(dot_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -template void agg_renderer::process(dot_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); -template void agg_renderer::process(dot_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); -template void agg_renderer::process(dot_symbolizer const&, - mapnik::feature_impl &, - proj_transform const&); } diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index ac3fb94f8..295982ed2 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -49,99 +49,9 @@ namespace mapnik { * to render it, and the boxes themselves should already be * in the detector from the placement_finder. */ -template -struct thunk_renderer -{ - using renderer_type = agg_renderer; - using buffer_type = typename renderer_type::buffer_type; - using text_renderer_type = agg_text_renderer; - thunk_renderer(renderer_type &ren, - std::unique_ptr const& ras_ptr, - buffer_type *buf, - renderer_common &common, - pixel_position const &offset) - : ren_(ren), ras_ptr_(ras_ptr), buf_(buf), common_(common), offset_(offset) - {} - - void operator()(vector_marker_render_thunk const &thunk) const - { - using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender - using buf_type = agg::rendering_buffer; - using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - using renderer_type = agg::renderer_scanline_aa_solid; - using svg_attribute_type = agg::pod_bvector; - using svg_renderer_type = svg::svg_renderer_agg; - ras_ptr_->reset(); - buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); - pixfmt_comp_type pixf(render_buffer); - pixf.comp_op(static_cast(thunk.comp_op_)); - renderer_base renb(pixf); - svg::vertex_stl_adapter stl_storage(thunk.src_->source()); - svg_path_adapter svg_path(stl_storage); - svg_renderer_type svg_renderer(svg_path, thunk.attrs_); - - agg::trans_affine offset_tr = thunk.tr_; - offset_tr.translate(offset_.x, offset_.y); - render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_); - } - - void operator()(raster_marker_render_thunk const &thunk) const - { - using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender - using buf_type = agg::rendering_buffer; - using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - - ras_ptr_->reset(); - buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); - pixfmt_comp_type pixf(render_buffer); - pixf.comp_op(static_cast(thunk.comp_op_)); - renderer_base renb(pixf); - - agg::trans_affine offset_tr = thunk.tr_; - offset_tr.translate(offset_.x, offset_.y); - render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); - } - - void operator()(text_render_thunk const &thunk) const - { - text_renderer_type ren(*buf_, thunk.halo_rasterizer_, thunk.comp_op_, thunk.comp_op_, - common_.scale_factor_, common_.font_manager_.get_stroker()); - - render_offset_placements( - thunk.placements_, - offset_, - [&] (glyph_positions_ptr glyphs) - { - if (glyphs->marker()) - { - ren_.render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), - glyphs->marker()->transform, - thunk.opacity_, thunk.comp_op_); - } - ren.render(*glyphs); - }); - } - - template - void operator()(T const &) const - { - // TODO: warning if unimplemented? - } - -private: - renderer_type &ren_; - std::unique_ptr const& ras_ptr_; - buffer_type *buf_; - renderer_common &common_; - pixel_position offset_; -}; +template +struct thunk_renderer; template <> struct thunk_renderer @@ -184,7 +94,7 @@ struct thunk_renderer render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender using buf_type = agg::rendering_buffer; @@ -199,7 +109,22 @@ struct thunk_renderer agg::trans_affine offset_tr = thunk.tr_; offset_tr.translate(offset_.x, offset_.y); - render_raster_marker(renb, *ras_ptr_, util::get(thunk.src_), offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); + render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); + } + + void operator()(raster_marker_render_thunk const &thunk) const + { + throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_data_rgba8 renderer"); + } + + void operator()(raster_marker_render_thunk const &thunk) const + { + throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_data_rgba8 renderer"); + } + + void operator()(raster_marker_render_thunk const &thunk) const + { + throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_data_rgba8 renderer"); } void operator()(text_render_thunk const &thunk) const @@ -226,7 +151,7 @@ struct thunk_renderer template void operator()(T const &) const { - // TODO: warning if unimplemented? + throw std::runtime_error("Rendering of this data type is not supported currently by the renderer"); } private: @@ -257,14 +182,5 @@ void agg_renderer::process(group_symbolizer const& sym, template void agg_renderer::process(group_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -//template void agg_renderer::process(group_symbolizer const&, -// mapnik::feature_impl &, -// proj_transform const&); -//template void agg_renderer::process(group_symbolizer const&, -// mapnik::feature_impl &, -// proj_transform const&); -//template void agg_renderer::process(group_symbolizer const&, -// mapnik::feature_impl &, -// proj_transform const&); } diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 65e0e17fc..3904f5f83 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -224,7 +224,7 @@ void agg_renderer::process(line_symbolizer const& sym, } -template void agg_renderer::process(line_symbolizer const&, +template void agg_renderer::process(line_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 8a3dc1e50..7c1dd695e 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -125,7 +125,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch; using renderer_base = agg::renderer_base; - raster_markers_rasterizer_dispatch(image_data_rgba8 & src, + raster_markers_rasterizer_dispatch(image_data_any & src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -148,7 +148,9 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_, marker_tr, opacity, this->scale_factor_, snap_to_pixels_); + // In the long term this should be a visitor pattern based on the type of render this->src_ provided that converts + // the destination pixel type required. + render_raster_marker(renb_, ras_, util::get(this->src_), marker_tr, opacity, this->scale_factor_, snap_to_pixels_); } private: diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 68a8df15c..73f9b0bd2 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -60,7 +60,7 @@ void agg_renderer::process(point_symbolizer const& sym, }); } -template void agg_renderer::process(point_symbolizer const&, +template void agg_renderer::process(point_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index d02ead68c..7cebc05fb 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -62,7 +62,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, } box2d clip_box = clipping_extent(common_); - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); render_polygon_symbolizer( sym, feature, prj_trans, common_, clip_box, *ras_ptr, @@ -88,7 +88,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, }); } -template void agg_renderer::process(polygon_symbolizer const&, +template void agg_renderer::process(polygon_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 3bfb6c20a..c3927ae93 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -54,13 +54,13 @@ void agg_renderer::process(raster_symbolizer const& sym, sym, feature, prj_trans, common_, [&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { - composite(current_buffer_->data(), target, + composite(*current_buffer_, target, comp_op, opacity, start_x, start_y); } ); } -template void agg_renderer::process(raster_symbolizer const&, +template void agg_renderer::process(raster_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index cd039d9b7..ee9c14657 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -73,7 +73,7 @@ void agg_renderer::process(shield_symbolizer const& sym, } -template void agg_renderer::process(shield_symbolizer const&, +template void agg_renderer::process(shield_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 1a73838a5..0edb97986 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -76,12 +76,8 @@ void agg_renderer::process(text_symbolizer const& sym, } } -template void agg_renderer::process(text_symbolizer const&, +template void agg_renderer::process(text_symbolizer const&, mapnik::feature_impl &, proj_transform const&); -//template void agg_renderer::process(text_symbolizer const&, -// mapnik::feature_impl &, -// proj_transform const&); - } diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index 37ba4c789..599baf5ec 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -77,7 +77,7 @@ struct thunk_renderer thunk.opacity_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); @@ -111,7 +111,7 @@ struct thunk_renderer template void operator()(T0 const &) const { - // TODO: warning if unimplemented? + throw std::runtime_error("Rendering of this type is not supported by the cairo renderer."); } private: diff --git a/src/cairo/process_markers_symbolizer.cpp b/src/cairo/process_markers_symbolizer.cpp index fe80a0106..8bbf57d70 100644 --- a/src/cairo/process_markers_symbolizer.cpp +++ b/src/cairo/process_markers_symbolizer.cpp @@ -86,7 +86,7 @@ private: template struct raster_markers_dispatch_cairo : public raster_markers_dispatch { - raster_markers_dispatch_cairo(mapnik::image_data_any & src, + raster_markers_dispatch_cairo(image_data_any & src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 0cb62b704..a06cd4f29 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -56,6 +56,6 @@ template class feature_style_processor template class feature_style_processor >; #endif -template class feature_style_processor >; +template class feature_style_processor >; } diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index c1bbe15eb..9398dc404 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -103,7 +103,7 @@ struct thunk_renderer pixmap_.add_feature(feature_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { using buf_type = grid_rendering_buffer; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; @@ -115,9 +115,24 @@ struct thunk_renderer renderer_type ren(renb); agg::trans_affine offset_tr = thunk.tr_; offset_tr.translate(offset_.x, offset_.y); - render_raster_marker(ren, ras_, util::get(thunk.src_), feature_, offset_tr, thunk.opacity_); + render_raster_marker(ren, ras_, thunk.src_, feature_, offset_tr, thunk.opacity_); pixmap_.add_feature(feature_); } + + void operator()(raster_marker_render_thunk const &thunk) const + { + throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_data_rgba8 renderer"); + } + + void operator()(raster_marker_render_thunk const &thunk) const + { + throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_data_rgba8 renderer"); + } + + void operator()(raster_marker_render_thunk const &thunk) const + { + throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_data_rgba8 renderer"); + } void operator()(text_render_thunk const &thunk) const { diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 2d7fa49f9..493d8164f 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -146,7 +146,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch::type; using PixMapType = typename std::tuple_element<2,RendererContext>::type; - raster_markers_rasterizer_dispatch(image_data_rgba8 & src, + raster_markers_rasterizer_dispatch(image_data_any & src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, @@ -165,7 +165,9 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_, this->feature_, marker_tr, opacity); + // In the long term this should be a visitor pattern based on the type of render this->src_ provided that converts + // the destination pixel type required. + render_raster_marker(RendererType(renb_), ras_, util::get(this->src_), this->feature_, marker_tr, opacity); if (!placed_) { pixmap_.add_feature(this->feature_); diff --git a/src/image_convert.cpp b/src/image_convert.cpp new file mode 100644 index 000000000..0d74f298d --- /dev/null +++ b/src/image_convert.cpp @@ -0,0 +1,62 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + +namespace mapnik +{ + +namespace detail +{ + +template +struct visitor_convert +{ + using dst_type = typename T0::pixel_type; + template + T0 operator() (T1 const& src) + { + T0 dst(src.width(), src.height()); + for (unsigned y = 0; y < dst.height(); ++y) + { + for (unsigned x = 0; x < dst.width(); ++x) + { + dst(x,y) = static_cast(src(x,y)); + } + } + return T0(std::move(dst)); + } +}; + +} // end detail ns + +template +MAPNIK_DECL T2 convert_image(T1 const& data) +{ + detail::visitor_convert visit; + return visit(data); +} + +} // end mapnik ns diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index 30de4e1a3..1456f116c 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -39,7 +39,38 @@ vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) {} -raster_marker_render_thunk::raster_marker_render_thunk(image_data_any & src, +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_data_rgba8 & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_data_gray8 & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_data_gray16 & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_data_gray32f & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -94,6 +125,40 @@ private: render_thunk_list & thunks_; }; +struct visitor_push_thunk +{ + visitor_push_thunk(render_thunk_list & thunks, + agg::trans_affine const& marker_tr, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : thunks_(thunks), + marker_tr_(marker_tr), + opacity_(opacity), + comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) {} + + template + void operator() (T & data) + { + raster_marker_render_thunk thunk(data, marker_tr_, opacity_, comp_op_, snap_to_pixels_); + thunks_.push_back(std::make_unique(std::move(thunk))); + } + + private: + render_thunk_list & thunks_; + agg::trans_affine const& marker_tr_; + double opacity_; + composite_mode_e comp_op_; + bool snap_to_pixels_; +}; + +template <> +void visitor_push_thunk::operator() (image_data_null &) +{ + throw std::runtime_error("Push thunk does not support null images"); +} + template struct raster_marker_thunk_dispatch : public raster_markers_dispatch { @@ -115,8 +180,7 @@ struct raster_marker_thunk_dispatch : public raster_markers_dispatch void render_marker(agg::trans_affine const& marker_tr, double opacity) { - raster_marker_render_thunk thunk(this->src_, marker_tr, opacity, comp_op_, snap_to_pixels_); - thunks_.push_back(std::make_unique(std::move(thunk))); + util::apply_visitor(visitor_push_thunk(thunks_, marker_tr, opacity, comp_op_, snap_to_pixels_), this->src_); } private: @@ -125,7 +189,7 @@ private: render_thunk_list & thunks_; }; -} +} // end detail ns render_thunk_extractor::render_thunk_extractor(box2d & box, render_thunk_list & thunks, diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index 21c34b8d9..6d8ce6781 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -359,8 +359,7 @@ grid_text_renderer::grid_text_renderer(pixmap_type &pixmap, : text_renderer(HALO_RASTERIZER_FAST, comp_op, src_over, scale_factor), pixmap_(pixmap) {} -template class agg_text_renderer; -//template class agg_text_renderer; +template class agg_text_renderer; template class grid_text_renderer; } // namespace mapnik diff --git a/tests/cpp_tests/exceptions_test.cpp b/tests/cpp_tests/exceptions_test.cpp index 1bfc826e0..3019ab86a 100644 --- a/tests/cpp_tests/exceptions_test.cpp +++ b/tests/cpp_tests/exceptions_test.cpp @@ -83,8 +83,8 @@ int main(int argc, char** argv) mapnik::Map m = map; m.add_layer(l); m.zoom_all(); - mapnik::image_32 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im); + mapnik::image_data_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); //std::clog << mapnik::save_map_to_string(m) << "\n"; BOOST_TEST(true); // should throw here with "CSV Plugin: no attribute 'foo'. Valid attributes are: x,y." diff --git a/tests/cpp_tests/fontset_runtime_test.cpp b/tests/cpp_tests/fontset_runtime_test.cpp index 1b7cc59f9..80d7ff907 100644 --- a/tests/cpp_tests/fontset_runtime_test.cpp +++ b/tests/cpp_tests/fontset_runtime_test.cpp @@ -82,8 +82,8 @@ int main(int argc, char** argv) m.insert_style("style", std::move(the_style) ); m.zoom_to_box(mapnik::box2d(-256,-256, 256,256)); - mapnik::image_32 buf(m.width(),m.height()); - mapnik::agg_renderer ren(m,buf); + mapnik::image_data_rgba8 buf(m.width(),m.height()); + mapnik::agg_renderer ren(m,buf); ren.apply(); } catch (std::exception const& ex) { BOOST_TEST_EQ(std::string(ex.what()),std::string("Unable to find specified font face 'DejaVu Sans Book' in font set: 'fontset'")); diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index f7cb158f6..b02633272 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -44,16 +44,6 @@ int main(int argc, char** argv) } #endif - try - { - mapnik::image_32 im(-10,-10); // should throw rather than overflow - BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail - } - catch (std::exception const& ex) - { - BOOST_TEST( true ); // should hit bad alloc here - } - try { mapnik::image_data_rgba8 im(-10,-10); // should throw rather than overflow diff --git a/tests/cpp_tests/image_painted_test.cpp b/tests/cpp_tests/image_painted_test.cpp index 946c21124..3e89b819e 100644 --- a/tests/cpp_tests/image_painted_test.cpp +++ b/tests/cpp_tests/image_painted_test.cpp @@ -60,8 +60,8 @@ int main(int argc, char** argv) m.zoom_all(); - image_32 image(m.width(), m.height()); - agg_renderer ren(m, image); + image_data_rgba8 image(m.width(), m.height()); + agg_renderer ren(m, image); ren.apply(); BOOST_TEST_EQ(image.painted(), true); diff --git a/tests/cpp_tests/map_request_test.cpp b/tests/cpp_tests/map_request_test.cpp index 52159d0d4..227c8ae79 100644 --- a/tests/cpp_tests/map_request_test.cpp +++ b/tests/cpp_tests/map_request_test.cpp @@ -30,19 +30,19 @@ bool compare_images(std::string const& src_fn,std::string const& dest_fn) { throw mapnik::image_reader_exception("Failed to load: " + dest_fn); } - std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); - reader1->read(0,0,image_ptr1->data()); + std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); + reader1->read(0,0,*image_ptr1); std::unique_ptr reader2(mapnik::get_image_reader(src_fn,"png")); if (!reader2.get()) { throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); - reader2->read(0,0,image_ptr2->data()); + std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); + reader2->read(0,0,*image_ptr2); - image_data_rgba8 const& dest = image_ptr1->data(); - image_data_rgba8 const& src = image_ptr2->data(); + image_data_rgba8 const& dest = *image_ptr1; + image_data_rgba8 const& src = *image_ptr2; unsigned int width = src.width(); unsigned int height = src.height(); @@ -78,21 +78,21 @@ int main(int argc, char** argv) mapnik::Map m(256,256); mapnik::load_map(m,"./tests/data/good_maps/marker-text-line.xml",false); m.zoom_all(); - mapnik::image_32 im(m.width(),m.height()); + mapnik::image_data_rgba8 im(m.width(),m.height()); double scale_factor = 1.2; // render normally with apply() and just map and image - mapnik::agg_renderer renderer1(m,im,scale_factor); + mapnik::agg_renderer renderer1(m,im,scale_factor); renderer1.apply(); std::string actual1("/tmp/map-request-marker-text-line-actual1.png"); - //mapnik::save_to_file(im.data(),expected); - mapnik::save_to_file(im.data(),actual1); + //mapnik::save_to_file(im,expected); + mapnik::save_to_file(im,actual1); // TODO - re-enable if we can control the freetype/cairo versions used // https://github.com/mapnik/mapnik/issues/1868 //BOOST_TEST(compare_images(actual1,expected)); // reset image - mapnik::fill(im.data(), 0); + mapnik::fill(im, 0); // set up a mapnik::request object mapnik::request req(m.width(),m.height(),m.get_current_extent()); @@ -100,19 +100,19 @@ int main(int argc, char** argv) // render using apply() and mapnik::request mapnik::attributes vars; - mapnik::agg_renderer renderer2(m,req,vars,im,scale_factor); + mapnik::agg_renderer renderer2(m,req,vars,im,scale_factor); renderer2.apply(); std::string actual2("/tmp/map-request-marker-text-line-actual2.png"); - mapnik::save_to_file(im.data(),actual2); + mapnik::save_to_file(im,actual2); // TODO - re-enable if we can control the freetype/cairo versions used // https://github.com/mapnik/mapnik/issues/1868 //BOOST_TEST(compare_images(actual2,expected)); // reset image - mapnik::fill(im.data(), 0); + mapnik::fill(im, 0); // render with apply_to_layer api and mapnik::request params passed to apply_to_layer - mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); + mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); renderer3.start_map_processing(m); mapnik::projection map_proj(m.srs(),true); double scale_denom = mapnik::scale_denominator(req.scale(),map_proj.is_geographic()); @@ -137,7 +137,7 @@ int main(int argc, char** argv) } renderer3.end_map_processing(m); std::string actual3("/tmp/map-request-marker-text-line-actual3.png"); - mapnik::save_to_file(im.data(),actual3); + mapnik::save_to_file(im,actual3); // TODO - re-enable if we can control the freetype/cairo versions used // https://github.com/mapnik/mapnik/issues/1868 //BOOST_TEST(compare_images(actual3,expected)); diff --git a/utils/nik2img/nik2img.cpp b/utils/nik2img/nik2img.cpp index fe410be7f..ccdb78208 100644 --- a/utils/nik2img/nik2img.cpp +++ b/utils/nik2img/nik2img.cpp @@ -111,7 +111,7 @@ int main (int argc,char** argv) mapnik::Map map(600,400); mapnik::load_map(map,xml_file,true); map.zoom_all(); - mapnik::image_32 im(map.width(),map.height()); + mapnik::image_data_rgba8 im(map.width(),map.height()); mapnik::request req(map.width(),map.height(),map.get_current_extent()); req.set_buffer_size(map.buffer_size()); mapnik::attributes vars; @@ -138,9 +138,9 @@ int main (int argc,char** argv) } } } - mapnik::agg_renderer ren(map,req,vars,im,scale_factor,0,0); + mapnik::agg_renderer ren(map,req,vars,im,scale_factor,0,0); ren.apply(); - mapnik::save_to_file(im.data(),img_file); + mapnik::save_to_file(im,img_file); if (auto_open) { std::ostringstream s; diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 7b73c49ed..3473c52e9 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -158,8 +158,8 @@ int main (int argc,char** argv) std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; } // 10 pixel buffer to avoid edge clipping of 100% svg's - mapnik::image_32 im(w+0,h+0); - agg::rendering_buffer buf(im.raw_data(), im.width(), im.height(), im.width() * 4); + mapnik::image_data_rgba8 im(w+0,h+0); + agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.width() * 4); pixfmt pixf(buf); renderer_base renb(pixf); @@ -181,8 +181,8 @@ int main (int argc,char** argv) svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox); boost::algorithm::ireplace_last(svg_name,".svg",".png"); - demultiply_alpha(im.data()); - mapnik::save_to_file(im.data(),svg_name,"png"); + demultiply_alpha(im); + mapnik::save_to_file(im,svg_name,"png"); if (auto_open) { std::ostringstream s; From 4856886284d25e200478807f0f0c6b175f8ce857 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 20 Jan 2015 19:37:31 -0800 Subject: [PATCH 46/91] fix compile of rundemo.cpp --- demo/c++/rundemo.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index 66999fba1..dc3592b73 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -311,21 +311,21 @@ int main ( int, char** ) ren.apply(); std::string msg("These maps have been rendered using AGG in the current directory:\n"); #ifdef HAVE_JPEG - save_to_file(buf.data(),"demo.jpg","jpeg"); + save_to_file(buf,"demo.jpg","jpeg"); msg += "- demo.jpg\n"; #endif #ifdef HAVE_PNG - save_to_file(buf.data(),"demo.png","png"); - save_to_file(buf.data(),"demo256.png","png8"); + save_to_file(buf,"demo.png","png"); + save_to_file(buf,"demo256.png","png8"); msg += "- demo.png\n"; msg += "- demo256.png\n"; #endif #ifdef HAVE_TIFF - save_to_file(buf.data(),"demo.tif","tiff"); + save_to_file(buf,"demo.tif","tiff"); msg += "- demo.tif\n"; #endif #ifdef HAVE_WEBP - save_to_file(buf.data(),"demo.webp","webp"); + save_to_file(buf,"demo.webp","webp"); msg += "- demo.webp\n"; #endif msg += "Have a look!\n"; From df9613369eb26fc3e013de99f53854d4a5f60c3d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 20 Jan 2015 20:38:22 -0800 Subject: [PATCH 47/91] temp fix: copy rather than move image_data inside marker to avoid mutating marker --- src/agg/process_line_pattern_symbolizer.cpp | 14 ++++++++++---- src/agg/process_polygon_pattern_symbolizer.cpp | 15 ++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index ab3c552b9..cdace38c6 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -78,10 +78,16 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, value_double opacity = get(sym, feature, common_.vars_); if ((*marker_ptr)->is_bitmap()) { - pat = boost::optional>( - std::make_shared( - std::move(util::get(**(*marker_ptr)->get_bitmap_data()) - ))); + // FIXME: copy is necessary atm to transform a + // shared_ptr into shared_ptr + boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); + if (bitmap) { + mapnik::image_data_any const& im = *(bitmap)->get(); + if (im.is()) { + // invoke copy ctor of image_data_rgba8 + pat = std::make_shared(util::get(im)); + } + } } else { diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index cb33a04ee..52632c17c 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -68,11 +68,16 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, if ((*marker_ptr)->is_bitmap()) { - pat = boost::optional>( - std::make_shared( - std::move(util::get(**(*marker_ptr)->get_bitmap_data()) - ))); - //pat = (*marker_ptr)->get_bitmap_data(); + // FIXME: copy is necessary atm to transform a + // shared_ptr into shared_ptr + boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); + if (bitmap) { + mapnik::image_data_any const& im = *(bitmap)->get(); + if (im.is()) { + // invoke copy ctor of image_data_rgba8 + pat = std::make_shared(util::get(im)); + } + } } else { From b57b1c12d61ecb939242640600a7202c7e5711d6 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 21 Jan 2015 17:09:53 -0600 Subject: [PATCH 48/91] Some smaller fixes that cause the proper operator to be called in visitor_create_marker. All tests now passing. Ref #2633 --- include/mapnik/image_data.hpp | 2 ++ src/image_compositing.cpp | 1 + src/marker_cache.cpp | 12 ++++++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image_data.hpp index 24d2eec11..30a9da9cd 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image_data.hpp @@ -161,6 +161,8 @@ public: { std::swap(dimensions_, rhs.dimensions_); std::swap(buffer_, rhs.buffer_); + std::swap(premultiplied_alpha_, rhs.premultiplied_alpha_); + std::swap(painted_, rhs.painted_); } inline pixel_type& operator() (std::size_t i, std::size_t j) diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 181702c12..f15a29cfd 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -169,6 +169,7 @@ MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, #ifdef MAPNIK_DEBUG if (!src.get_premultiplied()) { + abort(); throw std::runtime_error("SOURCE MUST BE PREMULTIPLIED FOR COMPOSITING!"); } if (!dst.get_premultiplied()) diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 2ebc027ef..ec09affc8 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -62,7 +62,10 @@ marker_cache::marker_cache() "" "" ""); - marker_ptr mark = std::make_shared(); + image_data_rgba8 im(4,4,true,true); + im.set(0xff000000); + boost::optional bitmap_data = boost::optional(std::make_shared(std::move(im))); + marker_ptr mark = std::make_shared(bitmap_data); marker_cache_.emplace("image://square",mark); } @@ -126,7 +129,7 @@ struct visitor_create_marker template marker_ptr operator() (T & data) { - std::shared_ptr image = std::make_shared(std::move(data)); + std::shared_ptr image = std::make_shared(data); return std::make_shared(image); } }; @@ -134,7 +137,7 @@ struct visitor_create_marker template<> marker_ptr visitor_create_marker::operator() (image_data_rgba8 & data) { - std::shared_ptr image = std::make_shared(std::move(data)); + std::shared_ptr image = std::make_shared(data); mapnik::premultiply_alpha(*image); return std::make_shared(image); } @@ -237,7 +240,8 @@ boost::optional marker_cache::find(std::string const& uri, unsigned width = reader->width(); unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); - marker_ptr mark(util::apply_visitor(detail::visitor_create_marker(), reader->read(0,0,width,height))); + image_data_any im = reader->read(0,0,width,height); + marker_ptr mark(util::apply_visitor(detail::visitor_create_marker(), im)); result.reset(mark); if (update_cache) { From 93f835177bc8907e74cfc17030c1fb772f776264 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 21 Jan 2015 17:57:16 -0600 Subject: [PATCH 49/91] Removed all the code for the previous type of image and image_32. Ref #2633 --- benchmark/test_font_registration.cpp | 2 +- benchmark/test_png_encoding1.cpp | 1 - benchmark/test_polygon_clipping.cpp | 1 - benchmark/test_polygon_clipping_rendering.cpp | 1 - benchmark/test_rendering.cpp | 1 - benchmark/test_rendering_shared_map.cpp | 1 - bindings/python/mapnik_image.cpp | 28 +---- bindings/python/mapnik_python.cpp | 1 - bindings/python/mapnik_symbolizer.cpp | 1 - demo/c++/rundemo.cpp | 1 - demo/viewer/mapwidget.cpp | 1 - include/mapnik/graphics.hpp | 106 ------------------ include/mapnik/image.hpp | 49 -------- src/agg/agg_renderer.cpp | 1 - src/agg/process_building_symbolizer.cpp | 1 - src/agg/process_debug_symbolizer.cpp | 1 - src/agg/process_dot_symbolizer.cpp | 1 - src/agg/process_line_pattern_symbolizer.cpp | 1 - src/agg/process_line_symbolizer.cpp | 1 - src/agg/process_markers_symbolizer.cpp | 1 - .../process_polygon_pattern_symbolizer.cpp | 1 - src/agg/process_polygon_symbolizer.cpp | 1 - src/agg/process_raster_symbolizer.cpp | 1 - src/agg/process_shield_symbolizer.cpp | 1 - src/agg/process_text_symbolizer.cpp | 1 - src/build.py | 2 - src/feature_style_processor.cpp | 1 - src/graphics.cpp | 56 --------- src/image.cpp | 61 ---------- src/text/renderer.cpp | 1 - tests/cpp_tests/exceptions_test.cpp | 1 - tests/cpp_tests/fontset_runtime_test.cpp | 1 - tests/cpp_tests/image_io_test.cpp | 1 - tests/cpp_tests/image_painted_test.cpp | 1 - tests/cpp_tests/map_request_test.cpp | 1 - tests/cxx/test_main.cpp | 2 +- utils/nik2img/nik2img.cpp | 1 - utils/svg2png/svg2png.cpp | 1 - 38 files changed, 3 insertions(+), 333 deletions(-) delete mode 100644 include/mapnik/graphics.hpp delete mode 100644 include/mapnik/image.hpp delete mode 100644 src/graphics.cpp delete mode 100644 src/image.cpp diff --git a/benchmark/test_font_registration.cpp b/benchmark/test_font_registration.cpp index 749f12232..0fd9f8d29 100644 --- a/benchmark/test_font_registration.cpp +++ b/benchmark/test_font_registration.cpp @@ -24,4 +24,4 @@ public: } }; -BENCHMARK(test,"font registration") \ No newline at end of file +BENCHMARK(test,"font registration") diff --git a/benchmark/test_png_encoding1.cpp b/benchmark/test_png_encoding1.cpp index 9c1005ef7..f6fc5a229 100644 --- a/benchmark/test_png_encoding1.cpp +++ b/benchmark/test_png_encoding1.cpp @@ -1,6 +1,5 @@ #include "bench_framework.hpp" #include -#include class test : public benchmark::test_case { diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index ad3dd3a75..dbc8701ce 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/benchmark/test_polygon_clipping_rendering.cpp b/benchmark/test_polygon_clipping_rendering.cpp index 0de0bb631..396cca1d8 100644 --- a/benchmark/test_polygon_clipping_rendering.cpp +++ b/benchmark/test_polygon_clipping_rendering.cpp @@ -1,7 +1,6 @@ #include "bench_framework.hpp" #include #include -#include #include #include diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp index c82b1a30d..b98705638 100644 --- a/benchmark/test_rendering.cpp +++ b/benchmark/test_rendering.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/benchmark/test_rendering_shared_map.cpp b/benchmark/test_rendering_shared_map.cpp index 0c94b910c..df95db853 100644 --- a/benchmark/test_rendering_shared_map.cpp +++ b/benchmark/test_rendering_shared_map.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index d0e2abdf0..a85d0c149 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -35,14 +35,12 @@ #pragma GCC diagnostic pop // mapnik -#include #include #include -#include -#include #include #include #include +#include // cairo #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) @@ -52,7 +50,6 @@ #include #endif -using mapnik::image; using mapnik::image_data_any; using mapnik::image_reader; using mapnik::get_image_reader; @@ -250,21 +247,6 @@ std::shared_ptr from_cairo(PycairoSurface* py_surface) } #endif -// ============ image any -std::shared_ptr read_from_file_impl(std::string const& filename) -{ - std::shared_ptr img = std::make_shared(); - std::unique_ptr reader(get_image_reader(filename)); - if (reader) - { - unsigned w = reader->width(); - unsigned h = reader->height(); - img->set_data(reader->read(0, 0, w, h)); - } - return img; -} -// ========================= - void export_image() { using namespace boost::python; @@ -308,14 +290,6 @@ void export_image() .value("divide", mapnik::divide) ; - class_, boost::noncopyable > ("ImageAny", "This class represents an any Image object", no_init) - .def("width",&image::width) - .def("height",&image::height) - .def("open", &read_from_file_impl) - .staticmethod("open") - .def("save",&image::save_to_file) - ; - class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) .def("width",&image_data_any::width) .def("height",&image_data_any::height) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 89e92519d..b285185bf 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -99,7 +99,6 @@ void export_logger(); #include #include #include -#include #include #include #include diff --git a/bindings/python/mapnik_symbolizer.cpp b/bindings/python/mapnik_symbolizer.cpp index ef23bdb98..2f4929229 100644 --- a/bindings/python/mapnik_symbolizer.cpp +++ b/bindings/python/mapnik_symbolizer.cpp @@ -43,7 +43,6 @@ #include #include "mapnik_enumeration.hpp" #include "mapnik_svg.hpp" -#include #include #include #include // for known_svg_prefix_ diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index dc3592b73..f30bee2b9 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 1c68eccde..8c389811e 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp deleted file mode 100644 index 9030cc5d5..000000000 --- a/include/mapnik/graphics.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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_GRAPHICS_HPP -#define MAPNIK_GRAPHICS_HPP - -// mapnik -#include -#include -#include -#include -#include -#include - -// stl -#include -#include -#include - -// boost -#include - -namespace mapnik -{ - -class MAPNIK_DECL image_32 -{ -private: - image_data_rgba8 data_; - bool painted_; -public: - using pixel_type = typename image_data_rgba8::pixel_type; - image_32(int width,int height); - image_32(image_32 const& rhs); - image_32(image_data_rgba8 && data); - ~image_32(); - - void painted(bool painted) - { - data_.painted(painted); - } - - bool painted() const - { - return data_.painted(); - } - - inline const image_data_rgba8& data() const - { - return data_; - } - - inline image_data_rgba8& data() - { - return data_; - } - - inline const unsigned char* raw_data() const - { - return data_.getBytes(); - } - - inline unsigned char* raw_data() - { - return data_.getBytes(); - } - - inline image_view_rgba8 get_view(unsigned x,unsigned y, unsigned w,unsigned h) - { - return image_view_rgba8(x,y,w,h,data_); - } - -public: - inline unsigned width() const - { - return data_.width(); - } - - inline unsigned height() const - { - return data_.height(); - } - -}; -} - -#endif // MAPNIK_GRAPHICS_HPP diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp deleted file mode 100644 index d9ee28334..000000000 --- a/include/mapnik/image.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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_HPP -#define MAPNIK_IMAGE_HPP - -#include -#include - -namespace mapnik { - -class MAPNIK_DECL image -{ -public: - image() = default; - inline std::size_t width() const { return data_.width(); } - inline std::size_t height() const { return data_.height(); } - void set_data(image_data_any && data); - inline image_data_any const& data() const { return data_;} - static image read_from_file(std::string const& filename); - void save_to_file(std::string const& filename, std::string const& format); -private: - image(image && other) = default; - image(image_data_any && data) noexcept; - image_data_any data_; -}; - -} - -#endif // MAPNIK_IMAGE_HPP diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index d2683e115..5cfc4e2d4 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index d16816f61..ad2677113 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -22,7 +22,6 @@ // mapnik #include -#include #include #include #include diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index be3e6d9e7..76f425792 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index 7fe40a818..5de5e1501 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index cdace38c6..957fbe33a 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 3904f5f83..744dafd6b 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -22,7 +22,6 @@ // mapnik #include -#include #include #include #include diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 7c1dd695e..6814c380d 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -21,7 +21,6 @@ *****************************************************************************/ // mapnik -#include #include #include #include diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 52632c17c..79f5f5b68 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index 7cebc05fb..d49b82be9 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -26,7 +26,6 @@ // mapnik #include #include -#include #include #include #include diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index c3927ae93..907ff67f8 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index ee9c14657..6c01aaaa9 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 0edb97986..217cc1870 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include diff --git a/src/build.py b/src/build.py index 0103aa8a8..953ce6c2c 100644 --- a/src/build.py +++ b/src/build.py @@ -152,7 +152,6 @@ source = Split( miniz_png.cpp color.cpp conversions.cpp - image.cpp image_convert.cpp image_compositing.cpp image_scaling.cpp @@ -172,7 +171,6 @@ source = Split( font_set.cpp function_call.cpp gradient.cpp - graphics.cpp parse_path.cpp image_reader.cpp cairo_io.cpp diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index a06cd4f29..8f6babee0 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #if defined(GRID_RENDERER) diff --git a/src/graphics.cpp b/src/graphics.cpp deleted file mode 100644 index 48664835b..000000000 --- a/src/graphics.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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 -#include -#include - -// agg -#include "agg_rendering_buffer.h" -#include "agg_pixfmt_rgba.h" -#include "agg_color_rgba.h" - -#ifdef HAVE_CAIRO -#include -#endif - -namespace mapnik -{ -image_32::image_32(int width,int height) - : data_(width,height), - painted_(false) {} - - -image_32::image_32(image_32 const& rhs) - : data_(rhs.data_), - painted_(rhs.painted_) {} - -image_32::image_32(image_data_rgba8 && data) - : data_(std::move(data)), - painted_(false) {} - -image_32::~image_32() {} - -} diff --git a/src/image.cpp b/src/image.cpp deleted file mode 100644 index 6e71b80c9..000000000 --- a/src/image.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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 - * - *****************************************************************************/ - -#include -#include -#include -#include - -#include - -namespace mapnik { - -image::image(image_data_any && data) noexcept - : data_(std::move(data)) {} - -void image::set_data(image_data_any && data) -{ - data_ = std::move(data); -} - -image image::read_from_file(std::string const& filename) -{ - std::unique_ptr reader(get_image_reader(filename)); - if (reader) - { - unsigned w = reader->width(); - unsigned h = reader->height(); - image_data_any data = reader->read(0, 0, w, h); - return image(std::move(data)); - } - else - { - return image(); - } -} - -void image::save_to_file(std::string const& filename, std::string const& format) -{ - mapnik::save_to_file(data_, filename, format); -} - -} diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index 6d8ce6781..bf400cd7f 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -22,7 +22,6 @@ // mapnik #include -#include #include #include #include diff --git a/tests/cpp_tests/exceptions_test.cpp b/tests/cpp_tests/exceptions_test.cpp index 3019ab86a..38e742344 100644 --- a/tests/cpp_tests/exceptions_test.cpp +++ b/tests/cpp_tests/exceptions_test.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/cpp_tests/fontset_runtime_test.cpp b/tests/cpp_tests/fontset_runtime_test.cpp index 80d7ff907..9c6c883d9 100644 --- a/tests/cpp_tests/fontset_runtime_test.cpp +++ b/tests/cpp_tests/fontset_runtime_test.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index b02633272..f275b0665 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff --git a/tests/cpp_tests/image_painted_test.cpp b/tests/cpp_tests/image_painted_test.cpp index 3e89b819e..b3cbc8238 100644 --- a/tests/cpp_tests/image_painted_test.cpp +++ b/tests/cpp_tests/image_painted_test.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/cpp_tests/map_request_test.cpp b/tests/cpp_tests/map_request_test.cpp index 227c8ae79..b9f5210bc 100644 --- a/tests/cpp_tests/map_request_test.cpp +++ b/tests/cpp_tests/map_request_test.cpp @@ -7,7 +7,6 @@ #if defined(HAVE_CAIRO) #include #endif -#include #include #include #include diff --git a/tests/cxx/test_main.cpp b/tests/cxx/test_main.cpp index 063e87874..0c7c351f4 100644 --- a/tests/cxx/test_main.cpp +++ b/tests/cxx/test_main.cpp @@ -1,2 +1,2 @@ #define CATCH_CONFIG_MAIN -#include "catch.hpp" \ No newline at end of file +#include "catch.hpp" diff --git a/utils/nik2img/nik2img.cpp b/utils/nik2img/nik2img.cpp index ccdb78208..8a9976248 100644 --- a/utils/nik2img/nik2img.cpp +++ b/utils/nik2img/nik2img.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 3473c52e9..4913c1a7e 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include From 82bc43c76f706c2e96a27be04b64758f3aa282f7 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 21 Jan 2015 16:32:31 -0800 Subject: [PATCH 50/91] fix stray include of graphics.hpp --- include/mapnik/renderer_common/process_group_symbolizer.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 23657e1a4..64a1ad49d 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -42,7 +42,6 @@ #include #include #include -#include // agg #include From 0f388ed68f97ca7295296941b8c18b4d0e96c354 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 21 Jan 2015 19:40:12 -0600 Subject: [PATCH 51/91] Changed the name of image_data_any to image_any. Moved header file for image_data_any to image_any. Ref #2633 --- bindings/python/mapnik_image.cpp | 66 +++++------ bindings/python/mapnik_python.cpp | 22 ++-- include/mapnik/agg_renderer.hpp | 2 +- include/mapnik/cairo/cairo_context.hpp | 6 +- .../{image_data_any.hpp => image_any.hpp} | 24 ++-- include/mapnik/image_reader.hpp | 4 +- include/mapnik/image_util.hpp | 16 +-- include/mapnik/marker.hpp | 4 +- include/mapnik/marker_helpers.hpp | 4 +- include/mapnik/raster.hpp | 4 +- include/mapnik/tiff_io.hpp | 2 +- plugins/input/raster/raster_featureset.cpp | 2 +- src/agg/agg_renderer.cpp | 2 +- src/agg/process_building_symbolizer.cpp | 2 +- src/agg/process_debug_symbolizer.cpp | 2 +- src/agg/process_line_pattern_symbolizer.cpp | 6 +- src/agg/process_line_symbolizer.cpp | 2 +- src/agg/process_markers_symbolizer.cpp | 2 +- src/agg/process_point_symbolizer.cpp | 2 +- .../process_polygon_pattern_symbolizer.cpp | 4 +- src/agg/process_text_symbolizer.cpp | 2 +- src/cairo/cairo_context.cpp | 4 +- src/cairo/process_markers_symbolizer.cpp | 2 +- src/feature_style_processor.cpp | 2 +- src/grid/process_markers_symbolizer.cpp | 2 +- src/image_compositing.cpp | 8 +- src/image_convert.cpp | 2 +- src/image_util.cpp | 112 +++++++++--------- src/image_util_jpeg.cpp | 2 +- src/image_util_png.cpp | 2 +- src/image_util_webp.cpp | 2 +- src/jpeg_reader.cpp | 6 +- src/marker_cache.cpp | 8 +- src/png_reader.cpp | 6 +- .../process_group_symbolizer.cpp | 2 +- src/text/renderer.cpp | 2 +- src/tiff_reader.cpp | 26 ++-- src/webp_reader.cpp | 6 +- tests/cpp_tests/utils.hpp | 2 +- tests/cxx/tiff_io.cpp | 26 ++-- 40 files changed, 201 insertions(+), 201 deletions(-) rename include/mapnik/{image_data_any.hpp => image_any.hpp} (88%) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index a85d0c149..1fac2e371 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -50,7 +50,7 @@ #include #endif -using mapnik::image_data_any; +using mapnik::image_any; using mapnik::image_reader; using mapnik::get_image_reader; using mapnik::type_from_filename; @@ -59,7 +59,7 @@ using mapnik::save_to_file; using namespace boost::python; // output 'raw' pixels -PyObject* tostring1( image_data_any const& im) +PyObject* tostring1( image_any const& im) { return #if PY_VERSION_HEX >= 0x03000000 @@ -71,7 +71,7 @@ PyObject* tostring1( image_data_any const& im) } // encode (png,jpeg) -PyObject* tostring2(image_data_any const & im, std::string const& format) +PyObject* tostring2(image_any const & im, std::string const& format) { std::string s = mapnik::save_to_string(im, format); return @@ -83,7 +83,7 @@ PyObject* tostring2(image_data_any const & im, std::string const& format) (s.data(),s.size()); } -PyObject* tostring3(image_data_any const & im, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* tostring3(image_any const & im, std::string const& format, mapnik::rgba_palette const& pal) { std::string s = mapnik::save_to_string(im, format, pal); return @@ -96,58 +96,58 @@ PyObject* tostring3(image_data_any const & im, std::string const& format, mapnik } -void save_to_file1(mapnik::image_data_any const& im, std::string const& filename) +void save_to_file1(mapnik::image_any const& im, std::string const& filename) { save_to_file(im,filename); } -void save_to_file2(mapnik::image_data_any const& im, std::string const& filename, std::string const& type) +void save_to_file2(mapnik::image_any const& im, std::string const& filename, std::string const& type) { save_to_file(im,filename,type); } -void save_to_file3(mapnik::image_data_any const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) +void save_to_file3(mapnik::image_any const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) { save_to_file(im,filename,type,pal); } -mapnik::image_view_any get_view(mapnik::image_data_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) +mapnik::image_view_any get_view(mapnik::image_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) { return mapnik::create_view(data,x,y,w,h); } -bool painted(mapnik::image_data_any const& im) +bool painted(mapnik::image_any const& im) { return im.painted(); } -bool is_solid(mapnik::image_data_any const& im) +bool is_solid(mapnik::image_any const& im) { return mapnik::is_solid(im); } -void background(mapnik::image_data_any & im, mapnik::color const& c) +void background(mapnik::image_any & im, mapnik::color const& c) { mapnik::fill(im, c); } -uint32_t get_pixel(mapnik::image_data_any const& im, int x, int y) +uint32_t get_pixel(mapnik::image_any const& im, int x, int y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) { - return mapnik::get_pixel(im, x, y); + return mapnik::get_pixel(im, x, y); } PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); boost::python::throw_error_already_set(); return 0; } -void set_pixel(mapnik::image_data_any & im, unsigned x, unsigned y, mapnik::color const& c) +void set_pixel(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c) { mapnik::set_pixel(im, x, y, c); } -std::shared_ptr open_from_file(std::string const& filename) +std::shared_ptr open_from_file(std::string const& filename) { boost::optional type = type_from_filename(filename); if (type) @@ -155,24 +155,24 @@ std::shared_ptr open_from_file(std::string const& filename) std::unique_ptr reader(get_image_reader(filename,*type)); if (reader.get()) { - return std::make_shared(std::move(reader->read(0,0,reader->width(),reader->height()))); + return std::make_shared(std::move(reader->read(0,0,reader->width(),reader->height()))); } throw mapnik::image_reader_exception("Failed to load: " + filename); } throw mapnik::image_reader_exception("Unsupported image format:" + filename); } -std::shared_ptr fromstring(std::string const& str) +std::shared_ptr fromstring(std::string const& str) { std::unique_ptr reader(get_image_reader(str.c_str(),str.size())); if (reader.get()) { - return std::make_shared(std::move(reader->read(0,0,reader->width(), reader->height()))); + return std::make_shared(std::move(reader->read(0,0,reader->width(), reader->height()))); } throw mapnik::image_reader_exception("Failed to load image from buffer" ); } -std::shared_ptr frombuffer(PyObject * obj) +std::shared_ptr frombuffer(PyObject * obj) { void const* buffer=0; Py_ssize_t buffer_len; @@ -181,48 +181,48 @@ std::shared_ptr frombuffer(PyObject * obj) std::unique_ptr reader(get_image_reader(reinterpret_cast(buffer),buffer_len)); if (reader.get()) { - return std::make_shared(reader->read(0,0,reader->width(),reader->height())); + return std::make_shared(reader->read(0,0,reader->width(),reader->height())); } } throw mapnik::image_reader_exception("Failed to load image from buffer" ); } -void set_grayscale_to_alpha(image_data_any & im) +void set_grayscale_to_alpha(image_any & im) { mapnik::set_grayscale_to_alpha(im); } -void set_color_to_alpha(image_data_any & im, mapnik::color const& c) +void set_color_to_alpha(image_any & im, mapnik::color const& c) { mapnik::set_color_to_alpha(im, c); } -void set_alpha(image_data_any & im, float opacity) +void set_alpha(image_any & im, float opacity) { mapnik::set_alpha(im, opacity); } -bool premultiplied(image_data_any &im) +bool premultiplied(image_any &im) { return im.get_premultiplied(); } -bool premultiply(image_data_any & im) +bool premultiply(image_any & im) { return mapnik::premultiply_alpha(im); } -bool demultiply(image_data_any & im) +bool demultiply(image_any & im) { return mapnik::demultiply_alpha(im); } -void clear(image_data_any & im) +void clear(image_any & im) { mapnik::fill(im, 0); } -void composite(image_data_any & dst, image_data_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) +void composite(image_any & dst, image_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) { bool demultiply_dst = mapnik::premultiply_alpha(dst); bool demultiply_src = mapnik::premultiply_alpha(src); @@ -238,12 +238,12 @@ void composite(image_data_any & dst, image_data_any & src, mapnik::composite_mod } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) -std::shared_ptr from_cairo(PycairoSurface* py_surface) +std::shared_ptr from_cairo(PycairoSurface* py_surface) { mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); mapnik::image_data_rgba8 image = mapnik::image_data_rgba8(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); cairo_image_to_rgba8(image, surface); - return std::make_shared(std::move(image)); + return std::make_shared(std::move(image)); } #endif @@ -290,9 +290,9 @@ void export_image() .value("divide", mapnik::divide) ; - class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) - .def("width",&image_data_any::width) - .def("height",&image_data_any::height) + class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) + .def("width",&image_any::width) + .def("height",&image_any::height) .def("view",&get_view) .def("painted",&painted) .def("is_solid",&is_solid) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index b285185bf..cae43a62f 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -101,7 +101,7 @@ void export_logger(); #include #include #include -#include +#include #include #include #include @@ -301,7 +301,7 @@ void agg_renderer_visitor_4::operator() (mapnik::image void render(mapnik::Map const& map, - mapnik::image_data_any& image, + mapnik::image_any& image, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) @@ -311,7 +311,7 @@ void render(mapnik::Map const& map, } void render_with_vars(mapnik::Map const& map, - mapnik::image_data_any& image, + mapnik::image_any& image, boost::python::dict const& d, double scale_factor = 1.0, unsigned offset_x = 0u, @@ -326,7 +326,7 @@ void render_with_vars(mapnik::Map const& map, void render_with_detector( mapnik::Map const& map, - mapnik::image_data_any &image, + mapnik::image_any &image, std::shared_ptr detector, double scale_factor = 1.0, unsigned offset_x = 0u, @@ -337,7 +337,7 @@ void render_with_detector( } void render_layer2(mapnik::Map const& map, - mapnik::image_data_any& image, + mapnik::image_any& image, unsigned layer_idx, double scale_factor, unsigned offset_x, @@ -458,7 +458,7 @@ void render_tile_to_file(mapnik::Map const& map, std::string const& file, std::string const& format) { - mapnik::image_data_any image(width,height); + mapnik::image_any image(width,height); render(map,image,1.0,offset_x, offset_y); mapnik::save_to_file(image,file,format); } @@ -493,7 +493,7 @@ void render_to_file1(mapnik::Map const& map, } else { - mapnik::image_data_any image(map.width(),map.height()); + mapnik::image_any image(map.width(),map.height()); render(map,image,1.0,0,0); mapnik::save_to_file(image,filename,format); } @@ -512,7 +512,7 @@ void render_to_file2(mapnik::Map const& map,std::string const& filename) } else { - mapnik::image_data_any image(map.width(),map.height()); + mapnik::image_any image(map.width(),map.height()); render(map,image,1.0,0,0); mapnik::save_to_file(image,filename); } @@ -550,7 +550,7 @@ void render_to_file3(mapnik::Map const& map, } else { - mapnik::image_data_any image(map.width(),map.height()); + mapnik::image_any image(map.width(),map.height()); render(map,image,scale_factor,0,0); mapnik::save_to_file(image,filename,format); } @@ -832,7 +832,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("render", &render, render_overloads( "\n" - "Render Map to an AGG image_data_any using offsets\n" + "Render Map to an AGG image_any using offsets\n" "\n" "Usage:\n" ">>> from mapnik import Map, Image, render, load_map\n" @@ -849,7 +849,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("render_with_detector", &render_with_detector, render_with_detector_overloads( "\n" - "Render Map to an AGG image_data_any using a pre-constructed detector.\n" + "Render Map to an AGG image_any using a pre-constructed detector.\n" "\n" "Usage:\n" ">>> from mapnik import Map, Image, LabelCollisionDetector, render_with_detector, load_map\n" diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index e5aa1b117..74778b1d9 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -37,7 +37,7 @@ #include #include #include -#include +#include // stl #include diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index 3b5d40b17..80f094e4b 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -308,8 +308,8 @@ public: void paint(); void set_pattern(cairo_pattern const& pattern); void set_gradient(cairo_gradient const& pattern, box2d const& bbox); - void add_image(double x, double y, image_data_any & data, double opacity); - void add_image(agg::trans_affine const& tr, image_data_any & data, double opacity); + void add_image(double x, double y, image_any & data, double opacity); + void add_image(agg::trans_affine const& tr, image_any & data, double opacity); void add_image(double x, double y, image_data_rgba8 & data, double opacity = 1.0); void add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity = 1.0); void set_font_face(cairo_face_manager & manager, face_ptr face); diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_any.hpp similarity index 88% rename from include/mapnik/image_data_any.hpp rename to include/mapnik/image_any.hpp index 159b2c4e5..ed4443f8b 100644 --- a/include/mapnik/image_data_any.hpp +++ b/include/mapnik/image_any.hpp @@ -58,8 +58,8 @@ using image_data_base = util::variant; // Forward declaring -struct image_data_any; -image_data_any create_image_any(int width, +struct image_any; +image_any create_image_any(int width, int height, image_dtype type = image_dtype_rgba8, bool initialize = true, @@ -141,11 +141,11 @@ struct get_any_row_size_visitor }; } // namespace detail -struct image_data_any : image_data_base +struct image_any : image_data_base { - image_data_any() = default; + image_any() = default; - image_data_any(int width, + image_any(int width, int height, image_dtype type = image_dtype_rgba8, bool initialize = true, @@ -154,7 +154,7 @@ struct image_data_any : image_data_base : image_data_base(std::move(create_image_any(width, height, type, initialize, premultiplied, painted))) {} template - image_data_any(T && data) noexcept + image_any(T && data) noexcept : image_data_base(std::move(data)) {} unsigned char const* getBytes() const @@ -198,7 +198,7 @@ struct image_data_any : image_data_base } }; -inline image_data_any create_image_any(int width, +inline image_any create_image_any(int width, int height, image_dtype type, bool initialize, @@ -208,16 +208,16 @@ inline image_data_any create_image_any(int width, switch (type) { case image_dtype_gray8: - return image_data_any(std::move(image_data_gray8(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_data_gray8(width, height, initialize, premultiplied, painted))); case image_dtype_gray16: - return image_data_any(std::move(image_data_gray16(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_data_gray16(width, height, initialize, premultiplied, painted))); case image_dtype_gray32f: - return image_data_any(std::move(image_data_gray32f(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_data_gray32f(width, height, initialize, premultiplied, painted))); case image_dtype_null: - return image_data_any(std::move(image_data_null())); + return image_any(std::move(image_data_null())); case image_dtype_rgba8: default: - return image_data_any(std::move(image_data_rgba8(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_data_rgba8(width, height, initialize, premultiplied, painted))); } } diff --git a/include/mapnik/image_reader.hpp b/include/mapnik/image_reader.hpp index 178bfb628..2e6a6b9c0 100644 --- a/include/mapnik/image_reader.hpp +++ b/include/mapnik/image_reader.hpp @@ -24,7 +24,7 @@ #define MAPNIK_IMAGE_READER_HPP // mapnik -#include +#include #include #include #include @@ -61,7 +61,7 @@ struct MAPNIK_DECL image_reader : private util::noncopyable virtual bool has_alpha() const = 0; virtual boost::optional > bounding_box() const = 0; virtual void read(unsigned x,unsigned y,image_data_rgba8& image) = 0; - virtual image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0; + virtual image_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0; virtual ~image_reader() {} }; diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 9d249f4e4..d7efa51fe 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -26,7 +26,7 @@ // mapnik #include #include -#include +#include #include #include #include @@ -154,7 +154,7 @@ MAPNIK_DECL T2 get_pixel(T1 const& data, std::size_t x, std::size_t y); MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss); -MAPNIK_DECL image_view_any create_view (image_data_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); +MAPNIK_DECL image_view_any create_view (image_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); inline bool is_png(std::string const& filename) { @@ -238,7 +238,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file(image_data_any const&, +extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, std::string const&, rgba_palette const&); @@ -247,7 +247,7 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 std::string const&, std::string const&); -extern template MAPNIK_DECL void save_to_file(image_data_any const&, +extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, std::string const&); @@ -255,14 +255,14 @@ extern template MAPNIK_DECL void save_to_file(image_data_rgba8 std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file(image_data_any const&, +extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, rgba_palette const&); extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, std::string const&); -extern template MAPNIK_DECL void save_to_file(image_data_any const&, +extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&); extern template MAPNIK_DECL void save_to_file(image_view_any const&, @@ -295,10 +295,10 @@ extern template MAPNIK_DECL std::string save_to_string (image_ std::string const&, rgba_palette const&); -extern template MAPNIK_DECL std::string save_to_string(image_data_any const&, +extern template MAPNIK_DECL std::string save_to_string(image_any const&, std::string const&); -extern template MAPNIK_DECL std::string save_to_string(image_data_any const&, +extern template MAPNIK_DECL std::string save_to_string(image_any const&, std::string const&, rgba_palette const&); diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index d2d26e167..2edd1473a 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -46,7 +46,7 @@ namespace mapnik using attr_storage = agg::pod_bvector; using svg_storage_type = mapnik::svg::svg_storage; using svg_path_ptr = std::shared_ptr; -using image_ptr = std::shared_ptr; +using image_ptr = std::shared_ptr; /** * A class to hold either vector or bitmap marker data. This allows these to be treated equally * in the image caches and most of the render paths. @@ -59,7 +59,7 @@ public: // create default OGC 4x4 black pixel image_data_rgba8 image(4,4,true,true); image.set(0xff000000); - bitmap_data_ = boost::optional(std::make_shared(std::move(image))); + bitmap_data_ = boost::optional(std::make_shared(std::move(image))); } marker(boost::optional const& data) diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 3e9e42e0d..293bef31e 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -118,7 +118,7 @@ protected: template struct raster_markers_dispatch : util::noncopyable { - raster_markers_dispatch(image_data_any & src, + raster_markers_dispatch(image_any & src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -163,7 +163,7 @@ struct raster_markers_dispatch : util::noncopyable virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0; protected: - image_data_any & src_; + image_any & src_; agg::trans_affine const& marker_trans_; symbolizer_base const& sym_; Detector & detector_; diff --git a/include/mapnik/raster.hpp b/include/mapnik/raster.hpp index 6b5fbb663..a4b26cb63 100644 --- a/include/mapnik/raster.hpp +++ b/include/mapnik/raster.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include #include #include // boost @@ -37,7 +37,7 @@ class raster : private util::noncopyable { public: box2d ext_; - image_data_any data_; + image_any data_; double filter_factor_; boost::optional nodata_; diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 8ce71e433..38bdb8818 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include extern "C" diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index d0e8b6b2b..7c9c8353d 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -114,7 +114,7 @@ feature_ptr raster_featureset::next() rem.maxx() + x_off + width, rem.maxy() + y_off + height); intersect = t.backward(feature_raster_extent); - mapnik::image_data_any data = reader->read(x_off, y_off, width, height); + mapnik::image_any data = reader->read(x_off, y_off, width, height); mapnik::raster_ptr raster = std::make_shared(intersect, std::move(data), 1.0); feature->set_raster(raster); } diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 5cfc4e2d4..2837a58b6 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include // agg #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index ad2677113..0f969ca97 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include #include #include diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index 76f425792..6ad2bb80c 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 957fbe33a..21fc7231f 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include @@ -78,10 +78,10 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, if ((*marker_ptr)->is_bitmap()) { // FIXME: copy is necessary atm to transform a - // shared_ptr into shared_ptr + // shared_ptr into shared_ptr boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); if (bitmap) { - mapnik::image_data_any const& im = *(bitmap)->get(); + mapnik::image_any const& im = *(bitmap)->get(); if (im.is()) { // invoke copy ctor of image_data_rgba8 pat = std::make_shared(util::get(im)); diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 744dafd6b..6ef5bf0f8 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include #include #include diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 6814c380d..51d2ccfd5 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -124,7 +124,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch; using renderer_base = agg::renderer_base; - raster_markers_rasterizer_dispatch(image_data_any & src, + raster_markers_rasterizer_dispatch(image_any & src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 73f9b0bd2..91102763d 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 79f5f5b68..b2f22ee2f 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -68,10 +68,10 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, if ((*marker_ptr)->is_bitmap()) { // FIXME: copy is necessary atm to transform a - // shared_ptr into shared_ptr + // shared_ptr into shared_ptr boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); if (bitmap) { - mapnik::image_data_any const& im = *(bitmap)->get(); + mapnik::image_any const& im = *(bitmap)->get(); if (im.is()) { // invoke copy ctor of image_data_rgba8 pat = std::make_shared(util::get(im)); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 217cc1870..3dcf12381 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include diff --git a/src/cairo/cairo_context.cpp b/src/cairo/cairo_context.cpp index 3458cfa75..abf5b658a 100644 --- a/src/cairo/cairo_context.cpp +++ b/src/cairo/cairo_context.cpp @@ -388,12 +388,12 @@ void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d struct raster_markers_dispatch_cairo : public raster_markers_dispatch { - raster_markers_dispatch_cairo(image_data_any & src, + raster_markers_dispatch_cairo(image_any & src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 8f6babee0..1b9aef039 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #if defined(GRID_RENDERER) #include diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 493d8164f..a57cb943f 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -146,7 +146,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch::type; using PixMapType = typename std::tuple_element<2,RendererContext>::type; - raster_markers_rasterizer_dispatch(image_data_any & src, + raster_markers_rasterizer_dispatch(image_any & src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index f15a29cfd..89d2f9d05 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include // boost #pragma GCC diagnostic push @@ -204,7 +204,7 @@ namespace detail { struct composite_visitor { - composite_visitor(image_data_any const& src, + composite_visitor(image_any const& src, composite_mode_e mode, float opacity, int dx, @@ -219,7 +219,7 @@ struct composite_visitor void operator() (T & dst); private: - image_data_any const& src_; + image_any const& src_; composite_mode_e mode_; float opacity_; int dx_; @@ -247,7 +247,7 @@ void composite_visitor::operator() (image_data_gray32f & dst } // end ns template <> -MAPNIK_DECL void composite(image_data_any & dst, image_data_any const& src, composite_mode_e mode, +MAPNIK_DECL void composite(image_any & dst, image_any const& src, composite_mode_e mode, float opacity, int dx, int dy) diff --git a/src/image_convert.cpp b/src/image_convert.cpp index 0d74f298d..3a99383c9 100644 --- a/src/image_convert.cpp +++ b/src/image_convert.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include namespace mapnik { diff --git a/src/image_util.cpp b/src/image_util.cpp index e5b403ca5..647a07ba7 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -123,7 +123,7 @@ MAPNIK_DECL void save_to_stream(T const& image, else throw ImageWriterException("Could not write to empty stream" ); } -// This can be removed once image_data_any and image_view_any are the only +// This can be removed once image_any and image_view_any are the only // items using this template template <> MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, @@ -154,7 +154,7 @@ MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, else throw ImageWriterException("Could not write to empty stream" ); } -// This can be removed once image_data_any and image_view_any are the only +// This can be removed once image_any and image_view_any are the only // items using this template template <> MAPNIK_DECL void save_to_stream(image_view_rgba8 const& image, @@ -219,7 +219,7 @@ MAPNIK_DECL void save_to_stream(T const& image, else throw ImageWriterException("Could not write to empty stream" ); } -// This can be removed once image_data_any and image_view_any are the only +// This can be removed once image_any and image_view_any are the only // items using this template template <> MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, @@ -259,7 +259,7 @@ MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, else throw ImageWriterException("Could not write to empty stream" ); } -// This can be removed once image_data_any and image_view_any are the only +// This can be removed once image_any and image_view_any are the only // items using this template template <> MAPNIK_DECL void save_to_stream(image_view_rgba8 const& image, @@ -369,27 +369,27 @@ template MAPNIK_DECL std::string save_to_string (image_view_any std::string const&, rgba_palette const& palette); -// image_data_any -template MAPNIK_DECL void save_to_file(image_data_any const&, +// image_any +template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, std::string const&); -template MAPNIK_DECL void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, std::string const&, rgba_palette const& palette); -template MAPNIK_DECL void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_any const&, std::string const&); -template MAPNIK_DECL void save_to_file(image_data_any const&, +template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, rgba_palette const& palette); -template MAPNIK_DECL std::string save_to_string(image_data_any const&, +template MAPNIK_DECL std::string save_to_string(image_any const&, std::string const&); -template MAPNIK_DECL std::string save_to_string(image_data_any const&, +template MAPNIK_DECL std::string save_to_string(image_any const&, std::string const&, rgba_palette const& palette); @@ -444,7 +444,7 @@ MAPNIK_DECL bool is_solid(T const& image) return util::apply_visitor(detail::is_solid_visitor(), image); } -template MAPNIK_DECL bool is_solid (image_data_any const&); +template MAPNIK_DECL bool is_solid (image_any const&); template MAPNIK_DECL bool is_solid (image_view_any const&); // Temporary until image_data_rgba8 is removed from passing @@ -535,9 +535,9 @@ MAPNIK_DECL bool premultiply_alpha(T & image) return util::apply_visitor(detail::premultiply_visitor(), image); } -template MAPNIK_DECL bool premultiply_alpha (image_data_any &); +template MAPNIK_DECL bool premultiply_alpha (image_any &); -// Temporary, can be removed once image_view_any and image_data_any are the only ones passed +// Temporary, can be removed once image_view_any and image_any are the only ones passed template <> MAPNIK_DECL bool premultiply_alpha(image_data_rgba8 & image) { @@ -551,9 +551,9 @@ MAPNIK_DECL bool demultiply_alpha(T & image) return util::apply_visitor(detail::demultiply_visitor(), image); } -template MAPNIK_DECL bool demultiply_alpha (image_data_any &); +template MAPNIK_DECL bool demultiply_alpha (image_any &); -// Temporary, can be removed once image_view_any and image_data_any are the only ones passed +// Temporary, can be removed once image_view_any and image_any are the only ones passed template <> MAPNIK_DECL bool demultiply_alpha(image_data_rgba8 & image) { @@ -567,9 +567,9 @@ MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status) util::apply_visitor(detail::set_premultiplied_visitor(status), image); } -template void set_premultiplied_alpha (image_data_any &, bool); +template void set_premultiplied_alpha (image_any &, bool); -// Temporary, can be removed once image_view_any and image_data_any are the only ones passed +// Temporary, can be removed once image_view_any and image_any are the only ones passed template <> MAPNIK_DECL void set_premultiplied_alpha(image_data_rgba8 & image, bool status) { @@ -622,7 +622,7 @@ void visitor_set_alpha::operator() (image_data_rgba8 & data) } // end detail ns template<> -MAPNIK_DECL void set_alpha (image_data_any & data, float opacity) +MAPNIK_DECL void set_alpha (image_any & data, float opacity) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -633,7 +633,7 @@ MAPNIK_DECL void set_alpha (image_data_any & data, float opacity } } -// TEMPORARY can be removed once image_data_any is only way it is being passed. +// TEMPORARY can be removed once image_any is only way it is being passed. template<> MAPNIK_DECL void set_alpha (image_data_rgba8 & data, float opacity) { @@ -683,7 +683,7 @@ void visitor_set_grayscale_to_alpha::operator() (image_data_rg } // end detail ns template<> -MAPNIK_DECL void set_grayscale_to_alpha (image_data_any & data) +MAPNIK_DECL void set_grayscale_to_alpha (image_any & data) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -694,7 +694,7 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_data_any & data) } } -// TEMPORARY can be removed once image_data_any is only way it is being passed. +// TEMPORARY can be removed once image_any is only way it is being passed. template<> MAPNIK_DECL void set_grayscale_to_alpha (image_data_rgba8 & data) { @@ -750,7 +750,7 @@ void visitor_set_color_to_alpha::operator() (image_data_rgba8 } // end detail ns template<> -MAPNIK_DECL void set_color_to_alpha (image_data_any & data, color const& c) +MAPNIK_DECL void set_color_to_alpha (image_any & data, color const& c) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -761,7 +761,7 @@ MAPNIK_DECL void set_color_to_alpha (image_data_any & data, colo } } -// TEMPORARY can be removed once image_data_any is only way it is being passed. +// TEMPORARY can be removed once image_any is only way it is being passed. template<> MAPNIK_DECL void set_color_to_alpha (image_data_rgba8 & data, color const& c) { @@ -822,15 +822,15 @@ MAPNIK_DECL void fill (T1 & data, T2 const& val) util::apply_visitor(detail::visitor_fill(val), data); } -template MAPNIK_DECL void fill(image_data_any &, color const&); -template MAPNIK_DECL void fill(image_data_any &, uint32_t const&); -template MAPNIK_DECL void fill(image_data_any &, int32_t const&); -template MAPNIK_DECL void fill(image_data_any &, uint16_t const&); -template MAPNIK_DECL void fill(image_data_any &, int16_t const&); -template MAPNIK_DECL void fill(image_data_any &, uint8_t const&); -template MAPNIK_DECL void fill(image_data_any &, int8_t const&); -template MAPNIK_DECL void fill(image_data_any &, float const&); -template MAPNIK_DECL void fill(image_data_any &, double const&); +template MAPNIK_DECL void fill(image_any &, color const&); +template MAPNIK_DECL void fill(image_any &, uint32_t const&); +template MAPNIK_DECL void fill(image_any &, int32_t const&); +template MAPNIK_DECL void fill(image_any &, uint16_t const&); +template MAPNIK_DECL void fill(image_any &, int16_t const&); +template MAPNIK_DECL void fill(image_any &, uint8_t const&); +template MAPNIK_DECL void fill(image_any &, int8_t const&); +template MAPNIK_DECL void fill(image_any &, float const&); +template MAPNIK_DECL void fill(image_any &, double const&); // Temporary remove these later! @@ -861,7 +861,7 @@ namespace detail { struct visitor_set_rectangle { - visitor_set_rectangle(image_data_any const & src, int x0, int y0) + visitor_set_rectangle(image_any const & src, int x0, int y0) : src_(src), x0_(x0), y0_(y0) {} template @@ -888,7 +888,7 @@ struct visitor_set_rectangle } } private: - image_data_any const& src_; + image_any const& src_; int x0_; int y0_; }; @@ -936,7 +936,7 @@ MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x, int y) } template <> -MAPNIK_DECL void set_rectangle (image_data_any & dst, image_data_any const& src, int x, int y) +MAPNIK_DECL void set_rectangle (image_any & dst, image_any const& src, int x, int y) { util::apply_visitor(detail::visitor_set_rectangle(src, x, y), dst); } @@ -1065,15 +1065,15 @@ MAPNIK_DECL void set_pixel (T1 & data, std::size_t x, std::size_t y, T2 const& v util::apply_visitor(detail::visitor_set_pixel(x, y, val), data); } -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, color const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, uint32_t const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, int32_t const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, uint16_t const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, int16_t const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, uint8_t const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, int8_t const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, float const&); -template MAPNIK_DECL void set_pixel(image_data_any &, std::size_t, std::size_t, double const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, double const&); // Temporary remove these later! @@ -1163,15 +1163,15 @@ MAPNIK_DECL T2 get_pixel (T1 const& data, std::size_t x, std::size_t y) return util::apply_visitor(detail::visitor_get_pixel(x, y), data); } -template MAPNIK_DECL color get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL uint32_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL int32_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL uint16_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL int16_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL uint8_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL int8_t get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL float get_pixel(image_data_any const&, std::size_t, std::size_t); -template MAPNIK_DECL double get_pixel(image_data_any const&, std::size_t, std::size_t); +template MAPNIK_DECL color get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_any const&, std::size_t, std::size_t); // Temporary remove these later! @@ -1257,7 +1257,7 @@ image_view_any visitor_create_view::operator() (image_data_null } // end detail ns -MAPNIK_DECL image_view_any create_view(image_data_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) +MAPNIK_DECL image_view_any create_view(image_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) { return util::apply_visitor(detail::visitor_create_view(x,y,w,h), data); } diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index d096a44fc..efe4611d0 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index b4b102798..b34075882 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -35,7 +35,7 @@ extern "C" #include #include #include -#include +#include #include #include diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index 62c9ca2ed..8cea5f718 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/jpeg_reader.cpp b/src/jpeg_reader.cpp index d6935572c..0bc66e480 100644 --- a/src/jpeg_reader.cpp +++ b/src/jpeg_reader.cpp @@ -86,7 +86,7 @@ public: boost::optional > bounding_box() const final; inline bool has_alpha() const final { return false; } void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); static void on_error(j_common_ptr cinfo); @@ -320,11 +320,11 @@ void jpeg_reader::read(unsigned x0, unsigned y0, image_data_rgba8& image) } template -image_data_any jpeg_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) +image_any jpeg_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { image_data_rgba8 data(width,height, true, true); read(x, y, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index ec09affc8..27e08fcf6 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -64,7 +64,7 @@ marker_cache::marker_cache() ""); image_data_rgba8 im(4,4,true,true); im.set(0xff000000); - boost::optional bitmap_data = boost::optional(std::make_shared(std::move(im))); + boost::optional bitmap_data = boost::optional(std::make_shared(std::move(im))); marker_ptr mark = std::make_shared(bitmap_data); marker_cache_.emplace("image://square",mark); } @@ -129,7 +129,7 @@ struct visitor_create_marker template marker_ptr operator() (T & data) { - std::shared_ptr image = std::make_shared(data); + std::shared_ptr image = std::make_shared(data); return std::make_shared(image); } }; @@ -137,7 +137,7 @@ struct visitor_create_marker template<> marker_ptr visitor_create_marker::operator() (image_data_rgba8 & data) { - std::shared_ptr image = std::make_shared(data); + std::shared_ptr image = std::make_shared(data); mapnik::premultiply_alpha(*image); return std::make_shared(image); } @@ -240,7 +240,7 @@ boost::optional marker_cache::find(std::string const& uri, unsigned width = reader->width(); unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); - image_data_any im = reader->read(0,0,width,height); + image_any im = reader->read(0,0,width,height); marker_ptr mark(util::apply_visitor(detail::visitor_create_marker(), im)); result.reset(mark); if (update_cache) diff --git a/src/png_reader.cpp b/src/png_reader.cpp index 21cd38fc0..9efc02bef 100644 --- a/src/png_reader.cpp +++ b/src/png_reader.cpp @@ -81,7 +81,7 @@ public: boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length); @@ -310,11 +310,11 @@ void png_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) template -image_data_any png_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) +image_any png_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { image_data_rgba8 data(width,height); read(x, y, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index 1456f116c..2da30b553 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -162,7 +162,7 @@ void visitor_push_thunk::operator() (image_data_null &) template struct raster_marker_thunk_dispatch : public raster_markers_dispatch { - raster_marker_thunk_dispatch(image_data_any & src, + raster_marker_thunk_dispatch(image_any & src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index bf400cd7f..a933e45e0 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include namespace mapnik { diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index bfcf54b3a..74f1fdd5b 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -154,7 +154,7 @@ public: boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; // methods specific to tiff reader unsigned bits_per_sample() const { return bps_; } unsigned photometric() const { return photometric_; } @@ -175,7 +175,7 @@ private: void read_tiled(unsigned x,unsigned y, ImageData & image); template - image_data_any read_any_gray(unsigned x, unsigned y, unsigned width, unsigned height); + image_any read_any_gray(unsigned x, unsigned y, unsigned width, unsigned height); TIFF* open(std::istream & input); }; @@ -395,7 +395,7 @@ void tiff_reader::read(unsigned x,unsigned y,image_data_rgba8& image) template template -image_data_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height) +image_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height) { using image_data_type = ImageData; using pixel_type = typename image_data_type::pixel_type; @@ -403,7 +403,7 @@ image_data_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned { image_data_type data(width,height); read_tiled(x0, y0, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } else { @@ -427,10 +427,10 @@ image_data_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned std::transform(scanline.get() + start_x, scanline.get() + end_x, row, [](pixel_type const& p) { return p;}); } } - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } - return image_data_any(); + return image_any(); } @@ -484,7 +484,7 @@ struct tiff_reader_traits } template -image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigned height) +image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigned height) { switch (photometric_) { @@ -537,21 +537,21 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un } } } - return image_data_any(std::move(data)); + return image_any(std::move(data)); } - return image_data_any(); + return image_any(); } case 16: { image_data_rgba8 data(width,height,true,premultiplied_alpha_); read(x0, y0, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } case 32: { image_data_rgba8 data(width,height,true,premultiplied_alpha_); read(x0, y0, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } } @@ -569,10 +569,10 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un //PHOTOMETRIC_LOGLUV = 32845; image_data_rgba8 data(width,height, true, premultiplied_alpha_); read(x0, y0, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } - return image_data_any(); + return image_any(); } template diff --git a/src/webp_reader.cpp b/src/webp_reader.cpp index ff31e8996..2df7f96ba 100644 --- a/src/webp_reader.cpp +++ b/src/webp_reader.cpp @@ -125,7 +125,7 @@ public: boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); }; @@ -268,11 +268,11 @@ void webp_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) } template -image_data_any webp_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) +image_any webp_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { image_data_rgba8 data(width,height); read(x, y, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } diff --git a/tests/cpp_tests/utils.hpp b/tests/cpp_tests/utils.hpp index e82281635..b4a541adc 100644 --- a/tests/cpp_tests/utils.hpp +++ b/tests/cpp_tests/utils.hpp @@ -23,4 +23,4 @@ inline static bool set_working_dir(std::vector args) return false; } return true; -} \ No newline at end of file +} diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index 302e7e5ce..d312331c7 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -45,7 +45,7 @@ REQUIRE( data.height() == reader->height() ); \ #define TIFF_READ_ONE_PIXEL \ - mapnik::image_data_any subimage = reader->read(1, 1, 1, 1); \ + mapnik::image_any subimage = reader->read(1, 1, 1, 1); \ REQUIRE( subimage.width() == 1 ); \ REQUIRE( subimage.height() == 1 ); \ @@ -74,7 +74,7 @@ SECTION("scan rgb8 striped") { std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); REQUIRE( reader2->width() == 512 ); REQUIRE( reader2->height() == 512 ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -104,7 +104,7 @@ SECTION("scan rgb8 tiled") { std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); REQUIRE( reader2->width() == 512 ); REQUIRE( reader2->height() == 512 ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -120,7 +120,7 @@ SECTION("rgba8 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_ADOBE_DEFLATE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_ALPHA( data ); @@ -136,7 +136,7 @@ SECTION("rgba8 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_ALPHA( data ); @@ -152,7 +152,7 @@ SECTION("rgb8 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -168,7 +168,7 @@ SECTION("rgb8 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -184,7 +184,7 @@ SECTION("gray8 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -200,7 +200,7 @@ SECTION("gray8 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -216,7 +216,7 @@ SECTION("gray16 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -232,7 +232,7 @@ SECTION("gray16 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -248,7 +248,7 @@ SECTION("gray32f striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); @@ -264,7 +264,7 @@ SECTION("gray32f tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); From 22a384ef33c82656175721da2f70b3ec3b17df93 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 21 Jan 2015 20:31:02 -0600 Subject: [PATCH 52/91] Moved image_data_rgba8 to image_rgba8. Ref #2633 --- benchmark/compare_images.hpp | 4 +- benchmark/test_png_encoding1.cpp | 2 +- benchmark/test_png_encoding2.cpp | 2 +- benchmark/test_polygon_clipping.cpp | 2 +- benchmark/test_polygon_clipping_rendering.cpp | 8 +- benchmark/test_rendering.cpp | 8 +- benchmark/test_rendering_shared_map.cpp | 12 +-- bindings/python/mapnik_image.cpp | 2 +- bindings/python/mapnik_python.cpp | 16 ++-- demo/c++/rundemo.cpp | 6 +- demo/viewer/mapwidget.cpp | 10 +-- demo/viewer/styles_model.cpp | 2 +- include/mapnik/agg_pattern_source.hpp | 4 +- include/mapnik/agg_render_marker.hpp | 2 +- include/mapnik/agg_renderer.hpp | 2 +- include/mapnik/cairo/cairo_context.hpp | 6 +- include/mapnik/cairo/cairo_image_util.hpp | 2 +- include/mapnik/grid/grid.hpp | 2 +- include/mapnik/grid/grid_marker_helpers.hpp | 4 +- include/mapnik/grid/grid_render_marker.hpp | 2 +- include/mapnik/image_any.hpp | 4 +- include/mapnik/image_data.hpp | 2 +- include/mapnik/image_reader.hpp | 2 +- include/mapnik/image_scaling_traits.hpp | 2 +- include/mapnik/image_util.hpp | 20 ++--- include/mapnik/image_view.hpp | 2 +- include/mapnik/marker.hpp | 2 +- include/mapnik/miniz_png.hpp | 4 +- include/mapnik/png_io.hpp | 8 +- include/mapnik/raster_colorizer.hpp | 2 +- .../process_group_symbolizer.hpp | 4 +- .../process_raster_symbolizer.hpp | 18 ++--- include/mapnik/tiff_io.hpp | 2 +- include/mapnik/webp_io.hpp | 8 +- plugins/input/gdal/gdal_featureset.cpp | 2 +- .../input/pgraster/pgraster_wkb_reader.cpp | 4 +- plugins/input/raster/raster_featureset.cpp | 2 +- .../rasterlite/rasterlite_featureset.cpp | 2 +- src/agg/agg_renderer.cpp | 4 +- src/agg/process_building_symbolizer.cpp | 2 +- src/agg/process_debug_symbolizer.cpp | 2 +- src/agg/process_dot_symbolizer.cpp | 2 +- src/agg/process_group_symbolizer.cpp | 14 ++-- src/agg/process_line_pattern_symbolizer.cpp | 6 +- src/agg/process_line_symbolizer.cpp | 2 +- src/agg/process_markers_symbolizer.cpp | 4 +- src/agg/process_point_symbolizer.cpp | 2 +- .../process_polygon_pattern_symbolizer.cpp | 6 +- src/agg/process_polygon_symbolizer.cpp | 2 +- src/agg/process_raster_symbolizer.cpp | 4 +- src/agg/process_shield_symbolizer.cpp | 2 +- src/agg/process_text_symbolizer.cpp | 2 +- src/cairo/cairo_context.cpp | 8 +- src/cairo/process_group_symbolizer.cpp | 2 +- src/cairo/process_line_pattern_symbolizer.cpp | 6 +- .../process_polygon_pattern_symbolizer.cpp | 4 +- src/cairo/process_raster_symbolizer.cpp | 2 +- src/feature_style_processor.cpp | 2 +- src/grid/grid_renderer.cpp | 4 +- src/grid/process_group_symbolizer.cpp | 8 +- src/grid/process_markers_symbolizer.cpp | 2 +- src/image_compositing.cpp | 8 +- src/image_scaling.cpp | 2 +- src/image_util.cpp | 80 +++++++++---------- src/image_util_jpeg.cpp | 2 +- src/image_util_png.cpp | 4 +- src/image_util_tiff.cpp | 2 +- src/image_util_webp.cpp | 4 +- src/jpeg_reader.cpp | 6 +- src/marker_cache.cpp | 4 +- src/miniz_png.cpp | 4 +- src/png_reader.cpp | 6 +- src/raster_colorizer.cpp | 8 +- .../process_group_symbolizer.cpp | 2 +- src/renderer_common/render_pattern.cpp | 4 +- src/text/renderer.cpp | 2 +- src/tiff_reader.cpp | 26 +++--- src/warp.cpp | 2 +- src/webp_reader.cpp | 6 +- tests/cpp_tests/exceptions_test.cpp | 4 +- tests/cpp_tests/fontset_runtime_test.cpp | 4 +- tests/cpp_tests/image_io_test.cpp | 4 +- tests/cpp_tests/image_painted_test.cpp | 4 +- tests/cpp_tests/map_request_test.cpp | 16 ++-- tests/cxx/tiff_io.cpp | 12 +-- utils/nik2img/nik2img.cpp | 4 +- utils/svg2png/svg2png.cpp | 4 +- 87 files changed, 252 insertions(+), 252 deletions(-) diff --git a/benchmark/compare_images.hpp b/benchmark/compare_images.hpp index b31c62a33..80dd7e929 100644 --- a/benchmark/compare_images.hpp +++ b/benchmark/compare_images.hpp @@ -24,8 +24,8 @@ namespace benchmark { throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - image_data_rgba8 const& dest = util::get(reader1->read(0,0,reader1->width(), reader1->height())); - image_data_rgba8 const& src = util::get(reader1->read(0,0,reader1->width(), reader1->height())); + image_rgba8 const& dest = util::get(reader1->read(0,0,reader1->width(), reader1->height())); + image_rgba8 const& src = util::get(reader1->read(0,0,reader1->width(), reader1->height())); unsigned int width = src.width(); unsigned int height = src.height(); diff --git a/benchmark/test_png_encoding1.cpp b/benchmark/test_png_encoding1.cpp index f6fc5a229..55d3f18af 100644 --- a/benchmark/test_png_encoding1.cpp +++ b/benchmark/test_png_encoding1.cpp @@ -3,7 +3,7 @@ class test : public benchmark::test_case { - mapnik::image_data_rgba8 im_; + mapnik::image_rgba8 im_; public: test(mapnik::parameters const& params) : test_case(params), diff --git a/benchmark/test_png_encoding2.cpp b/benchmark/test_png_encoding2.cpp index 798d0690a..640050c0d 100644 --- a/benchmark/test_png_encoding2.cpp +++ b/benchmark/test_png_encoding2.cpp @@ -3,7 +3,7 @@ class test : public benchmark::test_case { - std::shared_ptr im_; + std::shared_ptr im_; public: test(mapnik::parameters const& params) : test_case(params) { diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index dbc8701ce..8b72ea81d 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -36,7 +36,7 @@ void render(mapnik::geometry_type & geom, using path_type = mapnik::transform_path_adapter; using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; - mapnik::image_data_rgba8 im(256,256); + mapnik::image_rgba8 im(256,256); mapnik::fill(im, mapnik::color("white")); mapnik::box2d padded_extent = extent; padded_extent.pad(10); diff --git a/benchmark/test_polygon_clipping_rendering.cpp b/benchmark/test_polygon_clipping_rendering.cpp index 396cca1d8..88f20d5e0 100644 --- a/benchmark/test_polygon_clipping_rendering.cpp +++ b/benchmark/test_polygon_clipping_rendering.cpp @@ -21,8 +21,8 @@ public: mapnik::Map m(256,256); mapnik::load_map(m,xml_); m.zoom_to_box(extent_); - mapnik::image_data_rgba8 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); ren.apply(); //mapnik::save_to_file(im.data(),"test.png"); return true; @@ -34,8 +34,8 @@ public: m.zoom_to_box(extent_); for (unsigned i=0;i ren(m,im); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); ren.apply(); } return true; diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp index b98705638..fc7984b15 100644 --- a/benchmark/test_rendering.cpp +++ b/benchmark/test_rendering.cpp @@ -54,8 +54,8 @@ public: } else { m.zoom_all(); } - mapnik::image_data_rgba8 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im,scale_factor_); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im,scale_factor_); ren.apply(); if (!preview_.empty()) { std::clog << "preview available at " << preview_ << "\n"; @@ -77,8 +77,8 @@ public: } for (unsigned i=0;i ren(m,im,scale_factor_); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im,scale_factor_); ren.apply(); } return true; diff --git a/benchmark/test_rendering_shared_map.cpp b/benchmark/test_rendering_shared_map.cpp index df95db853..a83410d1b 100644 --- a/benchmark/test_rendering_shared_map.cpp +++ b/benchmark/test_rendering_shared_map.cpp @@ -49,7 +49,7 @@ class test : public benchmark::test_case std::shared_ptr m_; double scale_factor_; std::string preview_; - mutable mapnik::image_data_rgba8 im_; + mutable mapnik::image_rgba8 im_; public: test(mapnik::parameters const& params) : test_case(params), @@ -93,7 +93,7 @@ public: mapnik::projection map_proj(m_->srs(),true); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); scale_denom *= scale_factor_; - mapnik::agg_renderer ren(*m_,m_req,variables,im_,scale_factor_); + mapnik::agg_renderer ren(*m_,m_req,variables,im_,scale_factor_); ren.start_map_processing(*m_); std::vector const& layers = m_->layers(); process_layers(ren,m_req,map_proj,layers,scale_denom); @@ -113,20 +113,20 @@ public: for (unsigned i=0;iwidth(),m_->height()); + mapnik::image_rgba8 im(m_->width(),m_->height()); mapnik::attributes variables; m_req.set_buffer_size(m_->buffer_size()); mapnik::projection map_proj(m_->srs(),true); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); scale_denom *= scale_factor_; - mapnik::agg_renderer ren(*m_,m_req,variables,im,scale_factor_); + mapnik::agg_renderer ren(*m_,m_req,variables,im,scale_factor_); ren.start_map_processing(*m_); std::vector const& layers = m_->layers(); process_layers(ren,m_req,map_proj,layers,scale_denom); ren.end_map_processing(*m_); bool diff = false; - mapnik::image_data_rgba8 const& dest = im; - mapnik::image_data_rgba8 const& src = im_; + mapnik::image_rgba8 const& dest = im; + mapnik::image_rgba8 const& src = im_; for (unsigned int y = 0; y < height_; ++y) { const unsigned int* row_from = src.getRow(y); diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 1fac2e371..65456600c 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -241,7 +241,7 @@ void composite(image_any & dst, image_any & src, mapnik::composite_mode_e mode, std::shared_ptr from_cairo(PycairoSurface* py_surface) { mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); - mapnik::image_data_rgba8 image = mapnik::image_data_rgba8(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); + mapnik::image_rgba8 image = mapnik::image_rgba8(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); cairo_image_to_rgba8(image, surface); return std::make_shared(std::move(image)); } diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index cae43a62f..89c9debdb 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -208,9 +208,9 @@ struct agg_renderer_visitor_1 }; template <> -void agg_renderer_visitor_1::operator() (mapnik::image_data_rgba8 & pixmap) +void agg_renderer_visitor_1::operator() (mapnik::image_rgba8 & pixmap) { - mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); + mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); ren.apply(); } @@ -235,9 +235,9 @@ struct agg_renderer_visitor_2 }; template <> -void agg_renderer_visitor_2::operator() (mapnik::image_data_rgba8 & pixmap) +void agg_renderer_visitor_2::operator() (mapnik::image_rgba8 & pixmap) { - mapnik::agg_renderer ren(m_,pixmap,detector_, scale_factor_,offset_x_, offset_y_); + mapnik::agg_renderer ren(m_,pixmap,detector_, scale_factor_,offset_x_, offset_y_); ren.apply(); } @@ -264,9 +264,9 @@ struct agg_renderer_visitor_3 }; template <> -void agg_renderer_visitor_3::operator() (mapnik::image_data_rgba8 & pixmap) +void agg_renderer_visitor_3::operator() (mapnik::image_rgba8 & pixmap) { - mapnik::agg_renderer ren(m_,req_, vars_, pixmap, scale_factor_, offset_x_, offset_y_); + mapnik::agg_renderer ren(m_,req_, vars_, pixmap, scale_factor_, offset_x_, offset_y_); ren.apply(); } @@ -293,9 +293,9 @@ struct agg_renderer_visitor_4 }; template <> -void agg_renderer_visitor_4::operator() (mapnik::image_data_rgba8 & pixmap) +void agg_renderer_visitor_4::operator() (mapnik::image_rgba8 & pixmap) { - mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); + mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); ren.apply(layer_, names_); } diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index f30bee2b9..39614bfe9 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -305,8 +305,8 @@ int main ( int, char** ) m.zoom_to_box(box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855)); - image_data_rgba8 buf(m.width(),m.height()); - agg_renderer ren(m,buf); + image_rgba8 buf(m.width(),m.height()); + agg_renderer ren(m,buf); ren.apply(); std::string msg("These maps have been rendered using AGG in the current directory:\n"); #ifdef HAVE_JPEG @@ -353,7 +353,7 @@ int main ( int, char** ) cairo_surface_write_to_png(&*image_surface, "cairo-demo.png"); // but we can also benefit from quantization by converting // to a mapnik image object and then saving that - mapnik::image_data_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); + mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); cairo_image_to_rgba8(im_data, image_surface); save_to_file(im_data, "cairo-demo256.png","png8"); cairo_surface_finish(&*image_surface); diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 8c389811e..3f48e146a 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -41,7 +41,7 @@ #include "mapwidget.hpp" #include "info_dialog.hpp" -using mapnik::image_data_rgba8; +using mapnik::image_rgba8; using mapnik::Map; using mapnik::layer; using mapnik::box2d; @@ -478,7 +478,7 @@ void MapWidget::zoomToLevel(int level) void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&) { - //image_data_rgba8 image(width,height); + //image_rgba8 image(width,height); //agg_renderer renderer(map,image); //renderer.apply(); //image.saveToFile(filename,type); @@ -495,8 +495,8 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix) unsigned width=map.width(); unsigned height=map.height(); - image_data_rgba8 buf(width,height); - mapnik::agg_renderer ren(map,buf,scaling_factor); + image_rgba8 buf(width,height); + mapnik::agg_renderer ren(map,buf,scaling_factor); try { @@ -539,7 +539,7 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) mapnik::cairo_renderer renderer(map, cairo, scaling_factor); renderer.apply(); } - mapnik::image_data_rgba8 data(map.width(), map.height()); + mapnik::image_rgba8 data(map.width(), map.height()); mapnik::cairo_image_to_rgba8(data, image_surface); QImage image((uchar*)data.getBytes(),data.width(),data.height(),QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); diff --git a/demo/viewer/styles_model.cpp b/demo/viewer/styles_model.cpp index d8afc2631..e2f414e8a 100644 --- a/demo/viewer/styles_model.cpp +++ b/demo/viewer/styles_model.cpp @@ -201,7 +201,7 @@ struct symbolizer_icon { // FIXME! /* - std::shared_ptr symbol = sym.get_image(); + std::shared_ptr symbol = sym.get_image(); if (symbol) { QImage image(symbol->getBytes(), diff --git a/include/mapnik/agg_pattern_source.hpp b/include/mapnik/agg_pattern_source.hpp index 324dee630..534d3f671 100644 --- a/include/mapnik/agg_pattern_source.hpp +++ b/include/mapnik/agg_pattern_source.hpp @@ -36,7 +36,7 @@ namespace mapnik class pattern_source : private util::noncopyable { public: - pattern_source(image_data_rgba8 const& pattern, double opacity = 1.0) + pattern_source(image_rgba8 const& pattern, double opacity = 1.0) : pattern_(pattern), opacity_(opacity) {} @@ -57,7 +57,7 @@ public: static_cast(((c >> 24) & 0xff) * opacity_)); } private: - image_data_rgba8 const& pattern_; + image_rgba8 const& pattern_; double opacity_; }; } diff --git a/include/mapnik/agg_render_marker.hpp b/include/mapnik/agg_render_marker.hpp index dcd7dac9c..5f77303ed 100644 --- a/include/mapnik/agg_render_marker.hpp +++ b/include/mapnik/agg_render_marker.hpp @@ -66,7 +66,7 @@ void render_vector_marker(SvgRenderer & svg_renderer, RasterizerType & ras, Rend } template -void render_raster_marker(RendererType renb, RasterizerType & ras, image_data_rgba8 const& src, +void render_raster_marker(RendererType renb, RasterizerType & ras, image_rgba8 const& src, agg::trans_affine const& tr, double opacity, float scale_factor, bool snap_to_pixels) { diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 74778b1d9..392aa95b7 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -171,7 +171,7 @@ private: void setup(Map const& m); }; -extern template class MAPNIK_DECL agg_renderer; +extern template class MAPNIK_DECL agg_renderer; } // namespace mapnik diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index 80f094e4b..44d16db17 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -122,7 +122,7 @@ private: class cairo_pattern : private util::noncopyable { public: - explicit cairo_pattern(image_data_rgba8 const& data, double opacity = 1.0) + explicit cairo_pattern(image_rgba8 const& data, double opacity = 1.0) { int pixels = data.width() * data.height(); const unsigned int *in_ptr = data.getData(); @@ -310,8 +310,8 @@ public: void set_gradient(cairo_gradient const& pattern, box2d const& bbox); void add_image(double x, double y, image_any & data, double opacity); void add_image(agg::trans_affine const& tr, image_any & data, double opacity); - void add_image(double x, double y, image_data_rgba8 & data, double opacity = 1.0); - void add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity = 1.0); + void add_image(double x, double y, image_rgba8 & data, double opacity = 1.0); + void add_image(agg::trans_affine const& tr, image_rgba8 & data, double opacity = 1.0); void set_font_face(cairo_face_manager & manager, face_ptr face); void set_font_matrix(cairo_matrix_t const& matrix); void set_matrix(cairo_matrix_t const& matrix); diff --git a/include/mapnik/cairo/cairo_image_util.hpp b/include/mapnik/cairo/cairo_image_util.hpp index 5fe764bcf..2a520bfc2 100644 --- a/include/mapnik/cairo/cairo_image_util.hpp +++ b/include/mapnik/cairo/cairo_image_util.hpp @@ -33,7 +33,7 @@ namespace mapnik { -static inline void cairo_image_to_rgba8(mapnik::image_data_rgba8 & data, +static inline void cairo_image_to_rgba8(mapnik::image_rgba8 & data, cairo_surface_ptr const& surface) { if (cairo_image_surface_get_format(&*surface) != CAIRO_FORMAT_ARGB32) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index bd4cd1e5d..e1ce21899 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -195,7 +195,7 @@ public: return height_; } - inline void set_rectangle(value_type id,image_data_rgba8 const& data,int x0,int y0) + inline void set_rectangle(value_type id,image_rgba8 const& data,int x0,int y0) { box2d ext0(0,0,width_,height_); box2d ext1(x0,y0,x0+data.width(),y0+data.height()); diff --git a/include/mapnik/grid/grid_marker_helpers.hpp b/include/mapnik/grid/grid_marker_helpers.hpp index 4a27f841a..f71cdebe6 100644 --- a/include/mapnik/grid/grid_marker_helpers.hpp +++ b/include/mapnik/grid/grid_marker_helpers.hpp @@ -51,7 +51,7 @@ struct raster_markers_rasterizer_dispatch_grid : util::noncopyable using RasterizerType = typename std::tuple_element<1,RendererContext>::type; using PixMapType = typename std::tuple_element<2,RendererContext>::type; - raster_markers_rasterizer_dispatch_grid(image_data_rgba8 const& src, + raster_markers_rasterizer_dispatch_grid(image_rgba8 const& src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, @@ -130,7 +130,7 @@ private: pixfmt_type pixf_; RendererBase renb_; RasterizerType & ras_; - image_data_rgba8 const& src_; + image_rgba8 const& src_; agg::trans_affine const& marker_trans_; markers_symbolizer const& sym_; Detector & detector_; diff --git a/include/mapnik/grid/grid_render_marker.hpp b/include/mapnik/grid/grid_render_marker.hpp index 454ae038f..f8b0258b8 100644 --- a/include/mapnik/grid/grid_render_marker.hpp +++ b/include/mapnik/grid/grid_render_marker.hpp @@ -41,7 +41,7 @@ namespace mapnik { template void render_raster_marker(RendererType ren, RasterizerType & ras, - image_data_rgba8 & src, + image_rgba8 & src, mapnik::feature_impl const& feature, agg::trans_affine const& marker_tr, double opacity) diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index ed4443f8b..58fd0d0b7 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -52,7 +52,7 @@ struct image_data_null }; using image_data_base = util::variant; @@ -217,7 +217,7 @@ inline image_any create_image_any(int width, return image_any(std::move(image_data_null())); case image_dtype_rgba8: default: - return image_any(std::move(image_data_rgba8(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_rgba8(width, height, initialize, premultiplied, painted))); } } diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image_data.hpp index 30a9da9cd..153e9a3b8 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image_data.hpp @@ -277,7 +277,7 @@ private: bool painted_; }; -using image_data_rgba8 = image_data; +using image_rgba8 = image_data; using image_data_gray8 = image_data ; using image_data_gray16 = image_data; using image_data_gray32f = image_data; diff --git a/include/mapnik/image_reader.hpp b/include/mapnik/image_reader.hpp index 2e6a6b9c0..471a08b58 100644 --- a/include/mapnik/image_reader.hpp +++ b/include/mapnik/image_reader.hpp @@ -60,7 +60,7 @@ struct MAPNIK_DECL image_reader : private util::noncopyable virtual unsigned height() const = 0; virtual bool has_alpha() const = 0; virtual boost::optional > bounding_box() const = 0; - virtual void read(unsigned x,unsigned y,image_data_rgba8& image) = 0; + virtual void read(unsigned x,unsigned y,image_rgba8& image) = 0; virtual image_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0; virtual ~image_reader() {} }; diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp index fe2ce61ed..47b47e331 100644 --- a/include/mapnik/image_scaling_traits.hpp +++ b/include/mapnik/image_scaling_traits.hpp @@ -38,7 +38,7 @@ template struct agg_scaling_traits {}; template <> -struct agg_scaling_traits +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_rgba32_pre; using color_type = agg::rgba8; diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index d7efa51fe..25c36afd1 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -233,7 +233,7 @@ void add_border(T & image) } /* -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&, std::string const&, rgba_palette const&); @@ -243,7 +243,7 @@ extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&, std::string const&); @@ -251,7 +251,7 @@ extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, std::string const&); -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&, rgba_palette const&); @@ -259,7 +259,7 @@ extern template MAPNIK_DECL void save_to_file(image_any const&, std::string const&, rgba_palette const&); -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&); extern template MAPNIK_DECL void save_to_file(image_any const&, @@ -281,10 +281,10 @@ extern template MAPNIK_DECL void save_to_file(image_view_any con extern template MAPNIK_DECL void save_to_file(image_view_any const&, std::string const&); -extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, +extern template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, std::string const&); -extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, +extern template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, std::string const&, rgba_palette const&); @@ -311,15 +311,15 @@ extern template MAPNIK_DECL std::string save_to_string (image_vi */ #ifdef _MSC_VER -template MAPNIK_DECL void save_to_stream( - image_data_rgba8 const& image, +template MAPNIK_DECL void save_to_stream( + image_rgba8 const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette ); -template MAPNIK_DECL void save_to_stream( - image_data_rgba8 const& image, +template MAPNIK_DECL void save_to_stream( + image_rgba8 const& image, std::ostream & stream, std::string const& type ); diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index d5b645c8b..6c0e9ac94 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -118,7 +118,7 @@ private: T const& data_; }; -using image_view_rgba8 = image_view; +using image_view_rgba8 = image_view; using image_view_gray8 = image_view; using image_view_gray16 = image_view; using image_view_gray32f = image_view; diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index 2edd1473a..f74ac2481 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -57,7 +57,7 @@ public: marker() { // create default OGC 4x4 black pixel - image_data_rgba8 image(4,4,true,true); + image_rgba8 image(4,4,true,true); image.set(0xff000000); bitmap_data_ = boost::optional(std::make_shared(std::move(image))); } diff --git a/include/mapnik/miniz_png.hpp b/include/mapnik/miniz_png.hpp index 5c6fed248..e5e00748c 100644 --- a/include/mapnik/miniz_png.hpp +++ b/include/mapnik/miniz_png.hpp @@ -85,9 +85,9 @@ private: extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_gray8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_gray8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_rgba8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_rgba8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_data_rgba8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_rgba8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); }} diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 7034ca293..de504a3a6 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -166,7 +166,7 @@ void reduce_8(T const& in, } for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y); + mapnik::image_rgba8::pixel_type const * row = in.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y); for (unsigned x = 0; x < width; ++x) { @@ -217,7 +217,7 @@ void reduce_4(T const& in, } for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y); + mapnik::image_rgba8::pixel_type const * row = in.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y); for (unsigned x = 0; x < width; ++x) { @@ -603,7 +603,7 @@ void save_as_png8(T1 & file, image_data_gray8 reduced_image(width, height); for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y); + mapnik::image_rgba8::pixel_type const * row = image.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); for (unsigned x = 0; x < width; ++x) { @@ -629,7 +629,7 @@ void save_as_png8(T1 & file, image_data_gray8 reduced_image(image_width, image_height); for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y); + mapnik::image_rgba8::pixel_type const * row = image.getRow(y); mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); byte index = 0; for (unsigned x = 0; x < width; ++x) diff --git a/include/mapnik/raster_colorizer.hpp b/include/mapnik/raster_colorizer.hpp index fe66769b8..f565597c7 100644 --- a/include/mapnik/raster_colorizer.hpp +++ b/include/mapnik/raster_colorizer.hpp @@ -198,7 +198,7 @@ public: colorizer_stops const& get_stops() const { return stops_; } template - void colorize(image_data_rgba8 & out, T const& in, boost::optionalconst& nodata, feature_impl const& f) const; + void colorize(image_rgba8 & out, T const& in, boost::optionalconst& nodata, feature_impl const& f) const; //! \brief Perform the translation of input to output //! diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 64a1ad49d..bb9359014 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -150,7 +150,7 @@ struct raster_marker_render_thunk : util::noncopyable snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} }; -template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; template struct raster_marker_render_thunk; template struct raster_marker_render_thunk; template struct raster_marker_render_thunk; @@ -184,7 +184,7 @@ struct text_render_thunk : util::noncopyable // via a static visitor later. using render_thunk = util::variant, + raster_marker_render_thunk, raster_marker_render_thunk, raster_marker_render_thunk, raster_marker_render_thunk, diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 5e171b9b2..881393531 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -70,9 +70,9 @@ struct image_data_dispatcher nodata_(nodata) {} void operator() (image_data_null const& data_in) const {} //no-op - void operator() (image_data_rgba8 const& data_in) const + void operator() (image_rgba8 const& data_in) const { - image_data_rgba8 data_out(width_, height_, true, true); + image_rgba8 data_out(width_, height_, true, true); scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } @@ -83,7 +83,7 @@ struct image_data_dispatcher using image_data_type = T; image_data_type data_out(width_, height_); scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_); - image_data_rgba8 dst(width_, height_); + image_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); premultiply_alpha(dst); @@ -137,9 +137,9 @@ struct image_data_warp_dispatcher void operator() (image_data_null const& data_in) const {} //no-op - void operator() (image_data_rgba8 const& data_in) const + void operator() (image_rgba8 const& data_in) const { - image_data_rgba8 data_out(width_, height_, true, true); + image_rgba8 data_out(width_, height_, true, true); warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } @@ -151,7 +151,7 @@ struct image_data_warp_dispatcher image_data_type data_out(width_, height_); if (nodata_) data_out.set(*nodata_); warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); - image_data_rgba8 dst(width_, height_); + image_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); premultiply_alpha(dst); @@ -205,7 +205,7 @@ void render_raster_symbolizer(raster_symbolizer const& sym, composite_mode_e comp_op = get(sym, keys::comp_op, feature, common.vars_, src_over); double opacity = get(sym,keys::opacity,feature, common.vars_, 1.0); // only premultiply rgba8 images - if (source->data_.is()) + if (source->data_.is()) { auto is_premultiplied = get_optional(sym, keys::premultiplied, feature, common.vars_); if (is_premultiplied && *is_premultiplied) @@ -236,9 +236,9 @@ void render_raster_symbolizer(raster_symbolizer const& sym, (std::abs(start_x) <= eps) && (std::abs(start_y) <= eps) ) { - if (source->data_.is()) + if (source->data_.is()) { - composite(util::get(source->data_), comp_op, opacity, start_x, start_y); + composite(util::get(source->data_), comp_op, opacity, start_x, start_y); } } else diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 38bdb8818..17ce9da0b 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -192,7 +192,7 @@ struct tag_setter throw ImageWriterException("Could not write TIFF - unknown image type provided"); } - inline void operator() (image_data_rgba8 const& data) const + inline void operator() (image_rgba8 const& data) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); diff --git a/include/mapnik/webp_io.hpp b/include/mapnik/webp_io.hpp index eecd65e70..2ec6c52c8 100644 --- a/include/mapnik/webp_io.hpp +++ b/include/mapnik/webp_io.hpp @@ -98,11 +98,11 @@ inline int import_image_data(T2 const& image, else { // need to copy: https://github.com/mapnik/mapnik/issues/2024 - image_data_rgba8 im(image.width(),image.height()); + image_rgba8 im(image.width(),image.height()); for (unsigned y = 0; y < image.height(); ++y) { typename T2::pixel_type const * row_from = image.getRow(y); - image_data_rgba8::pixel_type * row_to = im.getRow(y); + image_rgba8::pixel_type * row_to = im.getRow(y); std::copy(row_from, row_from + stride, row_to); } if (alpha) @@ -121,11 +121,11 @@ inline int import_image_data(T2 const& image, } template <> -inline int import_image_data(image_data_rgba8 const& im, +inline int import_image_data(image_rgba8 const& im, WebPPicture & pic, bool alpha) { - int stride = sizeof(image_data_rgba8::pixel_type) * im.width(); + int stride = sizeof(image_rgba8::pixel_type) * im.width(); if (alpha) { return WebPPictureImportRGBA(&pic, im.getBytes(), stride); diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 1e276cc2a..4bcc52450 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -229,7 +229,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) } else // working with all bands { - mapnik::image_data_rgba8 image(im_width, im_height); + mapnik::image_rgba8 image(im_width, im_height); image.set(std::numeric_limits::max()); for (int i = 0; i < nbands_; ++i) { diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp index 2932a52b0..462a5881b 100644 --- a/plugins/input/pgraster/pgraster_wkb_reader.cpp +++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp @@ -271,7 +271,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d const& bbox, uint16_t width, uint16_t height, bool hasnodata, T reader) { - mapnik::image_data_rgba8 image(width,height, true, true); + mapnik::image_rgba8 image(width,height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) // TODO: set to transparent instead? image.set(0xffffffff); @@ -352,7 +352,7 @@ mapnik::raster_ptr pgraster_wkb_reader::read_grayscale(mapnik::box2d con mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d const& bbox, uint16_t width, uint16_t height) { - mapnik::image_data_rgba8 image(width, height, true, true); + mapnik::image_rgba8 image(width, height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) image.set(0xffffffff); diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 7c9c8353d..c6a1f630a 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -43,7 +43,7 @@ using mapnik::query; using mapnik::image_reader; using mapnik::feature_ptr; -using mapnik::image_data_rgba8; +using mapnik::image_rgba8; using mapnik::raster; using mapnik::feature_factory; diff --git a/plugins/input/rasterlite/rasterlite_featureset.cpp b/plugins/input/rasterlite/rasterlite_featureset.cpp index 2e3c6bb40..7171eabdf 100644 --- a/plugins/input/rasterlite/rasterlite_featureset.cpp +++ b/plugins/input/rasterlite/rasterlite_featureset.cpp @@ -114,7 +114,7 @@ feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q) { if (size > 0) { - mapnik::image_data_rgba8 image(width,height); + mapnik::image_rgba8 image(width,height); unsigned char* raster_data = static_cast(raster); unsigned char* image_data = image.getBytes(); std::memcpy(image_data, raster_data, size); diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 2837a58b6..1563c3272 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -517,8 +517,8 @@ void agg_renderer::draw_geo_extent(box2d const& extent, mapnik::c } } -template class agg_renderer; -template void agg_renderer::debug_draw_box( +template class agg_renderer; +template void agg_renderer::debug_draw_box( agg::rendering_buffer& buf, box2d const& box, double x, double y, double angle); diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 0f969ca97..5d6fba5c9 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -109,7 +109,7 @@ void agg_renderer::process(building_symbolizer const& sym, }); } -template void agg_renderer::process(building_symbolizer const&, +template void agg_renderer::process(building_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index 6ad2bb80c..fafa61133 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -91,7 +91,7 @@ void agg_renderer::process(debug_symbolizer const& sym, } } -template void agg_renderer::process(debug_symbolizer const&, +template void agg_renderer::process(debug_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index 5de5e1501..ad052a79e 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -98,7 +98,7 @@ void agg_renderer::process(dot_symbolizer const& sym, } } -template void agg_renderer::process(dot_symbolizer const&, +template void agg_renderer::process(dot_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index 295982ed2..0c5c8128c 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -54,9 +54,9 @@ template struct thunk_renderer; template <> -struct thunk_renderer +struct thunk_renderer { - using renderer_type = agg_renderer; + using renderer_type = agg_renderer; using buffer_type = renderer_type::buffer_type; using text_renderer_type = agg_text_renderer; @@ -94,7 +94,7 @@ struct thunk_renderer render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender using buf_type = agg::rendering_buffer; @@ -114,17 +114,17 @@ struct thunk_renderer void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_data_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_rgba8 renderer"); } void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_data_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_rgba8 renderer"); } void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_data_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_rgba8 renderer"); } void operator()(text_render_thunk const &thunk) const @@ -179,7 +179,7 @@ void agg_renderer::process(group_symbolizer const& sym, }); } -template void agg_renderer::process(group_symbolizer const&, +template void agg_renderer::process(group_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 21fc7231f..5e5821ab0 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -78,12 +78,12 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, if ((*marker_ptr)->is_bitmap()) { // FIXME: copy is necessary atm to transform a - // shared_ptr into shared_ptr + // shared_ptr into shared_ptr boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); if (bitmap) { mapnik::image_any const& im = *(bitmap)->get(); if (im.is()) { - // invoke copy ctor of image_data_rgba8 + // invoke copy ctor of image_rgba8 pat = std::make_shared(util::get(im)); } } @@ -153,7 +153,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, } } -template void agg_renderer::process(line_pattern_symbolizer const&, +template void agg_renderer::process(line_pattern_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 6ef5bf0f8..126c7475c 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -223,7 +223,7 @@ void agg_renderer::process(line_symbolizer const& sym, } -template void agg_renderer::process(line_symbolizer const&, +template void agg_renderer::process(line_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 51d2ccfd5..b05787691 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -149,7 +149,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_ provided that converts // the destination pixel type required. - render_raster_marker(renb_, ras_, util::get(this->src_), marker_tr, opacity, this->scale_factor_, snap_to_pixels_); + render_raster_marker(renb_, ras_, util::get(this->src_), marker_tr, opacity, this->scale_factor_, snap_to_pixels_); } private: @@ -204,7 +204,7 @@ void agg_renderer::process(markers_symbolizer const& sym, sym, feature, prj_trans, common_, clip_box, renderer_context); } -template void agg_renderer::process(markers_symbolizer const&, +template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 91102763d..cabae6dc5 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -60,7 +60,7 @@ void agg_renderer::process(point_symbolizer const& sym, }); } -template void agg_renderer::process(point_symbolizer const&, +template void agg_renderer::process(point_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index b2f22ee2f..38a0eee8c 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -68,12 +68,12 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, if ((*marker_ptr)->is_bitmap()) { // FIXME: copy is necessary atm to transform a - // shared_ptr into shared_ptr + // shared_ptr into shared_ptr boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); if (bitmap) { mapnik::image_any const& im = *(bitmap)->get(); if (im.is()) { - // invoke copy ctor of image_data_rgba8 + // invoke copy ctor of image_rgba8 pat = std::make_shared(util::get(im)); } } @@ -188,7 +188,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, } -template void agg_renderer::process(polygon_pattern_symbolizer const&, +template void agg_renderer::process(polygon_pattern_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index d49b82be9..13b9f1e9f 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -87,7 +87,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, }); } -template void agg_renderer::process(polygon_symbolizer const&, +template void agg_renderer::process(polygon_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 907ff67f8..f51c3d0d1 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -51,7 +51,7 @@ void agg_renderer::process(raster_symbolizer const& sym, { render_raster_symbolizer( sym, feature, prj_trans, common_, - [&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity, + [&](image_rgba8 & target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { composite(*current_buffer_, target, comp_op, opacity, start_x, start_y); @@ -59,7 +59,7 @@ void agg_renderer::process(raster_symbolizer const& sym, ); } -template void agg_renderer::process(raster_symbolizer const&, +template void agg_renderer::process(raster_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 6c01aaaa9..619fb163c 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -72,7 +72,7 @@ void agg_renderer::process(shield_symbolizer const& sym, } -template void agg_renderer::process(shield_symbolizer const&, +template void agg_renderer::process(shield_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 3dcf12381..c697d0521 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -75,7 +75,7 @@ void agg_renderer::process(text_symbolizer const& sym, } } -template void agg_renderer::process(text_symbolizer const&, +template void agg_renderer::process(text_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/cairo/cairo_context.cpp b/src/cairo/cairo_context.cpp index abf5b658a..ba6774cae 100644 --- a/src/cairo/cairo_context.cpp +++ b/src/cairo/cairo_context.cpp @@ -53,7 +53,7 @@ struct visitor_context_add_image_1 }; template <> -void visitor_context_add_image_1::operator() (image_data_rgba8 & data) +void visitor_context_add_image_1::operator() (image_rgba8 & data) { context_.add_image(x_, y_, data, opacity_); } @@ -76,7 +76,7 @@ struct visitor_context_add_image_2 }; template <> -void visitor_context_add_image_2::operator() (image_data_rgba8 & data) +void visitor_context_add_image_2::operator() (image_rgba8 & data) { context_.add_image(tr_, data, opacity_); } @@ -398,7 +398,7 @@ void cairo_context::add_image(agg::trans_affine const& tr, image_any & data, dou util::apply_visitor(detail::visitor_context_add_image_2(*this,tr,opacity), data); } -void cairo_context::add_image(double x, double y, image_data_rgba8 & data, double opacity) +void cairo_context::add_image(double x, double y, image_rgba8 & data, double opacity) { cairo_pattern pattern(data); pattern.set_origin(x, y); @@ -409,7 +409,7 @@ void cairo_context::add_image(double x, double y, image_data_rgba8 & data, doubl check_object_status_and_throw_exception(*this); } -void cairo_context::add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity) +void cairo_context::add_image(agg::trans_affine const& tr, image_rgba8 & data, double opacity) { cairo_pattern pattern(data); if (!tr.is_identity()) diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index 599baf5ec..f5150aa97 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -77,7 +77,7 @@ struct thunk_renderer thunk.opacity_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); diff --git a/src/cairo/process_line_pattern_symbolizer.cpp b/src/cairo/process_line_pattern_symbolizer.cpp index 9cc10f17b..096672169 100644 --- a/src/cairo/process_line_pattern_symbolizer.cpp +++ b/src/cairo/process_line_pattern_symbolizer.cpp @@ -55,7 +55,7 @@ struct visitor_create_pattern }; template <> -std::shared_ptr visitor_create_pattern::operator() (image_data_rgba8 & data) +std::shared_ptr visitor_create_pattern::operator() (image_rgba8 & data) { return std::make_shared(data, opacity_); } @@ -87,7 +87,7 @@ void cairo_renderer::process(line_pattern_symbolizer const& sym, cairo_save_restore guard(context_); context_.set_operator(comp_op); std::shared_ptr pattern; - std::shared_ptr image = nullptr; + std::shared_ptr image = nullptr; // TODO - re-implement at renderer level like polygon_pattern symbolizer double opacity = get(sym, feature, common_.vars_); if ((*marker)->is_bitmap()) @@ -101,7 +101,7 @@ void cairo_renderer::process(line_pattern_symbolizer const& sym, agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); auto image_transform = get_optional(sym, keys::image_transform); if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - image = render_pattern(ras, **marker, image_tr, 1.0); + image = render_pattern(ras, **marker, image_tr, 1.0); pattern = std::make_unique(*image, opacity); width = image->width(); height = image->height(); diff --git a/src/cairo/process_polygon_pattern_symbolizer.cpp b/src/cairo/process_polygon_pattern_symbolizer.cpp index 99e0e507c..a2c742a7b 100644 --- a/src/cairo/process_polygon_pattern_symbolizer.cpp +++ b/src/cairo/process_polygon_pattern_symbolizer.cpp @@ -58,7 +58,7 @@ struct visitor_set_pattern }; template <> -void visitor_set_pattern::operator() (image_data_rgba8 & data) +void visitor_set_pattern::operator() (image_rgba8 & data) { cairo_pattern pattern(data, opacity_); pattern.set_extend(CAIRO_EXTEND_REPEAT); @@ -119,7 +119,7 @@ void cairo_renderer::process(polygon_pattern_symbolizer const& sym, else { mapnik::rasterizer ras; - std::shared_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // + std::shared_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // cairo_pattern pattern(*image, opacity); pattern.set_extend(CAIRO_EXTEND_REPEAT); pattern.set_origin(offset_x, offset_y); diff --git a/src/cairo/process_raster_symbolizer.cpp b/src/cairo/process_raster_symbolizer.cpp index 36daee737..7915ebbdd 100644 --- a/src/cairo/process_raster_symbolizer.cpp +++ b/src/cairo/process_raster_symbolizer.cpp @@ -43,7 +43,7 @@ void cairo_renderer::process(raster_symbolizer const& sym, cairo_save_restore guard(context_); render_raster_symbolizer( sym, feature, prj_trans, common_, - [&](image_data_rgba8 &target, composite_mode_e comp_op, double opacity, + [&](image_rgba8 &target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { context_.set_operator(comp_op); context_.add_image(start_x, start_y, target, opacity); diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 1b9aef039..3d845e4bc 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -55,6 +55,6 @@ template class feature_style_processor template class feature_style_processor >; #endif -template class feature_style_processor >; +template class feature_style_processor >; } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 55f103232..ccf258632 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -165,7 +165,7 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ } else { - image_data_rgba8 const& data = util::get(**marker.get_bitmap_data()); + image_rgba8 const& data = util::get(**marker.get_bitmap_data()); double width = data.width(); double height = data.height(); double cx = 0.5 * width; @@ -179,7 +179,7 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ } else { - image_data_rgba8 target(data.width(), data.height()); + image_rgba8 target(data.width(), data.height()); mapnik::scale_image_agg(target, data, SCALING_NEAR, diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 9398dc404..7ec0a69cd 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -103,7 +103,7 @@ struct thunk_renderer pixmap_.add_feature(feature_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { using buf_type = grid_rendering_buffer; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; @@ -121,17 +121,17 @@ struct thunk_renderer void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_data_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_rgba8 renderer"); } void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_data_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_rgba8 renderer"); } void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_data_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_rgba8 renderer"); } void operator()(text_render_thunk const &thunk) const diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index a57cb943f..be38f83f5 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -167,7 +167,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_ provided that converts // the destination pixel type required. - render_raster_marker(RendererType(renb_), ras_, util::get(this->src_), this->feature_, marker_tr, opacity); + render_raster_marker(RendererType(renb_), ras_, util::get(this->src_), this->feature_, marker_tr, opacity); if (!placed_) { pixmap_.add_feature(this->feature_); diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 89d2f9d05..ea776a282 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -149,14 +149,14 @@ struct rendering_buffer } // end detail ns template <> -MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, composite_mode_e mode, +MAPNIK_DECL void composite(image_rgba8 & dst, image_rgba8 const& src, composite_mode_e mode, float opacity, int dx, int dy) { using color = agg::rgba8; using order = agg::order_rgba; - using const_rendering_buffer = detail::rendering_buffer; + 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; @@ -233,9 +233,9 @@ void composite_visitor::operator() (T & dst) } template <> -void composite_visitor::operator() (image_data_rgba8 & dst) +void composite_visitor::operator() (image_rgba8 & dst) { - composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); } template <> diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index 7edf13e6e..d93ce64e2 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -165,7 +165,7 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho } -template MAPNIK_DECL void scale_image_agg(image_data_rgba8 &, image_data_rgba8 const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_rgba8 &, image_rgba8 const&, scaling_method_e, double, double , double, double , double); template MAPNIK_DECL void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e, diff --git a/src/image_util.cpp b/src/image_util.cpp index 647a07ba7..de5c21f3c 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -126,7 +126,7 @@ MAPNIK_DECL void save_to_stream(T const& image, // This can be removed once image_any and image_view_any are the only // items using this template template <> -MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, +MAPNIK_DECL void save_to_stream(image_rgba8 const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) @@ -222,7 +222,7 @@ MAPNIK_DECL void save_to_stream(T const& image, // This can be removed once image_any and image_view_any are the only // items using this template template <> -MAPNIK_DECL void save_to_stream(image_data_rgba8 const& image, +MAPNIK_DECL void save_to_stream(image_rgba8 const& image, std::ostream & stream, std::string const& type) { @@ -321,27 +321,27 @@ MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, rgba_ else throw ImageWriterException("Could not write file to " + filename ); } -// image_data_rgba8 -template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +// image_rgba8 +template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&, std::string const&); -template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&, std::string const&, rgba_palette const& palette); -template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&); -template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, +template MAPNIK_DECL void save_to_file(image_rgba8 const&, std::string const&, rgba_palette const& palette); -template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, +template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, std::string const&); -template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, +template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, std::string const&, rgba_palette const& palette); @@ -421,7 +421,7 @@ struct is_solid_visitor } }; -template bool is_solid_visitor::operator() (image_data_rgba8 const& data); +template bool is_solid_visitor::operator() (image_rgba8 const& data); template bool is_solid_visitor::operator() (image_data_gray8 const& data); template bool is_solid_visitor::operator() (image_data_gray16 const& data); template bool is_solid_visitor::operator() (image_data_gray32f const& data); @@ -447,9 +447,9 @@ MAPNIK_DECL bool is_solid(T const& image) template MAPNIK_DECL bool is_solid (image_any const&); template MAPNIK_DECL bool is_solid (image_view_any const&); -// Temporary until image_data_rgba8 is removed from passing +// Temporary until image_rgba8 is removed from passing template <> -MAPNIK_DECL bool is_solid(image_data_rgba8 const& image) +MAPNIK_DECL bool is_solid(image_rgba8 const& image) { detail::is_solid_visitor visitor; return visitor(image); @@ -476,7 +476,7 @@ struct premultiply_visitor }; template <> -bool premultiply_visitor::operator() (image_data_rgba8 & data) +bool premultiply_visitor::operator() (image_rgba8 & data) { if (!data.get_premultiplied()) { @@ -500,7 +500,7 @@ struct demultiply_visitor }; template <> -bool demultiply_visitor::operator() (image_data_rgba8 & data) +bool demultiply_visitor::operator() (image_rgba8 & data) { if (data.get_premultiplied()) { @@ -539,7 +539,7 @@ template MAPNIK_DECL bool premultiply_alpha (image_any &); // Temporary, can be removed once image_view_any and image_any are the only ones passed template <> -MAPNIK_DECL bool premultiply_alpha(image_data_rgba8 & image) +MAPNIK_DECL bool premultiply_alpha(image_rgba8 & image) { detail::premultiply_visitor visit; return visit(image); @@ -555,7 +555,7 @@ template MAPNIK_DECL bool demultiply_alpha (image_any &); // Temporary, can be removed once image_view_any and image_any are the only ones passed template <> -MAPNIK_DECL bool demultiply_alpha(image_data_rgba8 & image) +MAPNIK_DECL bool demultiply_alpha(image_rgba8 & image) { detail::demultiply_visitor visit; return visit(image); @@ -571,7 +571,7 @@ template void set_premultiplied_alpha (image_any &, bool); // Temporary, can be removed once image_view_any and image_any are the only ones passed template <> -MAPNIK_DECL void set_premultiplied_alpha(image_data_rgba8 & image, bool status) +MAPNIK_DECL void set_premultiplied_alpha(image_rgba8 & image, bool status) { detail::set_premultiplied_visitor visit(status); visit(image); @@ -596,9 +596,9 @@ struct visitor_set_alpha }; template <> -void visitor_set_alpha::operator() (image_data_rgba8 & data) +void visitor_set_alpha::operator() (image_rgba8 & data) { - using pixel_type = typename image_data_rgba8::pixel_type; + using pixel_type = typename image_rgba8::pixel_type; for (unsigned int y = 0; y < data.height(); ++y) { pixel_type* row_to = data.getRow(y); @@ -635,7 +635,7 @@ MAPNIK_DECL void set_alpha (image_any & data, float opacity) // TEMPORARY can be removed once image_any is only way it is being passed. template<> -MAPNIK_DECL void set_alpha (image_data_rgba8 & data, float opacity) +MAPNIK_DECL void set_alpha (image_rgba8 & data, float opacity) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -659,9 +659,9 @@ struct visitor_set_grayscale_to_alpha }; template <> -void visitor_set_grayscale_to_alpha::operator() (image_data_rgba8 & data) +void visitor_set_grayscale_to_alpha::operator() (image_rgba8 & data) { - using pixel_type = typename image_data_rgba8::pixel_type; + using pixel_type = typename image_rgba8::pixel_type; for (unsigned int y = 0; y < data.height(); ++y) { pixel_type* row_from = data.getRow(y); @@ -696,7 +696,7 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_any & data) // TEMPORARY can be removed once image_any is only way it is being passed. template<> -MAPNIK_DECL void set_grayscale_to_alpha (image_data_rgba8 & data) +MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -727,9 +727,9 @@ struct visitor_set_color_to_alpha }; template <> -void visitor_set_color_to_alpha::operator() (image_data_rgba8 & data) +void visitor_set_color_to_alpha::operator() (image_rgba8 & data) { - using pixel_type = typename image_data_rgba8::pixel_type; + using pixel_type = typename image_rgba8::pixel_type; for (unsigned y = 0; y < data.height(); ++y) { pixel_type* row_from = data.getRow(y); @@ -763,7 +763,7 @@ MAPNIK_DECL void set_color_to_alpha (image_any & data, color const& c // TEMPORARY can be removed once image_any is only way it is being passed. template<> -MAPNIK_DECL void set_color_to_alpha (image_data_rgba8 & data, color const& c) +MAPNIK_DECL void set_color_to_alpha (image_rgba8 & data, color const& c) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -835,7 +835,7 @@ template MAPNIK_DECL void fill(image_any &, double const&); // Temporary remove these later! template <> -MAPNIK_DECL void fill (image_data_rgba8 & data , color const& val) +MAPNIK_DECL void fill (image_rgba8 & data , color const& val) { detail::visitor_fill visitor(val); visitor(data); @@ -843,7 +843,7 @@ MAPNIK_DECL void fill (image_data_rgba8 & data , color // Temporary remove these later! template <> -MAPNIK_DECL void fill (image_data_rgba8 & data , uint32_t const& val) +MAPNIK_DECL void fill (image_rgba8 & data , uint32_t const& val) { detail::visitor_fill visitor(val); visitor(data); @@ -851,7 +851,7 @@ MAPNIK_DECL void fill (image_data_rgba8 & data , uin // Temporary remove these later! template <> -MAPNIK_DECL void fill (image_data_rgba8 & data , int32_t const& val) +MAPNIK_DECL void fill (image_rgba8 & data , int32_t const& val) { detail::visitor_fill visitor(val); visitor(data); @@ -894,10 +894,10 @@ struct visitor_set_rectangle }; template <> -void visitor_set_rectangle::operator() (image_data_rgba8 & dst) +void visitor_set_rectangle::operator() (image_rgba8 & dst) { - using pixel_type = typename image_data_rgba8::pixel_type; - image_data_rgba8 src = util::get(src_); + using pixel_type = typename image_rgba8::pixel_type; + image_rgba8 src = util::get(src_); box2d ext0(0,0,dst.width(),dst.height()); box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); @@ -973,7 +973,7 @@ struct visitor_composite_pixel }; template<> -void visitor_composite_pixel::operator() (image_data_rgba8 & data) +void visitor_composite_pixel::operator() (image_rgba8 & data) { using color_type = agg::rgba8; using value_type = color_type::value_type; @@ -1002,7 +1002,7 @@ MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c // Temporary delete later template <> -MAPNIK_DECL void composite_pixel(image_data_rgba8 & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +MAPNIK_DECL void composite_pixel(image_rgba8 & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) { detail::visitor_composite_pixel visitor(op, x, y, c, cover, opacity); visitor(data); @@ -1078,7 +1078,7 @@ template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, doubl // Temporary remove these later! template <> -MAPNIK_DECL void set_pixel (image_data_rgba8 & data, std::size_t x, std::size_t y, color const& val) +MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, color const& val) { detail::visitor_set_pixel visitor(x, y, val); visitor(data); @@ -1086,7 +1086,7 @@ MAPNIK_DECL void set_pixel (image_data_rgba8 & data, st // Temporary remove these later! template <> -MAPNIK_DECL void set_pixel (image_data_rgba8 & data, std::size_t x, std::size_t y, uint32_t const& val) +MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, uint32_t const& val) { detail::visitor_set_pixel visitor(x, y, val); visitor(data); @@ -1094,7 +1094,7 @@ MAPNIK_DECL void set_pixel (image_data_rgba8 & data, // Temporary remove these later! template <> -MAPNIK_DECL void set_pixel (image_data_rgba8 & data, std::size_t x, std::size_t y, int32_t const& val) +MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, int32_t const& val) { detail::visitor_set_pixel visitor(x, y, val); visitor(data); @@ -1176,7 +1176,7 @@ template MAPNIK_DECL double get_pixel(image_any const&, std::size_t, std::size_t // Temporary remove these later! template <> -MAPNIK_DECL color get_pixel (image_data_rgba8 const& data, std::size_t x, std::size_t y) +MAPNIK_DECL color get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) { detail::visitor_get_pixel visitor(x, y); return visitor(data); @@ -1184,7 +1184,7 @@ MAPNIK_DECL color get_pixel (image_data_rgba8 const& da // Temporary remove these later! template <> -MAPNIK_DECL uint32_t get_pixel (image_data_rgba8 const& data, std::size_t x, std::size_t y) +MAPNIK_DECL uint32_t get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) { detail::visitor_get_pixel visitor(x, y); return visitor(data); @@ -1192,7 +1192,7 @@ MAPNIK_DECL uint32_t get_pixel (image_data_rgba8 con // Temporary remove these later! template <> -MAPNIK_DECL int32_t get_pixel (image_data_rgba8 const& data, std::size_t x, std::size_t y) +MAPNIK_DECL int32_t get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) { detail::visitor_get_pixel visitor(x, y); return visitor(data); diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index efe4611d0..cc0e6c651 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -65,7 +65,7 @@ void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & str } template<> -void jpeg_saver::operator() (image_data_rgba8 const& image) const +void jpeg_saver::operator() (image_rgba8 const& image) const { process_rgba8_jpeg(image, t_, stream_); } diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index b34075882..78ced0e0a 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -259,7 +259,7 @@ void process_rgba8_png(T const& image, } template<> -void png_saver_pal::operator() (image_data_rgba8 const& image) const +void png_saver_pal::operator() (image_rgba8 const& image) const { process_rgba8_png_pal(image, t_, stream_, pal_); } @@ -271,7 +271,7 @@ void png_saver_pal::operator() (image_view_rgba8 const& image) } template<> -void png_saver::operator() (image_data_rgba8 const& image) const +void png_saver::operator() (image_rgba8 const& image) const { process_rgba8_png(image, t_, stream_); } diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index 533eeb2a3..3da0136bf 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -181,7 +181,7 @@ void tiff_saver::operator() (T const& image) const #endif } -template void tiff_saver::operator() (image_data_rgba8 const& image) const; +template void tiff_saver::operator() (image_rgba8 const& image) const; template void tiff_saver::operator() (image_data_gray8 const& image) const; template void tiff_saver::operator() (image_data_gray16 const& image) const; template void tiff_saver::operator() (image_data_gray32f const& image) const; diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index 8cea5f718..96b82bf82 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -360,7 +360,7 @@ void process_rgba8_webp(T const& image, std::string const& t, std::ostream & str } template <> -void webp_saver::operator() (image_data_rgba8 const& image) const +void webp_saver::operator() (image_rgba8 const& image) const { process_rgba8_webp(image, t_, stream_); } @@ -377,7 +377,7 @@ void webp_saver::operator() (T const& image) const throw ImageWriterException("Mapnik does not support webp grayscale images"); } -template void webp_saver::operator() (image_data_rgba8 const& image) const; +template void webp_saver::operator() (image_rgba8 const& image) const; template void webp_saver::operator() (image_data_gray8 const& image) const; template void webp_saver::operator() (image_data_gray16 const& image) const; template void webp_saver::operator() (image_data_gray32f const& image) const; diff --git a/src/jpeg_reader.cpp b/src/jpeg_reader.cpp index 0bc66e480..e375e9a10 100644 --- a/src/jpeg_reader.cpp +++ b/src/jpeg_reader.cpp @@ -85,7 +85,7 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return false; } - void read(unsigned x,unsigned y,image_data_rgba8& image) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); @@ -265,7 +265,7 @@ boost::optional > jpeg_reader::bounding_box() const } template -void jpeg_reader::read(unsigned x0, unsigned y0, image_data_rgba8& image) +void jpeg_reader::read(unsigned x0, unsigned y0, image_rgba8& image) { stream_.clear(); stream_.seekg(0, std::ios_base::beg); @@ -322,7 +322,7 @@ void jpeg_reader::read(unsigned x0, unsigned y0, image_data_rgba8& image) template image_any jpeg_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height, true, true); + image_rgba8 data(width,height, true, true); read(x, y, data); return image_any(std::move(data)); } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 27e08fcf6..63b27f1d7 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -62,7 +62,7 @@ marker_cache::marker_cache() "" "" ""); - image_data_rgba8 im(4,4,true,true); + image_rgba8 im(4,4,true,true); im.set(0xff000000); boost::optional bitmap_data = boost::optional(std::make_shared(std::move(im))); marker_ptr mark = std::make_shared(bitmap_data); @@ -135,7 +135,7 @@ struct visitor_create_marker }; template<> -marker_ptr visitor_create_marker::operator() (image_data_rgba8 & data) +marker_ptr visitor_create_marker::operator() (image_rgba8 & data) { std::shared_ptr image = std::make_shared(data); mapnik::premultiply_alpha(*image); diff --git a/src/miniz_png.cpp b/src/miniz_png.cpp index 485337992..b4ee851de 100644 --- a/src/miniz_png.cpp +++ b/src/miniz_png.cpp @@ -363,9 +363,9 @@ const mz_uint8 PNGWriter::IEND_tpl[] = { template void PNGWriter::writeIDAT(image_data_gray8 const& image); template void PNGWriter::writeIDAT(image_view_gray8 const& image); -template void PNGWriter::writeIDAT(image_data_rgba8 const& image); +template void PNGWriter::writeIDAT(image_rgba8 const& image); template void PNGWriter::writeIDAT(image_view_rgba8 const& image); -template void PNGWriter::writeIDATStripAlpha(image_data_rgba8 const& image); +template void PNGWriter::writeIDATStripAlpha(image_rgba8 const& image); template void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); }} diff --git a/src/png_reader.cpp b/src/png_reader.cpp index 9efc02bef..0773a4164 100644 --- a/src/png_reader.cpp +++ b/src/png_reader.cpp @@ -80,7 +80,7 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - void read(unsigned x,unsigned y,image_data_rgba8& image) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); @@ -226,7 +226,7 @@ boost::optional > png_reader::bounding_box() const } template -void png_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) +void png_reader::read(unsigned x0, unsigned y0,image_rgba8& image) { stream_.clear(); stream_.seekg(0, std::ios_base::beg); @@ -312,7 +312,7 @@ void png_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) template image_any png_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height); + image_rgba8 data(width,height); read(x, y, data); return image_any(std::move(data)); } diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index 9bed5500a..f3bf48ea0 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -123,7 +123,7 @@ bool raster_colorizer::add_stop(colorizer_stop const& stop) } template -void raster_colorizer::colorize(image_data_rgba8 & out, T const& in, +void raster_colorizer::colorize(image_rgba8 & out, T const& in, boost::optional const& nodata, feature_impl const& f) const { @@ -286,13 +286,13 @@ unsigned raster_colorizer::get_color(float value) const } -template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray8 const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_data_gray8 const& in, boost::optionalconst& nodata, feature_impl const& f) const; -template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray16 const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_data_gray16 const& in, boost::optionalconst& nodata, feature_impl const& f) const; -template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray32f const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_data_gray32f const& in, boost::optionalconst& nodata, feature_impl const& f) const; diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index 2da30b553..c41abba7c 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -40,7 +40,7 @@ vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, {} template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_data_rgba8 & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index 0156cf10a..4263882d9 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -38,7 +38,7 @@ namespace mapnik { template <> -std::shared_ptr render_pattern(rasterizer & ras, +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity) @@ -54,7 +54,7 @@ std::shared_ptr render_pattern(rasterizer & mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); mtx = tr * mtx; - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4); pixfmt pixf(buf); renderer_base renb(pixf); diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index a933e45e0..25566e9c4 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -358,7 +358,7 @@ grid_text_renderer::grid_text_renderer(pixmap_type &pixmap, : text_renderer(HALO_RASTERIZER_FAST, comp_op, src_over, scale_factor), pixmap_(pixmap) {} -template class agg_text_renderer; +template class agg_text_renderer; template class grid_text_renderer; } // namespace mapnik diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 74f1fdd5b..eefc1d98b 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -153,7 +153,7 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - void read(unsigned x,unsigned y,image_data_rgba8& image) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; // methods specific to tiff reader unsigned bits_per_sample() const { return bps_; } @@ -168,8 +168,8 @@ private: tiff_reader(const tiff_reader&); tiff_reader& operator=(const tiff_reader&); void init(); - void read_generic(unsigned x,unsigned y,image_data_rgba8& image); - void read_stripped(unsigned x,unsigned y,image_data_rgba8& image); + void read_generic(unsigned x,unsigned y,image_rgba8& image); + void read_stripped(unsigned x,unsigned y,image_rgba8& image); template void read_tiled(unsigned x,unsigned y, ImageData & image); @@ -377,7 +377,7 @@ boost::optional > tiff_reader::bounding_box() const } template -void tiff_reader::read(unsigned x,unsigned y,image_data_rgba8& image) +void tiff_reader::read(unsigned x,unsigned y,image_rgba8& image) { if (read_method_==stripped) { @@ -464,7 +464,7 @@ struct tiff_reader_traits // default specialization that expands into RGBA template <> -struct tiff_reader_traits +struct tiff_reader_traits { using pixel_type = std::uint32_t; static bool read_tile(TIFF * tif, unsigned x0, unsigned y0, pixel_type* buf, std::size_t tile_width, std::size_t tile_height) @@ -518,7 +518,7 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne TIFF* tif = open(stream_); if (tif) { - image_data_rgba8 data(width, height, true, premultiplied_alpha_); + image_rgba8 data(width, height, true, premultiplied_alpha_); std::size_t element_size = sizeof(detail::rgb8); std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size; const std::unique_ptr scanline(new detail::rgb8[size_to_allocate]); @@ -532,7 +532,7 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne { if (y >= y0) { - image_data_rgba8::pixel_type * row = data.getRow(y - y0); + image_rgba8::pixel_type * row = data.getRow(y - y0); std::transform(scanline.get() + start_x, scanline.get() + end_x, row, detail::rgb8_to_rgba8()); } } @@ -543,13 +543,13 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne } case 16: { - image_data_rgba8 data(width,height,true,premultiplied_alpha_); + image_rgba8 data(width,height,true,premultiplied_alpha_); read(x0, y0, data); return image_any(std::move(data)); } case 32: { - image_data_rgba8 data(width,height,true,premultiplied_alpha_); + image_rgba8 data(width,height,true,premultiplied_alpha_); read(x0, y0, data); return image_any(std::move(data)); } @@ -567,7 +567,7 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne //PHOTOMETRIC_ITULAB = 10; //PHOTOMETRIC_LOGL = 32844; //PHOTOMETRIC_LOGLUV = 32845; - image_data_rgba8 data(width,height, true, premultiplied_alpha_); + image_rgba8 data(width,height, true, premultiplied_alpha_); read(x0, y0, data); return image_any(std::move(data)); } @@ -576,7 +576,7 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne } template -void tiff_reader::read_generic(unsigned, unsigned, image_data_rgba8& image) +void tiff_reader::read_generic(unsigned, unsigned, image_rgba8& image) { TIFF* tif = open(stream_); if (tif) @@ -630,12 +630,12 @@ void tiff_reader::read_tiled(unsigned x0,unsigned y0, ImageData & image) template -void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_rgba8& image) +void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_rgba8& image) { TIFF* tif = open(stream_); if (tif) { - image_data_rgba8 strip(width_,rows_per_strip_,false); + image_rgba8 strip(width_,rows_per_strip_,false); int width=image.width(); int height=image.height(); diff --git a/src/warp.cpp b/src/warp.cpp index 16a81492d..431263c17 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -210,7 +210,7 @@ void reproject_and_scale_raster(raster & target, raster const& source, util::apply_visitor(warper, source.data_); } -template MAPNIK_DECL void warp_image (image_data_rgba8&, image_data_rgba8 const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_rgba8&, image_rgba8 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); template MAPNIK_DECL void warp_image (image_data_gray8&, image_data_gray8 const&, proj_transform const&, diff --git a/src/webp_reader.cpp b/src/webp_reader.cpp index 2df7f96ba..967fb0469 100644 --- a/src/webp_reader.cpp +++ b/src/webp_reader.cpp @@ -124,7 +124,7 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - void read(unsigned x,unsigned y,image_data_rgba8& image) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); @@ -236,7 +236,7 @@ boost::optional > webp_reader::bounding_box() const } template -void webp_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) +void webp_reader::read(unsigned x0, unsigned y0,image_rgba8& image) { WebPDecoderConfig config; config_guard guard(config); @@ -270,7 +270,7 @@ void webp_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) template image_any webp_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height); + image_rgba8 data(width,height); read(x, y, data); return image_any(std::move(data)); } diff --git a/tests/cpp_tests/exceptions_test.cpp b/tests/cpp_tests/exceptions_test.cpp index 38e742344..de3008f1b 100644 --- a/tests/cpp_tests/exceptions_test.cpp +++ b/tests/cpp_tests/exceptions_test.cpp @@ -82,8 +82,8 @@ int main(int argc, char** argv) mapnik::Map m = map; m.add_layer(l); m.zoom_all(); - mapnik::image_data_rgba8 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); //std::clog << mapnik::save_map_to_string(m) << "\n"; BOOST_TEST(true); // should throw here with "CSV Plugin: no attribute 'foo'. Valid attributes are: x,y." diff --git a/tests/cpp_tests/fontset_runtime_test.cpp b/tests/cpp_tests/fontset_runtime_test.cpp index 9c6c883d9..a0045e646 100644 --- a/tests/cpp_tests/fontset_runtime_test.cpp +++ b/tests/cpp_tests/fontset_runtime_test.cpp @@ -81,8 +81,8 @@ int main(int argc, char** argv) m.insert_style("style", std::move(the_style) ); m.zoom_to_box(mapnik::box2d(-256,-256, 256,256)); - mapnik::image_data_rgba8 buf(m.width(),m.height()); - mapnik::agg_renderer ren(m,buf); + mapnik::image_rgba8 buf(m.width(),m.height()); + mapnik::agg_renderer ren(m,buf); ren.apply(); } catch (std::exception const& ex) { BOOST_TEST_EQ(std::string(ex.what()),std::string("Unable to find specified font face 'DejaVu Sans Book' in font set: 'fontset'")); diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index f275b0665..7cc037862 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -45,7 +45,7 @@ int main(int argc, char** argv) try { - mapnik::image_data_rgba8 im(-10,-10); // should throw rather than overflow + mapnik::image_rgba8 im(-10,-10); // should throw rather than overflow BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail } catch (std::exception const& ex) @@ -57,7 +57,7 @@ int main(int argc, char** argv) mapnik::cairo_surface_ptr image_surface( cairo_image_surface_create(CAIRO_FORMAT_ARGB32,256,257), mapnik::cairo_surface_closer()); - mapnik::image_data_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); + mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); im_data.set(1); BOOST_TEST( (unsigned)im_data(0,0) == unsigned(1) ); // Should set back to fully transparent diff --git a/tests/cpp_tests/image_painted_test.cpp b/tests/cpp_tests/image_painted_test.cpp index b3cbc8238..b58a87e07 100644 --- a/tests/cpp_tests/image_painted_test.cpp +++ b/tests/cpp_tests/image_painted_test.cpp @@ -59,8 +59,8 @@ int main(int argc, char** argv) m.zoom_all(); - image_data_rgba8 image(m.width(), m.height()); - agg_renderer ren(m, image); + image_rgba8 image(m.width(), m.height()); + agg_renderer ren(m, image); ren.apply(); BOOST_TEST_EQ(image.painted(), true); diff --git a/tests/cpp_tests/map_request_test.cpp b/tests/cpp_tests/map_request_test.cpp index b9f5210bc..194f2a9b7 100644 --- a/tests/cpp_tests/map_request_test.cpp +++ b/tests/cpp_tests/map_request_test.cpp @@ -29,7 +29,7 @@ bool compare_images(std::string const& src_fn,std::string const& dest_fn) { throw mapnik::image_reader_exception("Failed to load: " + dest_fn); } - std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); + std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); reader1->read(0,0,*image_ptr1); std::unique_ptr reader2(mapnik::get_image_reader(src_fn,"png")); @@ -37,11 +37,11 @@ bool compare_images(std::string const& src_fn,std::string const& dest_fn) { throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); + std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); reader2->read(0,0,*image_ptr2); - image_data_rgba8 const& dest = *image_ptr1; - image_data_rgba8 const& src = *image_ptr2; + image_rgba8 const& dest = *image_ptr1; + image_rgba8 const& src = *image_ptr2; unsigned int width = src.width(); unsigned int height = src.height(); @@ -77,11 +77,11 @@ int main(int argc, char** argv) mapnik::Map m(256,256); mapnik::load_map(m,"./tests/data/good_maps/marker-text-line.xml",false); m.zoom_all(); - mapnik::image_data_rgba8 im(m.width(),m.height()); + mapnik::image_rgba8 im(m.width(),m.height()); double scale_factor = 1.2; // render normally with apply() and just map and image - mapnik::agg_renderer renderer1(m,im,scale_factor); + mapnik::agg_renderer renderer1(m,im,scale_factor); renderer1.apply(); std::string actual1("/tmp/map-request-marker-text-line-actual1.png"); //mapnik::save_to_file(im,expected); @@ -99,7 +99,7 @@ int main(int argc, char** argv) // render using apply() and mapnik::request mapnik::attributes vars; - mapnik::agg_renderer renderer2(m,req,vars,im,scale_factor); + mapnik::agg_renderer renderer2(m,req,vars,im,scale_factor); renderer2.apply(); std::string actual2("/tmp/map-request-marker-text-line-actual2.png"); mapnik::save_to_file(im,actual2); @@ -111,7 +111,7 @@ int main(int argc, char** argv) mapnik::fill(im, 0); // render with apply_to_layer api and mapnik::request params passed to apply_to_layer - mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); + mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); renderer3.start_map_processing(m); mapnik::projection map_proj(m.srs(),true); double scale_denom = mapnik::scale_denominator(req.scale(),map_proj.is_geographic()); diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index d312331c7..1a352aae0 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -75,7 +75,7 @@ SECTION("scan rgb8 striped") { REQUIRE( reader2->width() == 512 ); REQUIRE( reader2->height() == 512 ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -105,7 +105,7 @@ SECTION("scan rgb8 tiled") { REQUIRE( reader2->width() == 512 ); REQUIRE( reader2->height() == 512 ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -121,7 +121,7 @@ SECTION("rgba8 striped") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_ADOBE_DEFLATE ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -137,7 +137,7 @@ SECTION("rgba8 tiled") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -153,7 +153,7 @@ SECTION("rgb8 striped") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -169,7 +169,7 @@ SECTION("rgb8 tiled") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL diff --git a/utils/nik2img/nik2img.cpp b/utils/nik2img/nik2img.cpp index 8a9976248..1d11358df 100644 --- a/utils/nik2img/nik2img.cpp +++ b/utils/nik2img/nik2img.cpp @@ -110,7 +110,7 @@ int main (int argc,char** argv) mapnik::Map map(600,400); mapnik::load_map(map,xml_file,true); map.zoom_all(); - mapnik::image_data_rgba8 im(map.width(),map.height()); + mapnik::image_rgba8 im(map.width(),map.height()); mapnik::request req(map.width(),map.height(),map.get_current_extent()); req.set_buffer_size(map.buffer_size()); mapnik::attributes vars; @@ -137,7 +137,7 @@ int main (int argc,char** argv) } } } - mapnik::agg_renderer ren(map,req,vars,im,scale_factor,0,0); + mapnik::agg_renderer ren(map,req,vars,im,scale_factor,0,0); ren.apply(); mapnik::save_to_file(im,img_file); if (auto_open) diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 4913c1a7e..24f11e623 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -157,7 +157,7 @@ int main (int argc,char** argv) std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; } // 10 pixel buffer to avoid edge clipping of 100% svg's - mapnik::image_data_rgba8 im(w+0,h+0); + mapnik::image_rgba8 im(w+0,h+0); agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.width() * 4); pixfmt pixf(buf); renderer_base renb(pixf); @@ -181,7 +181,7 @@ int main (int argc,char** argv) boost::algorithm::ireplace_last(svg_name,".svg",".png"); demultiply_alpha(im); - mapnik::save_to_file(im,svg_name,"png"); + mapnik::save_to_file(im,svg_name,"png"); if (auto_open) { std::ostringstream s; From e01ce5b7d65b3f43b3d856296bcaec8aac9c28b7 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 21 Jan 2015 21:08:04 -0600 Subject: [PATCH 53/91] Changed image_data_gray* to image_gray* Ref #2633. --- include/mapnik/image_any.hpp | 12 ++++---- include/mapnik/image_data.hpp | 6 ++-- include/mapnik/image_scaling_traits.hpp | 6 ++-- include/mapnik/image_view.hpp | 6 ++-- include/mapnik/miniz_png.hpp | 2 +- include/mapnik/png_io.hpp | 28 +++++++++---------- .../process_group_symbolizer.hpp | 12 ++++---- include/mapnik/tiff_io.hpp | 6 ++-- plugins/input/gdal/gdal_featureset.cpp | 2 +- .../input/pgraster/pgraster_wkb_reader.cpp | 2 +- src/agg/process_group_symbolizer.cpp | 12 ++++---- src/grid/process_group_symbolizer.cpp | 12 ++++---- src/image_compositing.cpp | 8 +++--- src/image_scaling.cpp | 6 ++-- src/image_util.cpp | 6 ++-- src/image_util_jpeg.cpp | 6 ++-- src/image_util_png.cpp | 12 ++++---- src/image_util_tiff.cpp | 6 ++-- src/image_util_webp.cpp | 6 ++-- src/miniz_png.cpp | 2 +- src/raster_colorizer.cpp | 6 ++-- .../process_group_symbolizer.cpp | 6 ++-- src/renderer_common/render_pattern.cpp | 12 ++++---- src/tiff_reader.cpp | 6 ++-- src/warp.cpp | 6 ++-- tests/cxx/tiff_io.cpp | 12 ++++---- 26 files changed, 103 insertions(+), 103 deletions(-) diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index 58fd0d0b7..054c57fc0 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -53,9 +53,9 @@ struct image_data_null using image_data_base = util::variant; + image_gray8, + image_gray16, + image_gray32f>; // Forward declaring struct image_any; @@ -208,11 +208,11 @@ inline image_any create_image_any(int width, switch (type) { case image_dtype_gray8: - return image_any(std::move(image_data_gray8(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_gray8(width, height, initialize, premultiplied, painted))); case image_dtype_gray16: - return image_any(std::move(image_data_gray16(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_gray16(width, height, initialize, premultiplied, painted))); case image_dtype_gray32f: - return image_any(std::move(image_data_gray32f(width, height, initialize, premultiplied, painted))); + return image_any(std::move(image_gray32f(width, height, initialize, premultiplied, painted))); case image_dtype_null: return image_any(std::move(image_data_null())); case image_dtype_rgba8: diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image_data.hpp index 153e9a3b8..8736ae605 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image_data.hpp @@ -278,9 +278,9 @@ private: }; using image_rgba8 = image_data; -using image_data_gray8 = image_data ; -using image_data_gray16 = image_data; -using image_data_gray32f = image_data; +using image_gray8 = image_data ; +using image_gray16 = image_data; +using image_gray32f = image_data; enum image_dtype { diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp index 47b47e331..c891b37df 100644 --- a/include/mapnik/image_scaling_traits.hpp +++ b/include/mapnik/image_scaling_traits.hpp @@ -50,7 +50,7 @@ struct agg_scaling_traits }; template <> -struct agg_scaling_traits +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_gray8_pre; using color_type = agg::gray8; @@ -61,7 +61,7 @@ struct agg_scaling_traits }; template <> -struct agg_scaling_traits +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_gray16_pre; using color_type = agg::gray16; @@ -72,7 +72,7 @@ struct agg_scaling_traits }; template <> -struct agg_scaling_traits +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_gray32_pre; using color_type = agg::gray32; diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 6c0e9ac94..0c9a45e82 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -119,9 +119,9 @@ private: }; using image_view_rgba8 = image_view; -using image_view_gray8 = image_view; -using image_view_gray16 = image_view; -using image_view_gray32f = image_view; +using image_view_gray8 = image_view; +using image_view_gray16 = image_view; +using image_view_gray32f = image_view; } // end ns diff --git a/include/mapnik/miniz_png.hpp b/include/mapnik/miniz_png.hpp index e5e00748c..9d36f3bbc 100644 --- a/include/mapnik/miniz_png.hpp +++ b/include/mapnik/miniz_png.hpp @@ -83,7 +83,7 @@ private: static const unsigned char IEND_tpl[]; }; -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_gray8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_gray8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_gray8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_rgba8 const& image); extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_rgba8 const& image); diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index de504a3a6..0aa3afc01 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -149,7 +149,7 @@ void save_as_png(T1 & file, template void reduce_8(T const& in, - image_data_gray8 & out, + image_gray8 & out, octree trees[], unsigned limits[], unsigned levels, @@ -167,7 +167,7 @@ void reduce_8(T const& in, for (unsigned y = 0; y < height; ++y) { mapnik::image_rgba8::pixel_type const * row = in.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y); + mapnik::image_gray8::pixel_type * row_out = out.getRow(y); for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; @@ -200,7 +200,7 @@ void reduce_8(T const& in, template void reduce_4(T const& in, - image_data_gray8 & out, + image_gray8 & out, octree trees[], unsigned limits[], unsigned levels, @@ -218,7 +218,7 @@ void reduce_4(T const& in, for (unsigned y = 0; y < height; ++y) { mapnik::image_rgba8::pixel_type const * row = in.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y); + mapnik::image_gray8::pixel_type * row_out = out.getRow(y); for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; @@ -256,7 +256,7 @@ void reduce_4(T const& in, // 1-bit but only one color. template void reduce_1(T const&, - image_data_gray8 & out, + image_gray8 & out, octree /*trees*/[], unsigned /*limits*/[], std::vector & /*alpha*/) @@ -266,7 +266,7 @@ void reduce_1(T const&, template void save_as_png(T & file, std::vector const& palette, - mapnik::image_data_gray8 const& image, + mapnik::image_gray8 const& image, unsigned width, unsigned height, unsigned color_depth, @@ -556,7 +556,7 @@ void save_as_png8_oct(T1 & file, if (palette.size() > 16 ) { // >16 && <=256 colors -> write 8-bit color depth - image_data_gray8 reduced_image(width,height); + image_gray8 reduced_image(width,height); reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable); save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts); } @@ -565,7 +565,7 @@ void save_as_png8_oct(T1 & file, // 1 color image -> write 1-bit color depth PNG unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width,image_height); + image_gray8 reduced_image(image_width,image_height); reduce_1(image,reduced_image,trees, limits, alphaTable); if (meanAlpha<255 && cols[0]==0) { @@ -579,7 +579,7 @@ void save_as_png8_oct(T1 & file, // <=16 colors -> write 4-bit color depth PNG unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width,image_height); + image_gray8 reduced_image(image_width,image_height); reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable); save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts); } @@ -600,11 +600,11 @@ void save_as_png8(T1 & file, if (palette.size() > 16 ) { // >16 && <=256 colors -> write 8-bit color depth - image_data_gray8 reduced_image(width, height); + image_gray8 reduced_image(width, height); for (unsigned y = 0; y < height; ++y) { mapnik::image_rgba8::pixel_type const * row = image.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); + mapnik::image_gray8::pixel_type * row_out = reduced_image.getRow(y); for (unsigned x = 0; x < width; ++x) { row_out[x] = tree.quantize(row[x]); @@ -617,7 +617,7 @@ void save_as_png8(T1 & file, // 1 color image -> write 1-bit color depth PNG unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width, image_height); + image_gray8 reduced_image(image_width, image_height); reduced_image.set(0); save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts); } @@ -626,11 +626,11 @@ void save_as_png8(T1 & file, // <=16 colors -> write 4-bit color depth PNG unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width, image_height); + image_gray8 reduced_image(image_width, image_height); for (unsigned y = 0; y < height; ++y) { mapnik::image_rgba8::pixel_type const * row = image.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); + mapnik::image_gray8::pixel_type * row_out = reduced_image.getRow(y); byte index = 0; for (unsigned x = 0; x < width; ++x) { diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index bb9359014..f0b7e2f75 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -151,9 +151,9 @@ struct raster_marker_render_thunk : util::noncopyable }; template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; using helper_ptr = std::unique_ptr; @@ -185,9 +185,9 @@ struct text_render_thunk : util::noncopyable using render_thunk = util::variant, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, text_render_thunk>; using render_thunk_ptr = std::unique_ptr; using render_thunk_list = std::list; diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 17ce9da0b..0a27ebf75 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -216,7 +216,7 @@ struct tag_setter } } - inline void operator() (image_data_gray32f const&) const + inline void operator() (image_gray32f const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); @@ -229,7 +229,7 @@ struct tag_setter TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT); } } - inline void operator() (image_data_gray16 const&) const + inline void operator() (image_gray16 const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); @@ -243,7 +243,7 @@ struct tag_setter } } - inline void operator() (image_data_gray8 const&) const + inline void operator() (image_gray8 const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 4bcc52450..3d889215c 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -203,7 +203,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; if (band_ > 0) // we are querying a single band { - mapnik::image_data_gray16 image(im_width, im_height); + mapnik::image_gray16 image(im_width, im_height); image.set(std::numeric_limits::max()); if (band_ > nbands_) { diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp index 462a5881b..11e19d2c4 100644 --- a/plugins/input/pgraster/pgraster_wkb_reader.cpp +++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp @@ -183,7 +183,7 @@ mapnik::raster_ptr read_data_band(mapnik::box2d const& bbox, uint16_t width, uint16_t height, bool hasnodata, T reader) { - mapnik::image_data_gray32f image(width, height); + mapnik::image_gray32f image(width, height); //image.set(std::numeric_limits::max()); // Start with plain white (ABGR or RGBA depending on endiannes) // TODO: set to transparent instead? diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index 0c5c8128c..bd7db6c05 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -112,19 +112,19 @@ struct thunk_renderer render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_gray8 type is not supported currently by the image_rgba8 renderer"); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_gray16 type is not supported currently by the image_rgba8 renderer"); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_gray32f type is not supported currently by the image_rgba8 renderer"); } void operator()(text_render_thunk const &thunk) const diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 7ec0a69cd..bcc788a92 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -119,19 +119,19 @@ struct thunk_renderer pixmap_.add_feature(feature_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray8 type is not supported currently by the image_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_gray8 type is not supported currently by the image_rgba8 renderer"); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray16 type is not supported currently by the image_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_gray16 type is not supported currently by the image_rgba8 renderer"); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { - throw std::runtime_error("Rendering of this image_data_gray32f type is not supported currently by the image_rgba8 renderer"); + throw std::runtime_error("Rendering of this image_gray32f type is not supported currently by the image_rgba8 renderer"); } void operator()(text_render_thunk const &thunk) const diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index ea776a282..ea7a8a3d4 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -182,12 +182,12 @@ MAPNIK_DECL void composite(image_rgba8 & dst, image_rgba8 const& src, composite_ } template <> -MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f const& src, composite_mode_e mode, +MAPNIK_DECL void composite(image_gray32f & dst, image_gray32f const& src, composite_mode_e mode, float opacity, int dx, int dy) { - using const_rendering_buffer = detail::rendering_buffer; + 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; @@ -239,9 +239,9 @@ void composite_visitor::operator() (image_rgba8 & dst) } template <> -void composite_visitor::operator() (image_data_gray32f & dst) +void composite_visitor::operator() (image_gray32f & dst) { - composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); } } // end ns diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index d93ce64e2..24ea59ffc 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -168,13 +168,13 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho template MAPNIK_DECL void scale_image_agg(image_rgba8 &, image_rgba8 const&, scaling_method_e, double, double , double, double , double); -template MAPNIK_DECL void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_gray8 &, image_gray8 const&, scaling_method_e, double, double , double, double , double); -template MAPNIK_DECL void scale_image_agg(image_data_gray16 &, image_data_gray16 const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_gray16 &, image_gray16 const&, scaling_method_e, double, double , double, double , double); -template MAPNIK_DECL void scale_image_agg(image_data_gray32f &, image_data_gray32f const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_gray32f &, image_gray32f const&, scaling_method_e, double, double , double, double , double); } diff --git a/src/image_util.cpp b/src/image_util.cpp index de5c21f3c..db064a554 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -422,9 +422,9 @@ struct is_solid_visitor }; template bool is_solid_visitor::operator() (image_rgba8 const& data); -template bool is_solid_visitor::operator() (image_data_gray8 const& data); -template bool is_solid_visitor::operator() (image_data_gray16 const& data); -template bool is_solid_visitor::operator() (image_data_gray32f const& data); +template bool is_solid_visitor::operator() (image_gray8 const& data); +template bool is_solid_visitor::operator() (image_gray16 const& data); +template bool is_solid_visitor::operator() (image_gray32f const& data); template bool is_solid_visitor::operator() (image_view_rgba8 const& data); template bool is_solid_visitor::operator() (image_view_gray8 const& data); template bool is_solid_visitor::operator() (image_view_gray16 const& data); diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index cc0e6c651..523f73b06 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -88,9 +88,9 @@ void jpeg_saver::operator() (T const& image) const throw ImageWriterException("Mapnik does not support jpeg grayscale images"); } -template void jpeg_saver::operator() (image_data_gray8 const& image) const; -template void jpeg_saver::operator() (image_data_gray16 const& image) const; -template void jpeg_saver::operator() (image_data_gray32f const& image) const; +template void jpeg_saver::operator() (image_gray8 const& image) const; +template void jpeg_saver::operator() (image_gray16 const& image) const; +template void jpeg_saver::operator() (image_gray32f const& image) const; template void jpeg_saver::operator() (image_view_gray8 const& image) const; template void jpeg_saver::operator() (image_view_gray16 const& image) const; template void jpeg_saver::operator() (image_view_gray32f const& image) const; diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 78ced0e0a..41c293a1d 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -308,15 +308,15 @@ void png_saver_pal::operator() (T const& image) const #endif } -template void png_saver::operator() (image_data_gray8 const& image) const; -template void png_saver::operator() (image_data_gray16 const& image) const; -template void png_saver::operator() (image_data_gray32f const& image) const; +template void png_saver::operator() (image_gray8 const& image) const; +template void png_saver::operator() (image_gray16 const& image) const; +template void png_saver::operator() (image_gray32f const& image) const; template void png_saver::operator() (image_view_gray8 const& image) const; template void png_saver::operator() (image_view_gray16 const& image) const; template void png_saver::operator() (image_view_gray32f const& image) const; -template void png_saver_pal::operator() (image_data_gray8 const& image) const; -template void png_saver_pal::operator() (image_data_gray16 const& image) const; -template void png_saver_pal::operator() (image_data_gray32f const& image) const; +template void png_saver_pal::operator() (image_gray8 const& image) const; +template void png_saver_pal::operator() (image_gray16 const& image) const; +template void png_saver_pal::operator() (image_gray32f const& image) const; template void png_saver_pal::operator() (image_view_gray8 const& image) const; template void png_saver_pal::operator() (image_view_gray16 const& image) const; template void png_saver_pal::operator() (image_view_gray32f const& image) const; diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index 3da0136bf..75935f599 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -182,9 +182,9 @@ void tiff_saver::operator() (T const& image) const } template void tiff_saver::operator() (image_rgba8 const& image) const; -template void tiff_saver::operator() (image_data_gray8 const& image) const; -template void tiff_saver::operator() (image_data_gray16 const& image) const; -template void tiff_saver::operator() (image_data_gray32f const& image) const; +template void tiff_saver::operator() (image_gray8 const& image) const; +template void tiff_saver::operator() (image_gray16 const& image) const; +template void tiff_saver::operator() (image_gray32f const& image) const; template void tiff_saver::operator() (image_view_rgba8 const& image) const; template void tiff_saver::operator() (image_view_gray8 const& image) const; template void tiff_saver::operator() (image_view_gray16 const& image) const; diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index 96b82bf82..a46a4954c 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -378,9 +378,9 @@ void webp_saver::operator() (T const& image) const } template void webp_saver::operator() (image_rgba8 const& image) const; -template void webp_saver::operator() (image_data_gray8 const& image) const; -template void webp_saver::operator() (image_data_gray16 const& image) const; -template void webp_saver::operator() (image_data_gray32f const& image) const; +template void webp_saver::operator() (image_gray8 const& image) const; +template void webp_saver::operator() (image_gray16 const& image) const; +template void webp_saver::operator() (image_gray32f const& image) const; template void webp_saver::operator() (image_view_rgba8 const& image) const; template void webp_saver::operator() (image_view_gray8 const& image) const; template void webp_saver::operator() (image_view_gray16 const& image) const; diff --git a/src/miniz_png.cpp b/src/miniz_png.cpp index b4ee851de..cae070435 100644 --- a/src/miniz_png.cpp +++ b/src/miniz_png.cpp @@ -361,7 +361,7 @@ const mz_uint8 PNGWriter::IEND_tpl[] = { 'I', 'E', 'N', 'D' // "IEND" }; -template void PNGWriter::writeIDAT(image_data_gray8 const& image); +template void PNGWriter::writeIDAT(image_gray8 const& image); template void PNGWriter::writeIDAT(image_view_gray8 const& image); template void PNGWriter::writeIDAT(image_rgba8 const& image); template void PNGWriter::writeIDAT(image_view_rgba8 const& image); diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index f3bf48ea0..21f5a0b91 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -286,13 +286,13 @@ unsigned raster_colorizer::get_color(float value) const } -template void raster_colorizer::colorize(image_rgba8 & out, image_data_gray8 const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_gray8 const& in, boost::optionalconst& nodata, feature_impl const& f) const; -template void raster_colorizer::colorize(image_rgba8 & out, image_data_gray16 const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_gray16 const& in, boost::optionalconst& nodata, feature_impl const& f) const; -template void raster_colorizer::colorize(image_rgba8 & out, image_data_gray32f const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_gray32f const& in, boost::optionalconst& nodata, feature_impl const& f) const; diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index c41abba7c..2c19d63f7 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -50,7 +50,7 @@ raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 {} template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_data_gray8 & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_gray8 & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -60,7 +60,7 @@ raster_marker_render_thunk::raster_marker_render_thunk(image_d {} template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_data_gray16 & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_gray16 & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -70,7 +70,7 @@ raster_marker_render_thunk::raster_marker_render_thunk(image_ {} template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_data_gray32f & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_gray32f & src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index 4263882d9..6ad5e7ca4 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -81,7 +81,7 @@ std::shared_ptr render_pattern(rasterizer & ra } /* template <> -std::shared_ptr render_pattern(rasterizer & ras, +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity) @@ -97,7 +97,7 @@ std::shared_ptr render_pattern(rasterizer & mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); mtx = tr * mtx; - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width()); pixfmt pixf(buf); renderer_base renb(pixf); @@ -115,7 +115,7 @@ std::shared_ptr render_pattern(rasterizer & } template <> -std::shared_ptr render_pattern(rasterizer & ras, +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity) @@ -131,7 +131,7 @@ std::shared_ptr render_pattern(rasterizer mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); mtx = tr * mtx; - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 2); pixfmt pixf(buf); renderer_base renb(pixf); @@ -149,7 +149,7 @@ std::shared_ptr render_pattern(rasterizer } template <> -std::shared_ptr render_pattern(rasterizer & ras, +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity) @@ -165,7 +165,7 @@ std::shared_ptr render_pattern(rasterize mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); mtx = tr * mtx; - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); + std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4); pixfmt pixf(buf); renderer_base renb(pixf); diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index eefc1d98b..a3dade629 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -495,15 +495,15 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne { case 8: { - return read_any_gray(x0, y0, width, height); + return read_any_gray(x0, y0, width, height); } case 16: { - return read_any_gray(x0, y0, width, height); + return read_any_gray(x0, y0, width, height); } case 32: { - return read_any_gray(x0, y0, width, height); + return read_any_gray(x0, y0, width, height); } } } diff --git a/src/warp.cpp b/src/warp.cpp index 431263c17..a6a350685 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -213,13 +213,13 @@ void reproject_and_scale_raster(raster & target, raster const& source, template MAPNIK_DECL void warp_image (image_rgba8&, image_rgba8 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); -template MAPNIK_DECL void warp_image (image_data_gray8&, image_data_gray8 const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_gray8&, image_gray8 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); -template MAPNIK_DECL void warp_image (image_data_gray16&, image_data_gray16 const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_gray16&, image_gray16 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); -template MAPNIK_DECL void warp_image (image_data_gray32f&, image_data_gray32f const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_gray32f&, image_gray32f const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index 1a352aae0..da3b6c073 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -185,7 +185,7 @@ SECTION("gray8 striped") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -201,7 +201,7 @@ SECTION("gray8 tiled") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -217,7 +217,7 @@ SECTION("gray16 striped") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -233,7 +233,7 @@ SECTION("gray16 tiled") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -249,7 +249,7 @@ SECTION("gray32f striped") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL @@ -265,7 +265,7 @@ SECTION("gray32f tiled") { REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); TIFF_ASSERT_NO_ALPHA( data ); TIFF_READ_ONE_PIXEL From e353225772e23de6c8b9d90f64bde0772f817b49 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 22 Jan 2015 10:58:01 -0600 Subject: [PATCH 54/91] Modified the name of image_data_null to image_null. --- include/mapnik/image_any.hpp | 6 +++--- include/mapnik/image_data.hpp | 2 +- .../mapnik/renderer_common/process_raster_symbolizer.hpp | 4 ++-- include/mapnik/tiff_io.hpp | 2 +- src/image_util.cpp | 6 +++--- src/image_util_jpeg.cpp | 2 +- src/image_util_png.cpp | 4 ++-- src/image_util_tiff.cpp | 2 +- src/image_util_webp.cpp | 2 +- src/marker_cache.cpp | 2 +- src/renderer_common/process_group_symbolizer.cpp | 2 +- src/renderer_common/render_pattern.cpp | 4 ++-- src/warp.cpp | 2 +- 13 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index 054c57fc0..92f17d98e 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -28,7 +28,7 @@ namespace mapnik { -struct image_data_null +struct image_null { using pixel_type = uint8_t; unsigned char const* getBytes() const { return nullptr; } @@ -51,7 +51,7 @@ struct image_data_null } }; -using image_data_base = util::variant ; using image_gray16 = image_data; using image_gray32f = image_data; -enum image_dtype +enum image_dtype : std::uint8_t { image_dtype_rgba8 = 0, image_dtype_gray8, diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 881393531..53b6b7362 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -69,7 +69,7 @@ struct image_data_dispatcher composite_(composite), nodata_(nodata) {} - void operator() (image_data_null const& data_in) const {} //no-op + void operator() (image_null const& data_in) const {} //no-op void operator() (image_rgba8 const& data_in) const { image_rgba8 data_out(width_, height_, true, true); @@ -135,7 +135,7 @@ struct image_data_warp_dispatcher composite_(composite), nodata_(nodata) {} - void operator() (image_data_null const& data_in) const {} //no-op + void operator() (image_null const& data_in) const {} //no-op void operator() (image_rgba8 const& data_in) const { diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 0a27ebf75..5b94cc813 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -257,7 +257,7 @@ struct tag_setter } } - inline void operator() (image_data_null const&) const + inline void operator() (image_null const&) const { // Assume this would be null type throw ImageWriterException("Could not write TIFF - Null image provided"); diff --git a/src/image_util.cpp b/src/image_util.cpp index db064a554..56091771c 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -431,7 +431,7 @@ template bool is_solid_visitor::operator() (image_view_gray16 template bool is_solid_visitor::operator() (image_view_gray32f const& data); template<> -bool is_solid_visitor::operator() (image_data_null const&) +bool is_solid_visitor::operator() (image_null const&) { return true; } @@ -921,7 +921,7 @@ void visitor_set_rectangle::operator() (image_rgba8 & dst) } template<> -void visitor_set_rectangle::operator() (image_data_null &) +void visitor_set_rectangle::operator() (image_null &) { throw std::runtime_error("Set rectangle not support for null images"); } @@ -1250,7 +1250,7 @@ struct visitor_create_view }; template <> -image_view_any visitor_create_view::operator() (image_data_null const&) +image_view_any visitor_create_view::operator() (image_null const&) { throw std::runtime_error("Can not make a view from a null image"); } diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index 523f73b06..693fe96c6 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -77,7 +77,7 @@ void jpeg_saver::operator() (image_view_rgba8 const& image) co } template<> -void jpeg_saver::operator() (image_data_null const& image) const +void jpeg_saver::operator() (image_null const& image) const { throw ImageWriterException("Can not save a null image to jpeg"); } diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 41c293a1d..ed38c828d 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -184,13 +184,13 @@ png_saver_pal::png_saver_pal(std::ostream & stream, std::string const& t, rgba_p stream_(stream), t_(t), pal_(pal) {} template<> -void png_saver::operator() (image_data_null const& image) const +void png_saver::operator() (image_null const& image) const { throw ImageWriterException("null images not supported for png"); } template<> -void png_saver_pal::operator() (image_data_null const& image) const +void png_saver_pal::operator() (image_null const& image) const { throw ImageWriterException("null images not supported for png"); } diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index 75935f599..29ec07565 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -164,7 +164,7 @@ void handle_tiff_options(std::string const& type, tiff_saver::tiff_saver(std::ostream & stream, std::string const& t): stream_(stream), t_(t) {} template<> -void tiff_saver::operator() (image_data_null const& image) const +void tiff_saver::operator() (image_null const& image) const { throw ImageWriterException("null images not supported"); } diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index a46a4954c..34ec6ea72 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -335,7 +335,7 @@ webp_saver::webp_saver(std::ostream & stream, std::string const& t): stream_(stream), t_(t) {} template<> -void webp_saver::operator() (image_data_null const& image) const +void webp_saver::operator() (image_null const& image) const { throw ImageWriterException("null images not supported"); } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 63b27f1d7..897fab04a 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -143,7 +143,7 @@ marker_ptr visitor_create_marker::operator() (image_rgba8 & data) } template<> -marker_ptr visitor_create_marker::operator() (image_data_null & data) +marker_ptr visitor_create_marker::operator() (image_null & data) { throw std::runtime_error("Can not make marker from null image data type"); } diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index 2c19d63f7..ac00db020 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -154,7 +154,7 @@ struct visitor_push_thunk }; template <> -void visitor_push_thunk::operator() (image_data_null &) +void visitor_push_thunk::operator() (image_null &) { throw std::runtime_error("Push thunk does not support null images"); } diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index 6ad5e7ca4..8fc1ac5c2 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -72,12 +72,12 @@ std::shared_ptr render_pattern(rasterizer & ras, } template <> -std::shared_ptr render_pattern(rasterizer & ras, +std::shared_ptr render_pattern(rasterizer & ras, marker const& marker, agg::trans_affine const& tr, double opacity) { - throw std::runtime_error("Can not return image_data_null type from render pattern"); + throw std::runtime_error("Can not return image_null type from render pattern"); } /* template <> diff --git a/src/warp.cpp b/src/warp.cpp index a6a350685..89390e6a2 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -172,7 +172,7 @@ struct warp_image_visitor scaling_method_(scaling_method), filter_factor_(filter_factor) {} - void operator() (image_data_null const&) {} + void operator() (image_null const&) {} template void operator() (T const& source) From 51172c8fdfdf6432a204758fc916dac228c7a2b6 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 22 Jan 2015 11:39:37 -0600 Subject: [PATCH 55/91] Move image_data.hpp to image.hpp and renamed most everything from image_data to image alone. This might lead to the need to clean up some variables that are currently named image through out the code at some time, but I think in the long term is much better as image is a better name for the base class. --- benchmark/compare_images.hpp | 2 +- bindings/python/mapnik_image_view.cpp | 2 +- include/mapnik/agg_pattern_source.hpp | 2 +- include/mapnik/agg_renderer.hpp | 2 +- include/mapnik/cairo/cairo_context.hpp | 2 +- include/mapnik/cairo/cairo_image_util.hpp | 2 +- include/mapnik/grid/grid.hpp | 4 +-- include/mapnik/grid/grid_view.hpp | 4 +-- include/mapnik/{image_data.hpp => image.hpp} | 20 +++++++------- include/mapnik/image_any.hpp | 16 ++++++------ include/mapnik/image_compositing.hpp | 2 +- include/mapnik/image_scaling.hpp | 2 +- include/mapnik/image_util.hpp | 2 +- include/mapnik/marker.hpp | 2 +- include/mapnik/miniz_png.hpp | 2 +- include/mapnik/png_io.hpp | 2 +- include/mapnik/raster_colorizer.hpp | 2 +- .../process_raster_symbolizer.hpp | 20 +++++++------- .../mapnik/renderer_common/render_pattern.hpp | 2 +- include/mapnik/tiff_io.hpp | 8 +++--- include/mapnik/webp_io.hpp | 24 ++++++++--------- plugins/input/gdal/gdal_featureset.cpp | 2 +- .../input/pgraster/pgraster_featureset.cpp | 2 +- .../input/pgraster/pgraster_wkb_reader.cpp | 14 +++++----- plugins/input/raster/raster_featureset.cpp | 2 +- .../rasterlite/rasterlite_featureset.cpp | 6 ++--- src/agg/process_dot_symbolizer.cpp | 2 +- src/agg/process_group_symbolizer.cpp | 2 +- src/agg/process_raster_symbolizer.cpp | 2 +- src/image_compositing.cpp | 8 +++--- src/image_convert.cpp | 2 +- src/image_scaling.cpp | 18 ++++++------- src/image_util.cpp | 2 +- src/image_util_jpeg.cpp | 2 +- src/image_util_png.cpp | 2 +- src/image_util_tiff.cpp | 2 +- src/image_util_webp.cpp | 2 +- src/miniz_png.cpp | 2 +- src/raster_colorizer.cpp | 4 +-- src/tiff_reader.cpp | 14 +++++----- src/warp.cpp | 26 +++++++++---------- tests/cpp_tests/image_io_test.cpp | 2 +- tests/cpp_tests/map_request_test.cpp | 2 +- 43 files changed, 122 insertions(+), 122 deletions(-) rename include/mapnik/{image_data.hpp => image.hpp} (93%) diff --git a/benchmark/compare_images.hpp b/benchmark/compare_images.hpp index 80dd7e929..2f1f124c4 100644 --- a/benchmark/compare_images.hpp +++ b/benchmark/compare_images.hpp @@ -2,7 +2,7 @@ #define __MAPNIK_COMPARE_IMAGES_HPP__ #include -#include +#include #include #include diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index bac81b918..1c48bd33b 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -35,7 +35,7 @@ #pragma GCC diagnostic pop // mapnik -#include +#include #include #include #include diff --git a/include/mapnik/agg_pattern_source.hpp b/include/mapnik/agg_pattern_source.hpp index 534d3f671..1c5673950 100644 --- a/include/mapnik/agg_pattern_source.hpp +++ b/include/mapnik/agg_pattern_source.hpp @@ -24,7 +24,7 @@ #define MAPNIK_AGG_PATTERN_SOURCE_HPP // mapnik -#include +#include #include // agg diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 392aa95b7..9052b7600 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include // stl #include diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index 44d16db17..a5826bdc9 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -27,7 +27,7 @@ // mapnik #include #include -#include +#include #include #include #include diff --git a/include/mapnik/cairo/cairo_image_util.hpp b/include/mapnik/cairo/cairo_image_util.hpp index 2a520bfc2..f4a5a3dcd 100644 --- a/include/mapnik/cairo/cairo_image_util.hpp +++ b/include/mapnik/cairo/cairo_image_util.hpp @@ -25,7 +25,7 @@ #define MAPNIK_CAIRO_IMAGE_UTIL_HPP // mapnik -#include +#include #include // for cairo_surface_ptr // stl diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index e1ce21899..2aa423854 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include #include #include #include @@ -50,7 +50,7 @@ class MAPNIK_DECL hit_grid { public: using value_type = T; - using data_type = mapnik::image_data; + using data_type = mapnik::image; using lookup_type = std::string; // mapping between pixel id and key using feature_key_type = std::map; diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index e43633e97..2db982e5c 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -23,7 +23,7 @@ #ifndef MAPNIK_GRID_VIEW_HPP #define MAPNIK_GRID_VIEW_HPP -#include +#include #include #include #include @@ -196,7 +196,7 @@ private: feature_type const& features_; }; -using grid_view = hit_grid_view >; +using grid_view = hit_grid_view >; } diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image.hpp similarity index 93% rename from include/mapnik/image_data.hpp rename to include/mapnik/image.hpp index d36d8f9bd..fe2b2e8c0 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image.hpp @@ -116,13 +116,13 @@ struct image_dimensions } template -class image_data +class image { public: using pixel_type = T; static constexpr std::size_t pixel_size = sizeof(pixel_type); - image_data(int width, int height, bool initialize = true, bool premultiplied = false, bool painted = false) + image(int width, int height, bool initialize = true, bool premultiplied = false, bool painted = false) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), pData_(reinterpret_cast(buffer_.data())), @@ -132,7 +132,7 @@ public: if (pData_ && initialize) std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), 0); } - image_data(image_data const& rhs) + image(image const& rhs) : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), pData_(reinterpret_cast(buffer_.data())), @@ -140,7 +140,7 @@ public: painted_(rhs.painted_) {} - image_data(image_data && rhs) noexcept + image(image && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), buffer_(std::move(rhs.buffer_)), pData_(reinterpret_cast(buffer_.data())), @@ -151,13 +151,13 @@ public: rhs.pData_ = nullptr; } - image_data& operator=(image_data rhs) + image& operator=(image rhs) { swap(rhs); return *this; } - void swap(image_data & rhs) + void swap(image & rhs) { std::swap(dimensions_, rhs.dimensions_); std::swap(buffer_, rhs.buffer_); @@ -277,10 +277,10 @@ private: bool painted_; }; -using image_rgba8 = image_data; -using image_gray8 = image_data ; -using image_gray16 = image_data; -using image_gray32f = image_data; +using image_rgba8 = image; +using image_gray8 = image ; +using image_gray16 = image; +using image_gray32f = image; enum image_dtype : std::uint8_t { diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index 92f17d98e..fc764f6ed 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -23,7 +23,7 @@ #ifndef MAPNIK_IMAGE_DATA_ANY_HPP #define MAPNIK_IMAGE_DATA_ANY_HPP -#include +#include #include namespace mapnik { @@ -40,18 +40,18 @@ struct image_null bool painted() const { return false; } bool get_premultiplied() const { return false; } void set_premultiplied(bool) const {} - void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image_data"); } + void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image"); } pixel_type& operator() (std::size_t, std::size_t) { - throw std::runtime_error("Can not set or get values for null image_data"); + throw std::runtime_error("Can not set or get values for null image"); } pixel_type const& operator() (std::size_t, std::size_t) const { - throw std::runtime_error("Can not set or get values for null image_data"); + throw std::runtime_error("Can not set or get values for null image"); } }; -using image_data_base = util::variant image_any(T && data) noexcept - : image_data_base(std::move(data)) {} + : image_base(std::move(data)) {} unsigned char const* getBytes() const { diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index b41d14b2b..c3fce8be7 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -24,7 +24,7 @@ #define MAPNIK_IMAGE_COMPOSITING_HPP #include -#include +#include // boost #include diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp index c8c916fa6..0dd94c9a6 100644 --- a/include/mapnik/image_scaling.hpp +++ b/include/mapnik/image_scaling.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include // stl #include diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 25c36afd1..58f976e26 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include #include #include #include diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index f74ac2481..ea03e9607 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -24,7 +24,7 @@ #define MAPNIK_MARKER_HPP // mapnik -#include +#include #include #include #include diff --git a/include/mapnik/miniz_png.hpp b/include/mapnik/miniz_png.hpp index 9d36f3bbc..0414c329c 100644 --- a/include/mapnik/miniz_png.hpp +++ b/include/mapnik/miniz_png.hpp @@ -32,7 +32,7 @@ #include #include -#include +#include #include /* miniz.c porting issues: diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 0aa3afc01..8eced2442 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include // zlib #include // for Z_DEFAULT_COMPRESSION diff --git a/include/mapnik/raster_colorizer.hpp b/include/mapnik/raster_colorizer.hpp index f565597c7..63e2d0727 100644 --- a/include/mapnik/raster_colorizer.hpp +++ b/include/mapnik/raster_colorizer.hpp @@ -40,7 +40,7 @@ #include #include #include -#include +#include // boost #include // boost diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 53b6b7362..3ef8b19cb 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -45,10 +45,10 @@ namespace mapnik { namespace detail { template -struct image_data_dispatcher +struct image_dispatcher { using composite_function = F; - image_data_dispatcher(int start_x, int start_y, + image_dispatcher(int start_x, int start_y, int width, int height, double scale_x, double scale_y, scaling_method_e method, double filter_factor, @@ -80,8 +80,8 @@ struct image_data_dispatcher template void operator() (T const& data_in) const { - using image_data_type = T; - image_data_type data_out(width_, height_); + using image_type = T; + image_type data_out(width_, height_); scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_); image_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); @@ -107,10 +107,10 @@ private: }; template -struct image_data_warp_dispatcher +struct image_warp_dispatcher { using composite_function = F; - image_data_warp_dispatcher(proj_transform const& prj_trans, + image_warp_dispatcher(proj_transform const& prj_trans, int start_x, int start_y, int width, int height, box2d const& target_ext, box2d const& source_ext, double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, @@ -147,8 +147,8 @@ struct image_data_warp_dispatcher template void operator() (T const& data_in) const { - using image_data_type = T; - image_data_type data_out(width_, height_); + using image_type = T; + image_type data_out(width_, height_); if (nodata_) data_out.set(*nodata_); warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); image_rgba8 dst(width_, height_); @@ -220,7 +220,7 @@ void render_raster_symbolizer(raster_symbolizer const& sym, double offset_x = ext.minx() - start_x; double offset_y = ext.miny() - start_y; unsigned mesh_size = static_cast(get(sym,keys::mesh_size,feature, common.vars_, 16)); - detail::image_data_warp_dispatcher dispatcher(prj_trans, start_x, start_y, raster_width, raster_height, + detail::image_warp_dispatcher dispatcher(prj_trans, start_x, start_y, raster_width, raster_height, target_ext, source->ext_, offset_x, offset_y, mesh_size, scaling_method, source->get_filter_factor(), opacity, comp_op, sym, feature, composite, source->nodata()); @@ -243,7 +243,7 @@ void render_raster_symbolizer(raster_symbolizer const& sym, } else { - detail::image_data_dispatcher dispatcher(start_x, start_y, raster_width, raster_height, + detail::image_dispatcher dispatcher(start_x, start_y, raster_width, raster_height, image_ratio_x, image_ratio_y, scaling_method, source->get_filter_factor(), opacity, comp_op, sym, feature, composite, source->nodata()); diff --git a/include/mapnik/renderer_common/render_pattern.hpp b/include/mapnik/renderer_common/render_pattern.hpp index 6173bfd58..4cbf211c5 100644 --- a/include/mapnik/renderer_common/render_pattern.hpp +++ b/include/mapnik/renderer_common/render_pattern.hpp @@ -23,7 +23,7 @@ #ifndef MAPNIK_RENDER_PATTERN_HPP #define MAPNIK_RENDER_PATTERN_HPP -#include +#include #include // fwd decl diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 5b94cc813..dd8377f4f 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -387,7 +387,7 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) TIFFSetField(output, TIFFTAG_TILELENGTH, tile_height); TIFFSetField(output, TIFFTAG_TILEDEPTH, 1); std::size_t tile_size = tile_width * tile_height; - std::unique_ptr image_data_out (new pixel_type[tile_size]); + std::unique_ptr image_out (new pixel_type[tile_size]); int end_y = (height / tile_height + 1) * tile_height; int end_x = (width / tile_width + 1) * tile_width; end_y = std::min(end_y, height); @@ -400,14 +400,14 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) for (int x = 0; x < end_x; x += tile_width) { // Prefill the entire array with zeros. - std::fill(image_data_out.get(), image_data_out.get() + tile_size, 0); + std::fill(image_out.get(), image_out.get() + tile_size, 0); int tx1 = std::min(width, x + tile_width); int row = y; for (int ty = 0; ty < ty1; ++ty, ++row) { - std::copy(image.getRow(row, x), image.getRow(row, tx1), image_data_out.get() + ty * tile_width); + std::copy(image.getRow(row, x), image.getRow(row, tx1), image_out.get() + ty * tile_width); } - if (TIFFWriteEncodedTile(output, TIFFComputeTile(output, x, y, 0, 0), image_data_out.get(), tile_size * sizeof(pixel_type)) == -1) + if (TIFFWriteEncodedTile(output, TIFFComputeTile(output, x, y, 0, 0), image_out.get(), tile_size * sizeof(pixel_type)) == -1) { throw ImageWriterException("Could not write TIFF - TIFF Tile Write failed"); } diff --git a/include/mapnik/webp_io.hpp b/include/mapnik/webp_io.hpp index 2ec6c52c8..a65792f55 100644 --- a/include/mapnik/webp_io.hpp +++ b/include/mapnik/webp_io.hpp @@ -24,7 +24,7 @@ #define MAPNIK_WEBP_IO_HPP // mapnik -#include +#include #include // webp @@ -73,14 +73,14 @@ std::string webp_encoding_error(WebPEncodingError error) } template -inline int import_image_data(T2 const& image, +inline int import_image(T2 const& im_in, WebPPicture & pic, bool alpha) { - image_data const& data = image.data(); - int stride = sizeof(typename T2::pixel_type) * image.width(); - if (data.width() == image.width() && - data.height() == image.height()) + image const& data = im_in.data(); + int stride = sizeof(typename T2::pixel_type) * im_in.width(); + if (data.width() == im_in.width() && + data.height() == im_in.height()) { if (alpha) { @@ -98,10 +98,10 @@ inline int import_image_data(T2 const& image, else { // need to copy: https://github.com/mapnik/mapnik/issues/2024 - image_rgba8 im(image.width(),image.height()); - for (unsigned y = 0; y < image.height(); ++y) + image_rgba8 im(im_in.width(),im_in.height()); + for (unsigned y = 0; y < im_in.height(); ++y) { - typename T2::pixel_type const * row_from = image.getRow(y); + typename T2::pixel_type const * row_from = im_in.getRow(y); image_rgba8::pixel_type * row_to = im.getRow(y); std::copy(row_from, row_from + stride, row_to); } @@ -121,7 +121,7 @@ inline int import_image_data(T2 const& image, } template <> -inline int import_image_data(image_rgba8 const& im, +inline int import_image(image_rgba8 const& im, WebPPicture & pic, bool alpha) { @@ -187,10 +187,10 @@ void save_as_webp(T1& file, { // different approach for lossy since ImportYUVAFromRGBA is needed // to prepare WebPPicture and working with view pixels is not viable - ok = import_image_data(image,pic,alpha); + ok = import_image(image,pic,alpha); } #else - ok = import_image_data(image,pic,alpha); + ok = import_image(image,pic,alpha); #endif if (!ok) { diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 3d889215c..55f8e0f65 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/plugins/input/pgraster/pgraster_featureset.cpp b/plugins/input/pgraster/pgraster_featureset.cpp index 497652561..20900cfe5 100644 --- a/plugins/input/pgraster/pgraster_featureset.cpp +++ b/plugins/input/pgraster/pgraster_featureset.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include // for int2net diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp index 11e19d2c4..076ead40b 100644 --- a/plugins/input/pgraster/pgraster_wkb_reader.cpp +++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include // for box2d @@ -279,7 +279,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d const& bbox, int val; uint8_t * data = image.getBytes(); - int ps = 4; // sizeof(image_data::pixel_type) + int ps = 4; // sizeof(image::pixel_type) int off; val = reader(); // nodata value, need to read anyway for (int y=0; y con mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d const& bbox, uint16_t width, uint16_t height) { - mapnik::image_rgba8 image(width, height, true, true); + mapnik::image_rgba8 im(width, height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) - image.set(0xffffffff); + im.set(0xffffffff); uint8_t nodataval; for (int bn=0; bn const& b << " nodataval " << tmp << " != band 0 nodataval " << nodataval; } - int ps = 4; // sizeof(image_data::pixel_type) - uint8_t * image_data = image.getBytes(); + int ps = 4; // sizeof(image::pixel_type) + uint8_t * image_data = im.getBytes(); for (int y=0; y const& b } } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); + mapnik::raster_ptr raster = std::make_shared(bbox, im, 1.0); raster->set_nodata(0xffffffff); return raster; } diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index c6a1f630a..4bf95571e 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include #include #include diff --git a/plugins/input/rasterlite/rasterlite_featureset.cpp b/plugins/input/rasterlite/rasterlite_featureset.cpp index 7171eabdf..a532a7d93 100644 --- a/plugins/input/rasterlite/rasterlite_featureset.cpp +++ b/plugins/input/rasterlite/rasterlite_featureset.cpp @@ -24,7 +24,7 @@ // mapnik #include -#include +#include #include #include #include @@ -116,8 +116,8 @@ feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q) { mapnik::image_rgba8 image(width,height); unsigned char* raster_data = static_cast(raster); - unsigned char* image_data = image.getBytes(); - std::memcpy(image_data, raster_data, size); + unsigned char* image = image.getBytes(); + std::memcpy(image, raster_data, size); feature->set_raster(std::make_shared(intersect, std::move(image), 1.0)); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Done"; } diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index ad052a79e..7838a920b 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index bd7db6c05..f1ae6a30b 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index f51c3d0d1..7d5cd4b93 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index ea7a8a3d4..ea4908d71 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include // boost @@ -129,8 +129,8 @@ namespace detail { template struct rendering_buffer { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; using row_data = agg::const_row_info; rendering_buffer(T const& data) @@ -143,7 +143,7 @@ struct rendering_buffer 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_; + image_type const& data_; }; } // end detail ns diff --git a/src/image_convert.cpp b/src/image_convert.cpp index 3a99383c9..40a9dbad9 100644 --- a/src/image_convert.cpp +++ b/src/image_convert.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include namespace mapnik diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index 24ea59ffc..76bf931d3 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -21,7 +21,7 @@ *****************************************************************************/ // mapnik -#include +#include #include #include // does not handle alpha correctly @@ -107,12 +107,12 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho // 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 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 image_type = T; + using pixel_type = typename image_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; constexpr std::size_t pixel_size = sizeof(pixel_type); @@ -150,13 +150,13 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho if (scaling_method == SCALING_NEAR) { - using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; + 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); } else { - using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; + using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; agg::image_filter_lut filter; detail::set_scaling_method(filter, scaling_method, filter_factor); span_gen_type sg(img_src, interpolator, filter); diff --git a/src/image_util.cpp b/src/image_util.cpp index 56091771c..2b143f052 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index 693fe96c6..c689dd856 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index ed38c828d..691e7607f 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -34,7 +34,7 @@ extern "C" #include #include -#include +#include #include #include #include diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index 29ec07565..ffd4ecf64 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index 34ec6ea72..aa9bb2d93 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/miniz_png.cpp b/src/miniz_png.cpp index cae070435..3a32d50f3 100644 --- a/src/miniz_png.cpp +++ b/src/miniz_png.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include // miniz diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index 21f5a0b91..27682f3c3 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -127,8 +127,8 @@ void raster_colorizer::colorize(image_rgba8 & out, T const& in, boost::optional const& nodata, feature_impl const& f) const { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; // TODO: assuming in/out have the same width/height for now std::uint32_t * out_data = out.getData(); pixel_type const* in_data = in.getData(); diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index a3dade629..62c566aeb 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -397,12 +397,12 @@ template template image_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height) { - using image_data_type = ImageData; - using pixel_type = typename image_data_type::pixel_type; + using image_type = ImageData; + using pixel_type = typename image_type::pixel_type; if (read_method_ == tiled) { - image_data_type data(width,height); - read_tiled(x0, y0, data); + image_type data(width,height); + read_tiled(x0, y0, data); return image_any(std::move(data)); } else @@ -410,7 +410,7 @@ image_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned width TIFF* tif = open(stream_); if (tif) { - image_data_type data(width, height); + image_type data(width, height); std::size_t block_size = rows_per_strip_ > 0 ? rows_per_strip_ : tile_height_ ; std::ptrdiff_t start_y = y0 - y0 % block_size; std::ptrdiff_t end_y = std::min(y0 + height, static_cast(height_)); @@ -454,8 +454,8 @@ struct rgb8_to_rgba8 template struct tiff_reader_traits { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; static bool read_tile(TIFF * tif, unsigned x, unsigned y, pixel_type* buf, std::size_t tile_width, std::size_t tile_height) { return (TIFFReadEncodedTile(tif, TIFFComputeTile(tif, x,y,0,0), buf, tile_width * tile_height * sizeof(pixel_type)) != -1); diff --git a/src/warp.cpp b/src/warp.cpp index 89390e6a2..85730303f 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include @@ -53,12 +53,12 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& box2d const& target_ext, box2d const& source_ext, double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor) { - 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 image_type = T; + using pixel_type = typename image_type::pixel_type; + using pixfmt_pre = typename detail::agg_scaling_traits::pixfmt_pre; + using color_type = typename detail::agg_scaling_traits::color_type; using renderer_base = agg::renderer_base; - using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; + using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; constexpr std::size_t pixel_size = sizeof(pixel_type); @@ -70,8 +70,8 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& std::size_t mesh_nx = std::ceil(source.width()/double(mesh_size) + 1); std::size_t mesh_ny = std::ceil(source.height()/double(mesh_size) + 1); - image_data xs(mesh_nx, mesh_ny); - image_data ys(mesh_nx, mesh_ny); + image xs(mesh_nx, mesh_ny); + image ys(mesh_nx, mesh_ny); // Precalculate reprojected mesh for(std::size_t j = 0; j < mesh_ny; ++j) @@ -138,13 +138,13 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& interpolator_type interpolator(tr); if (scaling_method == SCALING_NEAR) { - using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; + using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; span_gen_type sg(ia, interpolator); agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg); } else { - using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; + using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; agg::image_filter_lut filter; detail::set_scaling_method(filter, scaling_method, filter_factor); span_gen_type sg(ia, interpolator, filter); @@ -177,11 +177,11 @@ struct warp_image_visitor template void operator() (T const& source) { - using image_data_type = T; + using image_type = T; //source and target image data types must match - if (target_raster_.data_.template is()) + if (target_raster_.data_.template is()) { - image_data_type & target = util::get(target_raster_.data_); + image_type & target = util::get(target_raster_.data_); warp_image (target, source, prj_trans_, target_raster_.ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); } diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index 7cc037862..1ea4008cf 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include diff --git a/tests/cpp_tests/map_request_test.cpp b/tests/cpp_tests/map_request_test.cpp index 194f2a9b7..45e9ec411 100644 --- a/tests/cpp_tests/map_request_test.cpp +++ b/tests/cpp_tests/map_request_test.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include From faddf1a615719fbf5c7bd2c97bb70ed7040d08cd Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 22 Jan 2015 15:59:01 -0800 Subject: [PATCH 56/91] fix compile of rasterlite plugin --- plugins/input/rasterlite/rasterlite_featureset.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/input/rasterlite/rasterlite_featureset.cpp b/plugins/input/rasterlite/rasterlite_featureset.cpp index a532a7d93..c47294b8b 100644 --- a/plugins/input/rasterlite/rasterlite_featureset.cpp +++ b/plugins/input/rasterlite/rasterlite_featureset.cpp @@ -116,8 +116,7 @@ feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q) { mapnik::image_rgba8 image(width,height); unsigned char* raster_data = static_cast(raster); - unsigned char* image = image.getBytes(); - std::memcpy(image, raster_data, size); + std::memcpy(image.getBytes(), raster_data, size); feature->set_raster(std::make_shared(intersect, std::move(image), 1.0)); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Done"; } From 490645d2e302c5a3fdb5411a7e6a50be663be74f Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 22 Jan 2015 20:36:45 -0600 Subject: [PATCH 57/91] Perhaps a solution to TIFF IO problems --- bindings/python/mapnik_image.cpp | 13 +++++++- include/mapnik/tiff_io.hpp | 9 ++++-- src/image_util.cpp | 26 +++++++++++++++ src/tiff_reader.cpp | 27 ++++++++++------ tests/python_tests/image_tiff_test.py | 46 +++++++++++++++------------ 5 files changed, 86 insertions(+), 35 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 65456600c..6263faf4d 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -290,7 +290,18 @@ void export_image() .value("divide", mapnik::divide) ; - class_, boost::noncopyable >("Image","This class represents a 32 bit RGBA image.",init()) + enum_("ImageType") + .value("rgba8", mapnik::image_dtype_rgba8) + .value("gray8", mapnik::image_dtype_gray8) + .value("gray16", mapnik::image_dtype_gray16) + .value("gray32f", mapnik::image_dtype_gray32f) + ; + + class_, boost::noncopyable >("Image","This class represents a image.",init()) + .def(init()) + .def(init()) + .def(init()) + .def(init()) .def("width",&image_any::width) .def("height",&image_any::height) .def("view",&get_view) diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index dd8377f4f..97d2d6a32 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -200,12 +200,14 @@ struct tag_setter TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 4); if (data.get_premultiplied()) { - uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; + //uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; + uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); } else { - uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; + //uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; + uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); } if (config_.compression == COMPRESSION_DEFLATE @@ -346,7 +348,8 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, rows_per_strip); std::size_t strip_size = width * rows_per_strip; std::unique_ptr strip_buffer(new pixel_type[strip_size]); - int end_y=(height/rows_per_strip+1)*rows_per_strip; + //int end_y=(height/rows_per_strip+1)*rows_per_strip; + int end_y=height; for (int y=0; y < end_y; y+=rows_per_strip) { diff --git a/src/image_util.cpp b/src/image_util.cpp index 2b143f052..c5239e5af 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -783,6 +783,19 @@ struct visitor_fill visitor_fill(T1 const& val) : val_(val) {} + void operator() (image_rgba8 & data) + { + using pixel_type = typename image_rgba8::pixel_type; + bool was_demultiplied = mapnik::demultiply_alpha(data); + pixel_type val = static_cast(val_); + data.set(val); + if (was_demultiplied) + { + mapnik::premultiply_alpha(data); + } + + } + template void operator() (T2 & data) { @@ -800,6 +813,19 @@ struct visitor_fill { visitor_fill(color const& val) : val_(val) {} + + void operator() (image_rgba8 & data) + { + using pixel_type = typename image_rgba8::pixel_type; + bool was_demultiplied = mapnik::demultiply_alpha(data); + pixel_type val = static_cast(val_.rgba()); + data.set(val); + if (was_demultiplied) + { + mapnik::premultiply_alpha(data); + } + + } template void operator() (T2 & data) diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 62c566aeb..9bbe6fd59 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -307,10 +307,11 @@ void tiff_reader::init() &extrasamples, &sampleinfo)) { has_alpha_ = true; + premultiplied_alpha_ = true; if (extrasamples == 1 && sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) { - premultiplied_alpha_ = true; + premultiplied_alpha_ = false; } } // Try extracting bounding box from geoTIFF tags @@ -640,31 +641,37 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_rgba8& image) int height=image.height(); unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_; - unsigned end_y=((y0+height)/rows_per_strip_+1)*rows_per_strip_; - bool laststrip=(static_cast(end_y) > height_)?true:false; + //unsigned end_y=((y0+height)/rows_per_strip_+1)*rows_per_strip_; + unsigned end_y=std::min(y0+height, static_cast(height_)); + //bool laststrip=(static_cast(end_y) > height_)?true:false; int row,tx0,tx1,ty0,ty1; + //image.set_premultiplied(true); tx0=x0; tx1=std::min(width+x0,static_cast(width_)); for (unsigned y=start_y; y < end_y; y+=rows_per_strip_) { ty0 = std::max(y0,y)-y; - ty1 = std::min(height+y0,y+rows_per_strip_)-y; + ty1 = std::min(end_y,y+rows_per_strip_)-y; if (!TIFFReadRGBAStrip(tif,y,strip.getData())) { std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; break; } - row=y+ty0-y0; + row=y+ty0; - int n0=laststrip ? 0:(rows_per_strip_-ty1); - int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1); - for (int n=n1;n>=n0;--n) + //int n0=laststrip ? 0:(rows_per_strip_-ty1); + //int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1); + //std::cout << " n0: " << n0 << " n1: " << n1 << " y: " << y << " endy: " << end_y << std::endl; + //for (int n=n1;n>=n0;--n) + //for (int n=n0;n>=n1;++n) + // This is in reverse becauase the TIFFReadRGBAStrip reads inverted? + for (int ty = ty1-1; ty >= ty0; --ty, ++row) { - image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[n*width_+tx0]); - ++row; + //std::cout << "row: " << row <<" s: " << (tx0-x0) << " e: " << (tx1-x0) << " n: " << (n*width_+tx0) << std::endl; + image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[ty*width_+tx0]); } } } diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index 036d22ff4..001d297a2 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -6,7 +6,7 @@ import os, mapnik from timeit import Timer, time from nose.tools import * from utilities import execution_path, run_all - +#mapnik.logger.set_severity(mapnik.severity_type.Debug) def setup(): # All of the paths used are relative, if we run the tests # from another directory we need to chdir() @@ -15,7 +15,7 @@ def setup(): def test_tiff_round_trip_scanline(): filepath = '/tmp/mapnik-tiff-io-scanline.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.background(mapnik.Color('rgba(12,255,128,.5)')) org_str = len(im.tostring()) im.save(filepath,'tiff:method=scanline') im2 = mapnik.Image.open(filepath) @@ -33,10 +33,11 @@ def test_tiff_round_trip_scanline(): def test_tiff_round_trip_stripped(): filepath = '/tmp/mapnik-tiff-io-stripped.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.background(mapnik.Color('rgba(12,255,128,.5)')) org_str = len(im.tostring()) im.save(filepath,'tiff:method=stripped') im2 = mapnik.Image.open(filepath) + im2.save('/tmp/mapnik-tiff-io-stripped2.tiff','tiff:method=stripped') im3 = mapnik.Image.fromstring(open(filepath,'r').read()) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) @@ -44,17 +45,20 @@ def test_tiff_round_trip_stripped(): eq_(im.height(),im3.height()) eq_(len(im.tostring()), org_str) eq_(len(im.tostring()),len(im2.tostring())) + eq_(len(im.tostring('png')),len(im2.tostring('png'))) eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) eq_(len(im.tostring()),len(im3.tostring())) eq_(len(im.tostring('tiff:method=stripped')),len(im3.tostring('tiff:method=stripped'))) def test_tiff_round_trip_rows_stripped(): - filepath = '/tmp/mapnik-tiff-io-stripped.tiff' + filepath = '/tmp/mapnik-tiff-io-rows_stripped.tiff' + filepath2 = '/tmp/mapnik-tiff-io-rows_stripped2.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.background(mapnik.Color('rgba(12,255,128,.5)')) org_str = len(im.tostring()) im.save(filepath,'tiff:method=stripped:rows_per_strip=8') im2 = mapnik.Image.open(filepath) + im2.save(filepath2,'tiff:method=stripped:rows_per_strip=8') im3 = mapnik.Image.fromstring(open(filepath,'r').read()) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) @@ -71,7 +75,7 @@ def test_tiff_round_trip_buffered_tiled(): filepath2 = '/tmp/mapnik-tiff-io-buffered-tiled2.tiff' im = mapnik.Image(255,267) #im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.background(mapnik.Color('rgba(1,255,128,.5)')) im.save(filepath,'tiff:method=tiled:tile_width=32:tile_height=32') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -91,7 +95,7 @@ def test_tiff_round_trip_buffered_tiled(): def test_tiff_round_trip_tiled(): filepath = '/tmp/mapnik-tiff-io-tiled.tiff' im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.background(mapnik.Color('rgba(1,255,128,.5)')) im.save(filepath,'tiff:method=tiled') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -109,14 +113,14 @@ def test_tiff_rgb8_compare(): filepath1 = '../data/tiff/ndvi_256x256_rgb8_striped.tif' filepath2 = '/tmp/mapnik-tiff-rgb8.tiff' im = mapnik.Image.open(filepath1) - im.save(filepath2,'tiff') + im.save(filepath2,'tiff:method=stripped:rows_per_strip=10') im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff')),len(im2.tostring('tiff'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -129,7 +133,7 @@ def test_tiff_rgba8_compare_scanline(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -142,7 +146,7 @@ def test_tiff_rgba8_compare_stripped(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -155,7 +159,7 @@ def test_tiff_rgba8_compare_tiled(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_gray8_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -168,7 +172,7 @@ def test_tiff_gray8_compare_scanline(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray8_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -181,7 +185,7 @@ def test_tiff_gray8_compare_stripped(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray8_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -194,7 +198,7 @@ def test_tiff_gray8_compare_tiled(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray16_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -207,7 +211,7 @@ def test_tiff_gray16_compare_scanline(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray16_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -220,7 +224,7 @@ def test_tiff_gray16_compare_stripped(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray16_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -233,7 +237,7 @@ def test_tiff_gray16_compare_tiled(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray32f_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -246,7 +250,7 @@ def test_tiff_gray32f_compare_scanline(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) def test_tiff_gray32f_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -259,7 +263,7 @@ def test_tiff_gray32f_compare_stripped(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) def test_tiff_gray32f_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -272,7 +276,7 @@ def test_tiff_gray32f_compare_tiled(): eq_(len(im.tostring()),len(im2.tostring())) eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) if __name__ == "__main__": setup() From a100b2fe1f30e7025caef3e418f50296534c1399 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 23 Jan 2015 18:08:59 -0600 Subject: [PATCH 58/91] Fixed the issues associated with TIFFs, now they always will return as premultiplied in the event they are rgba8 due to the way that the TIFF reader operates. Also added premultiply as a flag inside color class and exposed many of its components, made it so that setting and getting pixels took into consideration the state of the color and the image when dealing with the two. --- bindings/python/mapnik_color.cpp | 22 +++++ bindings/python/mapnik_image.cpp | 22 ++++- include/mapnik/color.hpp | 35 +++++-- include/mapnik/image_view.hpp | 9 ++ include/mapnik/tiff_io.hpp | 15 +-- src/agg/agg_renderer.cpp | 4 +- src/color.cpp | 11 ++- src/image_compositing.cpp | 1 - src/image_util.cpp | 44 ++++----- src/tiff_reader.cpp | 28 ++---- tests/cxx/tiff_io.cpp | 2 +- tests/python_tests/compositing_test.py | 2 +- tests/python_tests/image_test.py | 131 +++++++++++++++++++++++++ tests/python_tests/image_tiff_test.py | 38 ++++--- 14 files changed, 278 insertions(+), 86 deletions(-) diff --git a/bindings/python/mapnik_color.cpp b/bindings/python/mapnik_color.cpp index fc642f449..7210730c2 100644 --- a/bindings/python/mapnik_color.cpp +++ b/bindings/python/mapnik_color.cpp @@ -57,11 +57,27 @@ void export_color () "and an alpha value.\n" "All values between 0 and 255.\n") ) + .def(init( + ( arg("r"), arg("g"), arg("b"), arg("a"), arg("premultiplied") ), + "Creates a new color from its RGB components\n" + "and an alpha value.\n" + "All values between 0 and 255.\n") + ) .def(init( ( arg("r"), arg("g"), arg("b") ), "Creates a new color from its RGB components.\n" "All values between 0 and 255.\n") ) + .def(init( + ( arg("val") ), + "Creates a new color from an unsigned integer.\n" + "All values between 0 and 2^32-1\n") + ) + .def(init( + ( arg("val"), arg("premultiplied") ), + "Creates a new color from an unsigned integer.\n" + "All values between 0 and 2^32-1\n") + ) .def(init( ( arg("color_string") ), "Creates a new color from its CSS string representation.\n" @@ -93,6 +109,12 @@ void export_color () .def_pickle(color_pickle_suite()) .def("__str__",&color::to_string) .def("packed",&color::rgba) + .def("premultiply",&color::premultiply) + .def("set_premultiplied",&color::set_premultiplied) + .def("get_premultiplied",&color::get_premultiplied) + .def("premultiply",&color::premultiply) + .def("demultiply",&color::demultiply) + .def("packed",&color::rgba) .def("to_hex_string",&color::to_hex_string, "Returns the hexadecimal representation of this color.\n" "\n" diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 6263faf4d..a7142e699 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -131,9 +131,9 @@ void background(mapnik::image_any & im, mapnik::color const& c) mapnik::fill(im, c); } -uint32_t get_pixel(mapnik::image_any const& im, int x, int y) +uint32_t get_pixel(mapnik::image_any const& im, unsigned x, unsigned y) { - if (x < static_cast(im.width()) && y < static_cast(im.height())) + if (x < static_cast(im.width()) && y < static_cast(im.height())) { return mapnik::get_pixel(im, x, y); } @@ -142,8 +142,25 @@ uint32_t get_pixel(mapnik::image_any const& im, int x, int y) return 0; } +mapnik::color get_pixel_color(mapnik::image_any const& im, unsigned x, unsigned y) +{ + if (x < static_cast(im.width()) && y < static_cast(im.height())) + { + return mapnik::get_pixel(im, x, y); + } + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return 0; +} + void set_pixel(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c) { + if (x >= static_cast(im.width()) && y >= static_cast(im.height())) + { + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return; + } mapnik::set_pixel(im, x, y, c); } @@ -324,6 +341,7 @@ void export_image() .def("demultiply",&demultiply) .def("set_pixel",&set_pixel) .def("get_pixel",&get_pixel) + .def("get_pixel_color",&get_pixel_color) .def("clear",&clear) //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3 diff --git a/include/mapnik/color.hpp b/include/mapnik/color.hpp index f220ddd07..4d2eb846c 100644 --- a/include/mapnik/color.hpp +++ b/include/mapnik/color.hpp @@ -44,29 +44,39 @@ private: std::uint8_t green_; std::uint8_t blue_; std::uint8_t alpha_; - + bool premultiplied_; public: // default ctor color() : red_(0xff), green_(0xff), blue_(0xff), - alpha_(0xff) + alpha_(0xff), + premultiplied_(false) {} - color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 0xff) + color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 0xff, bool premultiplied = false) : red_(red), green_(green), blue_(blue), - alpha_(alpha) + alpha_(alpha), + premultiplied_(premultiplied) {} + color(std::uint32_t rgba, bool premultiplied = false) + : red_(rgba & 0xff), + green_((rgba >> 8) & 0xff), + blue_((rgba >> 16) & 0xff), + alpha_((rgba >> 24) & 0xff), + premultiplied_(premultiplied) {} + // copy ctor color(const color& rhs) : red_(rhs.red_), green_(rhs.green_), blue_(rhs.blue_), - alpha_(rhs.alpha_) + alpha_(rhs.alpha_), + premultiplied_(rhs.premultiplied_) {} // move ctor @@ -74,14 +84,15 @@ public: : red_(std::move(rhs.red_)), green_(std::move(rhs.green_)), blue_(std::move(rhs.blue_)), - alpha_(std::move(rhs.alpha_)) {} + alpha_(std::move(rhs.alpha_)), + premultiplied_(std::move(rhs.premultiplied_)) {} color( std::string const& str); std::string to_string() const; std::string to_hex_string() const; - void premultiply(); - void demultiply(); + bool premultiply(); + bool demultiply(); color& operator=(color rhs) { @@ -135,6 +146,14 @@ public: { alpha_ = alpha; } + inline bool get_premultiplied() const + { + return premultiplied_; + } + inline void set_premultiplied(bool status) + { + premultiplied_ = status; + } inline unsigned rgba() const { diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 0c9a45e82..2256cfbca 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -84,6 +84,10 @@ public: { return height_; } + inline const pixel_type& operator() (std::size_t i, std::size_t j) const + { + return data_(i,j); + } inline unsigned getSize() const { @@ -110,6 +114,11 @@ public: return data_; } + inline bool get_premultiplied() const + { + return data_.get_premultiplied(); + } + private: unsigned x_; unsigned y_; diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index 97d2d6a32..ecf6faec1 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -39,8 +39,6 @@ extern "C" #define TIFF_WRITE_STRIPPED 1 #define TIFF_WRITE_TILED 2 -#include - namespace mapnik { static inline tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size) @@ -200,14 +198,12 @@ struct tag_setter TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 4); if (data.get_premultiplied()) { - //uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; - uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; + uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); } else { - //uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; - uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; + uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); } if (config_.compression == COMPRESSION_DEFLATE @@ -267,7 +263,7 @@ struct tag_setter private: TIFF * output_; - tiff_config config_; + tiff_config & config_; }; inline void set_tiff_config(TIFF* output, tiff_config & config) @@ -348,10 +344,7 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, rows_per_strip); std::size_t strip_size = width * rows_per_strip; std::unique_ptr strip_buffer(new pixel_type[strip_size]); - //int end_y=(height/rows_per_strip+1)*rows_per_strip; - int end_y=height; - - for (int y=0; y < end_y; y+=rows_per_strip) + for (int y=0; y < height; y+=rows_per_strip) { int ty1 = std::min(height, static_cast(y + rows_per_strip)) - y; int row = y; diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 1563c3272..83aaed6bd 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -123,7 +123,9 @@ void agg_renderer::setup(Map const &m) } else { - mapnik::fill(pixmap_,*bg); + mapnik::color bg_color = *bg; + bg_color.set_premultiplied(true); + mapnik::fill(pixmap_,bg_color); } } diff --git a/src/color.cpp b/src/color.cpp index f1146e815..51fb19585 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -95,23 +95,28 @@ std::string color::to_hex_string() const return str; } -void color::premultiply() +bool color::premultiply() { + if (premultiplied_) return false; agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); pre_c.premultiply(); red_ = pre_c.r; green_ = pre_c.g; blue_ = pre_c.b; + premultiplied_ = true; + return true; } -void color::demultiply() +bool color::demultiply() { - // note: this darkens too much: https://github.com/mapnik/mapnik/issues/1519 + if (!premultiplied_) return false; agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); pre_c.demultiply(); red_ = pre_c.r; green_ = pre_c.g; blue_ = pre_c.b; + premultiplied_ = false; + return true; } } diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index ea4908d71..6667bce1c 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -169,7 +169,6 @@ MAPNIK_DECL void composite(image_rgba8 & dst, image_rgba8 const& src, composite_ #ifdef MAPNIK_DEBUG if (!src.get_premultiplied()) { - abort(); throw std::runtime_error("SOURCE MUST BE PREMULTIPLIED FOR COMPOSITING!"); } if (!dst.get_premultiplied()) diff --git a/src/image_util.cpp b/src/image_util.cpp index c5239e5af..02f5fdd32 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -783,19 +783,6 @@ struct visitor_fill visitor_fill(T1 const& val) : val_(val) {} - void operator() (image_rgba8 & data) - { - using pixel_type = typename image_rgba8::pixel_type; - bool was_demultiplied = mapnik::demultiply_alpha(data); - pixel_type val = static_cast(val_); - data.set(val); - if (was_demultiplied) - { - mapnik::premultiply_alpha(data); - } - - } - template void operator() (T2 & data) { @@ -817,14 +804,9 @@ struct visitor_fill void operator() (image_rgba8 & data) { using pixel_type = typename image_rgba8::pixel_type; - bool was_demultiplied = mapnik::demultiply_alpha(data); pixel_type val = static_cast(val_.rgba()); data.set(val); - if (was_demultiplied) - { - mapnik::premultiply_alpha(data); - } - + data.set_premultiplied(val_.get_premultiplied()); } template @@ -1069,7 +1051,23 @@ struct visitor_set_pixel void operator() (T2 & data) { using pixel_type = typename T2::pixel_type; - pixel_type val = static_cast(val_.rgba()); + pixel_type val; + if (data.get_premultiplied() && !val_.get_premultiplied()) + { + color tmp(val_); + tmp.premultiply(); + val = static_cast(tmp.rgba()); + } + else if (!data.get_premultiplied() && val_.get_premultiplied()) + { + color tmp(val_); + tmp.demultiply(); + val = static_cast(tmp.rgba()); + } + else + { + val = static_cast(val_.rgba()); + } if (check_bounds(data, x_, y_)) { data(x_, y_) = val; @@ -1163,11 +1161,7 @@ struct visitor_get_pixel { if (check_bounds(data, x_, y_)) { - uint32_t val = static_cast(data(x_, y_)); - return color(static_cast(val), - static_cast((val >>= 8)), - static_cast((val >>= 8)), - static_cast((val >>= 8))); + return color(static_cast(data(x_, y_)), data.get_premultiplied()); } else { diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 9bbe6fd59..65f405c09 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -308,10 +308,10 @@ void tiff_reader::init() { has_alpha_ = true; premultiplied_alpha_ = true; - if (extrasamples == 1 && - sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) + if (extrasamples > 0 && + sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED) { - premultiplied_alpha_ = false; + throw std::runtime_error("Unspecified provided for extra samples to tiff reader."); } } // Try extracting bounding box from geoTIFF tags @@ -641,15 +641,12 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_rgba8& image) int height=image.height(); unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_; - //unsigned end_y=((y0+height)/rows_per_strip_+1)*rows_per_strip_; unsigned end_y=std::min(y0+height, static_cast(height_)); - //bool laststrip=(static_cast(end_y) > height_)?true:false; - int row,tx0,tx1,ty0,ty1; + int tx0,tx1,ty0,ty1; - //image.set_premultiplied(true); tx0=x0; tx1=std::min(width+x0,static_cast(width_)); - + int row = 0; for (unsigned y=start_y; y < end_y; y+=rows_per_strip_) { ty0 = std::max(y0,y)-y; @@ -660,18 +657,11 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_rgba8& image) std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; break; } - row=y+ty0; - - //int n0=laststrip ? 0:(rows_per_strip_-ty1); - //int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1); - //std::cout << " n0: " << n0 << " n1: " << n1 << " y: " << y << " endy: " << end_y << std::endl; - //for (int n=n1;n>=n0;--n) - //for (int n=n0;n>=n1;++n) - // This is in reverse becauase the TIFFReadRGBAStrip reads inverted? - for (int ty = ty1-1; ty >= ty0; --ty, ++row) + // This is in reverse becauase the TIFFReadRGBAStrip reads inverted + for (unsigned ty = ty1; ty > ty0; --ty) { - //std::cout << "row: " << row <<" s: " << (tx0-x0) << " e: " << (tx1-x0) << " n: " << (n*width_+tx0) << std::endl; - image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[ty*width_+tx0]); + image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[(ty-1)*width_+tx0]); + ++row; } } } diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index da3b6c073..7652824ea 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -31,7 +31,7 @@ REQUIRE( reader->has_alpha() == true ); \ REQUIRE( tiff_reader2.has_alpha() == true ); \ REQUIRE( reader2->has_alpha() == true ); \ - REQUIRE( data.get_premultiplied() == false ); \ + REQUIRE( data.get_premultiplied() == true ); \ #define TIFF_ASSERT_NO_ALPHA( data ) \ REQUIRE( tiff_reader.has_alpha() == false ); \ diff --git a/tests/python_tests/compositing_test.py b/tests/python_tests/compositing_test.py index fc05525e6..bd4b75fe7 100644 --- a/tests/python_tests/compositing_test.py +++ b/tests/python_tests/compositing_test.py @@ -231,7 +231,7 @@ def test_background_image_with_alpha_and_background_color(): m.background_image = '../data/images/yellow_half_trans.png' im = mapnik.Image(m.width,m.height) mapnik.render(m,im) - eq_(get_unique_colors(im),['rgba(255,255,85,191)']) + eq_(get_unique_colors(im),['rgba(255,255,170,191)']) def test_background_image_with_alpha_and_background_color_against_composited_control(): m = mapnik.Map(10,10) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index a4b944bb9..7b233a233 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -28,6 +28,137 @@ def test_image_premultiply(): eq_(im.demultiply(), False) eq_(im.premultiplied(),False) +def test_image_premultiply_values(): + im = mapnik.Image(256,256) + im.background(mapnik.Color(16, 33, 255, 128)) + im.premultiply() + c = im.get_pixel_color(0,0) + eq_(c.r, 8) + eq_(c.g, 17) + eq_(c.b, 128) + eq_(c.a, 128) + im.demultiply() + # Do to the nature of this operation the result will not be exactly the same + c = im.get_pixel_color(0,0) + eq_(c.r,15) + eq_(c.g,33) + eq_(c.b,255) + eq_(c.a,128) + +def test_background(): + im = mapnik.Image(256,256) + eq_(im.premultiplied(), False) + im.background(mapnik.Color(32,64,125,128)) + eq_(im.premultiplied(), False) + c = im.get_pixel_color(0,0) + eq_(c.get_premultiplied(), False) + eq_(c.r,32) + eq_(c.g,64) + eq_(c.b,125) + eq_(c.a,128) + # Now again with a premultiplied alpha + im.background(mapnik.Color(32,64,125,128,True)) + eq_(im.premultiplied(), True) + c = im.get_pixel_color(0,0) + eq_(c.get_premultiplied(), True) + eq_(c.r,32) + eq_(c.g,64) + eq_(c.b,125) + eq_(c.a,128) + +def test_set_and_get_pixel(): + # Create an image that is not premultiplied + im = mapnik.Image(256,256) + c0 = mapnik.Color(16,33,255,128) + c0_pre = mapnik.Color(16,33,255,128, True) + im.set_pixel(0,0,c0) + im.set_pixel(1,1,c0_pre) + # No differences for non premultiplied pixels + c1_int = mapnik.Color(im.get_pixel(0,0)) + eq_(c0.r, c1_int.r) + eq_(c0.g, c1_int.g) + eq_(c0.b, c1_int.b) + eq_(c0.a, c1_int.a) + c1 = im.get_pixel_color(0,0) + eq_(c0.r, c1.r) + eq_(c0.g, c1.g) + eq_(c0.b, c1.b) + eq_(c0.a, c1.a) + # The premultiplied Color should be demultiplied before being applied. + c0_pre.demultiply() + c1_int = mapnik.Color(im.get_pixel(1,1)) + eq_(c0_pre.r, c1_int.r) + eq_(c0_pre.g, c1_int.g) + eq_(c0_pre.b, c1_int.b) + eq_(c0_pre.a, c1_int.a) + c1 = im.get_pixel_color(1,1) + eq_(c0_pre.r, c1.r) + eq_(c0_pre.g, c1.g) + eq_(c0_pre.b, c1.b) + eq_(c0_pre.a, c1.a) + + # Now create a new image that is premultiplied + im = mapnik.Image(256,256, mapnik.ImageType.rgba8, True, True) + c0 = mapnik.Color(16,33,255,128) + c0_pre = mapnik.Color(16,33,255,128, True) + im.set_pixel(0,0,c0) + im.set_pixel(1,1,c0_pre) + # It should have put pixels that are the same as premultiplied so premultiply c0 + c0.premultiply() + c1_int = mapnik.Color(im.get_pixel(0,0)) + eq_(c0.r, c1_int.r) + eq_(c0.g, c1_int.g) + eq_(c0.b, c1_int.b) + eq_(c0.a, c1_int.a) + c1 = im.get_pixel_color(0,0) + eq_(c0.r, c1.r) + eq_(c0.g, c1.g) + eq_(c0.b, c1.b) + eq_(c0.a, c1.a) + # The premultiplied Color should be the same though + c1_int = mapnik.Color(im.get_pixel(1,1)) + eq_(c0_pre.r, c1_int.r) + eq_(c0_pre.g, c1_int.g) + eq_(c0_pre.b, c1_int.b) + eq_(c0_pre.a, c1_int.a) + c1 = im.get_pixel_color(1,1) + eq_(c0_pre.r, c1.r) + eq_(c0_pre.g, c1.g) + eq_(c0_pre.b, c1.b) + eq_(c0_pre.a, c1.a) + +@raises(IndexError) +def test_set_pixel_out_of_range_1(): + im = mapnik.Image(4,4) + c = mapnik.Color('blue') + im.set_pixel(5,5,c) + +@raises(OverflowError) +def test_set_pixel_out_of_range_2(): + im = mapnik.Image(4,4) + c = mapnik.Color('blue') + im.set_pixel(-1,1,c) + +@raises(IndexError) +def test_get_pixel_out_of_range_1(): + im = mapnik.Image(4,4) + c = im.get_pixel(5,5) + +@raises(OverflowError) +def test_get_pixel_out_of_range_2(): + im = mapnik.Image(4,4) + c = im.get_pixel(-1,1) + +@raises(IndexError) +def test_get_pixel_color_out_of_range_1(): + im = mapnik.Image(4,4) + c = im.get_pixel_color(5,5) + +@raises(OverflowError) +def test_get_pixel_color_out_of_range_2(): + im = mapnik.Image(4,4) + c = im.get_pixel_color(-1,1) + def test_set_color_to_alpha(): im = mapnik.Image(256,256) im.background(mapnik.Color('rgba(12,12,12,255)')) diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index 001d297a2..634379fbd 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -45,16 +45,19 @@ def test_tiff_round_trip_stripped(): eq_(im.height(),im3.height()) eq_(len(im.tostring()), org_str) eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('png')),len(im2.tostring('png'))) + # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the + # difference in tags. But size should still be the same eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im3.tostring('tiff:method=stripped'))) + eq_(len(im2.tostring()),len(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(len(im2.tostring('tiff:method=stripped')),len(im3.tostring('tiff:method=stripped'))) def test_tiff_round_trip_rows_stripped(): filepath = '/tmp/mapnik-tiff-io-rows_stripped.tiff' filepath2 = '/tmp/mapnik-tiff-io-rows_stripped2.tiff' im = mapnik.Image(255,267) im.background(mapnik.Color('rgba(12,255,128,.5)')) + #im.premultiply() org_str = len(im.tostring()) im.save(filepath,'tiff:method=stripped:rows_per_strip=8') im2 = mapnik.Image.open(filepath) @@ -66,31 +69,35 @@ def test_tiff_round_trip_rows_stripped(): eq_(im.height(),im3.height()) eq_(len(im.tostring()), org_str) eq_(len(im.tostring()),len(im2.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the + # difference in tags. But size should still be the same eq_(len(im.tostring('tiff:method=stripped:rows_per_strip=8')),len(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=stripped:rows_per_strip=8')),len(im3.tostring('tiff:method=stripped:rows_per_strip=8'))) + eq_(len(im2.tostring()),len(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(len(im2.tostring('tiff:method=stripped:rows_per_strip=8')),len(im3.tostring('tiff:method=stripped:rows_per_strip=8'))) def test_tiff_round_trip_buffered_tiled(): filepath = '/tmp/mapnik-tiff-io-buffered-tiled.tiff' filepath2 = '/tmp/mapnik-tiff-io-buffered-tiled2.tiff' + filepath3 = '/tmp/mapnik-tiff-io-buffered-tiled3.tiff' im = mapnik.Image(255,267) - #im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(1,255,128,.5)')) + im.background(mapnik.Color('rgba(33,255,128,.5)')) im.save(filepath,'tiff:method=tiled:tile_width=32:tile_height=32') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) im2.save(filepath2, 'tiff:method=tiled:tile_width=32:tile_height=32') - im4 = mapnik.Image.open(filepath2) + im3.save(filepath3, 'tiff:method=tiled:tile_width=32:tile_height=32') eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im2.tostring()),len(im4.tostring())) - eq_(len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im4.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) eq_(len(im.tostring()),len(im2.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the + # difference in tags. But size should still be the same eq_(len(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + eq_(len(im2.tostring()),len(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) def test_tiff_round_trip_tiled(): filepath = '/tmp/mapnik-tiff-io-tiled.tiff' @@ -104,9 +111,12 @@ def test_tiff_round_trip_tiled(): eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) eq_(len(im.tostring()),len(im2.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the + # difference in tags. HOWEVER for this type they have the same size? Perhaps is a bad test? eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im3.tostring('tiff:method=tiled'))) + eq_(len(im2.tostring()),len(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(len(im2.tostring('tiff:method=tiled')),len(im3.tostring('tiff:method=tiled'))) def test_tiff_rgb8_compare(): From 5d9f04700214e5732b59681e1dd86bc5d9eaae4a Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Sat, 24 Jan 2015 20:48:15 -0600 Subject: [PATCH 59/91] Fixed some issues in color and bindings where you could create a color and premultiplied was not set and it was resulting in it being assigned randomly, causing some issues at runtime. Updated some images in visual tests that were orginally set prior to all tiffs being premultiplied, this was causing a slight difference in a few pixels. Updated the tiff tests a lot. Fixed tiff reader so that it always considers everything read from RGB or RGBA as premultiplied. This is due to the fact that RGBA reader always premultiplies the alpha no matter its original form. Put in a fix so that the file does not exist no longer shows up in the test running. Fixed some failing tests in the c++ test due to tiffs now always being premultiplied for RGB(A) --- bindings/python/mapnik_color.cpp | 8 +- include/mapnik/color.hpp | 2 +- include/mapnik/tiff_io.hpp | 9 +- src/color.cpp | 3 +- src/tiff_reader.cpp | 6 +- tests/cxx/tiff_io.cpp | 29 ++- tests/python_tests/compositing_test.py | 2 +- tests/python_tests/datasource_test.py | 24 ++- tests/python_tests/image_tiff_test.py | 196 +++++++++++------- ...edge-raster2-600-400-1.0-agg-reference.png | Bin 8179 -> 8181 bytes ...edge-raster2-600-400-2.0-agg-reference.png | Bin 8179 -> 8181 bytes ...edge-raster2-969-793-1.0-agg-reference.png | Bin 8907 -> 8913 bytes ...edge-raster2-969-793-2.0-agg-reference.png | Bin 8907 -> 8913 bytes 13 files changed, 172 insertions(+), 107 deletions(-) diff --git a/bindings/python/mapnik_color.cpp b/bindings/python/mapnik_color.cpp index 7210730c2..3e8df62f9 100644 --- a/bindings/python/mapnik_color.cpp +++ b/bindings/python/mapnik_color.cpp @@ -84,6 +84,12 @@ void export_color () "The string may be a CSS color name (e.g. 'blue')\n" "or a hex color string (e.g. '#0000ff').\n") ) + .def(init( + ( arg("color_string"), arg("premultiplied") ), + "Creates a new color from its CSS string representation.\n" + "The string may be a CSS color name (e.g. 'blue')\n" + "or a hex color string (e.g. '#0000ff').\n") + ) .add_property("r", &color::red, &color::set_red, @@ -108,8 +114,6 @@ void export_color () .def(self != self) .def_pickle(color_pickle_suite()) .def("__str__",&color::to_string) - .def("packed",&color::rgba) - .def("premultiply",&color::premultiply) .def("set_premultiplied",&color::set_premultiplied) .def("get_premultiplied",&color::get_premultiplied) .def("premultiply",&color::premultiply) diff --git a/include/mapnik/color.hpp b/include/mapnik/color.hpp index 4d2eb846c..e7e9ab92d 100644 --- a/include/mapnik/color.hpp +++ b/include/mapnik/color.hpp @@ -87,7 +87,7 @@ public: alpha_(std::move(rhs.alpha_)), premultiplied_(std::move(rhs.premultiplied_)) {} - color( std::string const& str); + color( std::string const& str, bool premultiplied = false); std::string to_string() const; std::string to_hex_string() const; diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index ecf6faec1..a887b975a 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -179,7 +179,7 @@ struct tiff_config struct tag_setter { - tag_setter(TIFF * output, tiff_config & config) + tag_setter(TIFF * output, tiff_config const& config) : output_(output), config_(config) {} @@ -263,10 +263,10 @@ struct tag_setter private: TIFF * output_; - tiff_config & config_; + tiff_config const& config_; }; -inline void set_tiff_config(TIFF* output, tiff_config & config) +inline void set_tiff_config(TIFF* output, tiff_config const& config) { // Set some constant tiff information that doesn't vary based on type of data // or image size @@ -287,7 +287,7 @@ inline void set_tiff_config(TIFF* output, tiff_config & config) } template -void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) +void save_as_tiff(T1 & file, T2 const& image, tiff_config const& config) { using pixel_type = typename T2::pixel_type; @@ -317,7 +317,6 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) // Set tags that vary based on the type of data being provided. tag_setter set(output, config); set(image); - //util::apply_visitor(set, image); // Use specific types of writing methods. if (TIFF_WRITE_SCANLINE == config.method) diff --git a/src/color.cpp b/src/color.cpp index 51fb19585..75204ce7f 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -45,9 +45,10 @@ namespace mapnik { -color::color(std::string const& str) +color::color(std::string const& str, bool premultiplied) { *this = parse_color(str); + premultiplied_ = premultiplied; } std::string color::to_string() const diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 65f405c09..705d939c6 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -136,7 +136,6 @@ private: unsigned bands_; unsigned planar_config_; unsigned compression_; - bool premultiplied_alpha_; bool has_alpha_; bool is_tiled_; @@ -214,7 +213,6 @@ tiff_reader::tiff_reader(std::string const& file_name) bands_(1), planar_config_(PLANARCONFIG_CONTIG), compression_(COMPRESSION_NONE), - premultiplied_alpha_(false), has_alpha_(false), is_tiled_(false) { @@ -238,7 +236,6 @@ tiff_reader::tiff_reader(char const* data, std::size_t size) bands_(1), planar_config_(PLANARCONFIG_CONTIG), compression_(COMPRESSION_NONE), - premultiplied_alpha_(false), has_alpha_(false), is_tiled_(false) { @@ -307,7 +304,6 @@ void tiff_reader::init() &extrasamples, &sampleinfo)) { has_alpha_ = true; - premultiplied_alpha_ = true; if (extrasamples > 0 && sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED) { @@ -568,7 +564,7 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne //PHOTOMETRIC_ITULAB = 10; //PHOTOMETRIC_LOGL = 32844; //PHOTOMETRIC_LOGLUV = 32845; - image_rgba8 data(width,height, true, premultiplied_alpha_); + image_rgba8 data(width,height, true, true); read(x0, y0, data); return image_any(std::move(data)); } diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index 7652824ea..7f7d798d1 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -33,7 +33,14 @@ REQUIRE( reader2->has_alpha() == true ); \ REQUIRE( data.get_premultiplied() == true ); \ -#define TIFF_ASSERT_NO_ALPHA( data ) \ +#define TIFF_ASSERT_NO_ALPHA_RGB( data ) \ + REQUIRE( tiff_reader.has_alpha() == false ); \ + REQUIRE( reader->has_alpha() == false ); \ + REQUIRE( tiff_reader2.has_alpha() == false ); \ + REQUIRE( reader2->has_alpha() == false ); \ + REQUIRE( data.get_premultiplied() == true ); \ + +#define TIFF_ASSERT_NO_ALPHA_GRAY( data ) \ REQUIRE( tiff_reader.has_alpha() == false ); \ REQUIRE( reader->has_alpha() == false ); \ REQUIRE( tiff_reader2.has_alpha() == false ); \ @@ -77,7 +84,7 @@ SECTION("scan rgb8 striped") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -107,7 +114,7 @@ SECTION("scan rgb8 tiled") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -155,7 +162,7 @@ SECTION("rgb8 striped") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -171,7 +178,7 @@ SECTION("rgb8 tiled") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -187,7 +194,7 @@ SECTION("gray8 striped") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -203,7 +210,7 @@ SECTION("gray8 tiled") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -219,7 +226,7 @@ SECTION("gray16 striped") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -235,7 +242,7 @@ SECTION("gray16 tiled") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -251,7 +258,7 @@ SECTION("gray32f striped") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -267,7 +274,7 @@ SECTION("gray32f tiled") { mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA( data ); + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } diff --git a/tests/python_tests/compositing_test.py b/tests/python_tests/compositing_test.py index bd4b75fe7..fc05525e6 100644 --- a/tests/python_tests/compositing_test.py +++ b/tests/python_tests/compositing_test.py @@ -231,7 +231,7 @@ def test_background_image_with_alpha_and_background_color(): m.background_image = '../data/images/yellow_half_trans.png' im = mapnik.Image(m.width,m.height) mapnik.render(m,im) - eq_(get_unique_colors(im),['rgba(255,255,170,191)']) + eq_(get_unique_colors(im),['rgba(255,255,85,191)']) def test_background_image_with_alpha_and_background_color_against_composited_control(): m = mapnik.Map(10,10) diff --git a/tests/python_tests/datasource_test.py b/tests/python_tests/datasource_test.py index e6a05e5a5..07fe09163 100644 --- a/tests/python_tests/datasource_test.py +++ b/tests/python_tests/datasource_test.py @@ -14,6 +14,7 @@ def test_that_datasources_exist(): print '***NOTICE*** - no datasource plugins have been loaded' # adapted from raster_symboliser_test#test_dataraster_query_point +@raises(RuntimeError) def test_vrt_referring_to_missing_files(): srs = '+init=epsg:32630' if 'gdal' in mapnik.DatasourceCache.plugin_names(): @@ -31,13 +32,26 @@ def test_vrt_referring_to_missing_files(): _map.zoom_all() - # Should RuntimeError here + # Fancy stuff to supress output of error + # open 2 fds + null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)] + # save the current file descriptors to a tuple + save = os.dup(1), os.dup(2) + # put /dev/null fds on 1 and 2 + os.dup2(null_fds[0], 1) + os.dup2(null_fds[1], 2) + + # *** run the function *** try: + # Should RuntimeError here _map.query_point(0, x, y).features - except RuntimeError, e: - eq_("this_file_should_not_exist.tif' does not exist in the file system" in str(e), True) - else: - assert False + finally: + # restore file descriptors so I can print the results + os.dup2(save[0], 1) + os.dup2(save[1], 2) + # close the temporary fds + os.close(null_fds[0]) + os.close(null_fds[1]) def test_field_listing(): diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index 634379fbd..a2c524f90 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -3,10 +3,14 @@ import sys import os, mapnik +import hashlib from timeit import Timer, time from nose.tools import * from utilities import execution_path, run_all -#mapnik.logger.set_severity(mapnik.severity_type.Debug) + +def hashstr(var): + return hashlib.md5(var).hexdigest() + def setup(): # All of the paths used are relative, if we run the tests # from another directory we need to chdir() @@ -16,7 +20,7 @@ def test_tiff_round_trip_scanline(): filepath = '/tmp/mapnik-tiff-io-scanline.tiff' im = mapnik.Image(255,267) im.background(mapnik.Color('rgba(12,255,128,.5)')) - org_str = len(im.tostring()) + org_str = hashstr(im.tostring()) im.save(filepath,'tiff:method=scanline') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -24,17 +28,22 @@ def test_tiff_round_trip_scanline(): eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()), org_str) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im3.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()), org_str) + # This won't be the same the first time around because the im is not premultiplied and im2 is + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + # Now premultiply + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) + eq_(hashstr(im2.tostring('tiff:method=scanline')),hashstr(im3.tostring('tiff:method=scanline'))) def test_tiff_round_trip_stripped(): filepath = '/tmp/mapnik-tiff-io-stripped.tiff' im = mapnik.Image(255,267) im.background(mapnik.Color('rgba(12,255,128,.5)')) - org_str = len(im.tostring()) + org_str = hashstr(im.tostring()) im.save(filepath,'tiff:method=stripped') im2 = mapnik.Image.open(filepath) im2.save('/tmp/mapnik-tiff-io-stripped2.tiff','tiff:method=stripped') @@ -43,38 +52,53 @@ def test_tiff_round_trip_stripped(): eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()), org_str) - eq_(len(im.tostring()),len(im2.tostring())) - # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the - # difference in tags. But size should still be the same - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) - eq_(len(im2.tostring()),len(im3.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + # Now if we premultiply they will be exactly the same + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) # Both of these started out premultiplied, so this round trip should be exactly the same! - eq_(len(im2.tostring('tiff:method=stripped')),len(im3.tostring('tiff:method=stripped'))) + eq_(hashstr(im2.tostring('tiff:method=stripped')),hashstr(im3.tostring('tiff:method=stripped'))) def test_tiff_round_trip_rows_stripped(): filepath = '/tmp/mapnik-tiff-io-rows_stripped.tiff' filepath2 = '/tmp/mapnik-tiff-io-rows_stripped2.tiff' im = mapnik.Image(255,267) im.background(mapnik.Color('rgba(12,255,128,.5)')) - #im.premultiply() - org_str = len(im.tostring()) + c = im.get_pixel_color(0,0) + eq_(c.r, 12) + eq_(c.g, 255) + eq_(c.b, 128) + eq_(c.a, 128) + eq_(c.get_premultiplied(), False) im.save(filepath,'tiff:method=stripped:rows_per_strip=8') im2 = mapnik.Image.open(filepath) + c2 = im2.get_pixel_color(0,0) + eq_(c2.r, 6) + eq_(c2.g, 128) + eq_(c2.b, 64) + eq_(c2.a, 128) + eq_(c2.get_premultiplied(), True) im2.save(filepath2,'tiff:method=stripped:rows_per_strip=8') im3 = mapnik.Image.fromstring(open(filepath,'r').read()) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()), org_str) - eq_(len(im.tostring()),len(im2.tostring())) - # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the - # difference in tags. But size should still be the same - eq_(len(im.tostring('tiff:method=stripped:rows_per_strip=8')),len(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) - eq_(len(im2.tostring()),len(im3.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) + # Now premultiply the first image and they will be the same! + im.premultiply() + eq_(hashstr(im.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) # Both of these started out premultiplied, so this round trip should be exactly the same! - eq_(len(im2.tostring('tiff:method=stripped:rows_per_strip=8')),len(im3.tostring('tiff:method=stripped:rows_per_strip=8'))) + eq_(hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im3.tostring('tiff:method=stripped:rows_per_strip=8'))) def test_tiff_round_trip_buffered_tiled(): filepath = '/tmp/mapnik-tiff-io-buffered-tiled.tiff' @@ -82,8 +106,20 @@ def test_tiff_round_trip_buffered_tiled(): filepath3 = '/tmp/mapnik-tiff-io-buffered-tiled3.tiff' im = mapnik.Image(255,267) im.background(mapnik.Color('rgba(33,255,128,.5)')) + c = im.get_pixel_color(0,0) + eq_(c.r, 33) + eq_(c.g, 255) + eq_(c.b, 128) + eq_(c.a, 128) + eq_(c.get_premultiplied(), False) im.save(filepath,'tiff:method=tiled:tile_width=32:tile_height=32') im2 = mapnik.Image.open(filepath) + c2 = im2.get_pixel_color(0,0) + eq_(c2.r, 17) + eq_(c2.g, 128) + eq_(c2.b, 64) + eq_(c2.a, 128) + eq_(c2.get_premultiplied(), True) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) im2.save(filepath2, 'tiff:method=tiled:tile_width=32:tile_height=32') im3.save(filepath3, 'tiff:method=tiled:tile_width=32:tile_height=32') @@ -91,13 +127,17 @@ def test_tiff_round_trip_buffered_tiled(): eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()),len(im2.tostring())) - # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the - # difference in tags. But size should still be the same - eq_(len(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) - eq_(len(im2.tostring()),len(im3.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + # Now premultiply the first image and they should be the same + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) # Both of these started out premultiplied, so this round trip should be exactly the same! - eq_(len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + eq_(hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) def test_tiff_round_trip_tiled(): filepath = '/tmp/mapnik-tiff-io-tiled.tiff' @@ -110,27 +150,31 @@ def test_tiff_round_trip_tiled(): eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()),len(im2.tostring())) - # Because one will end up with UNASSOC alpha tag which internally the TIFF will multiply, the first to string will not be the same due to the - # difference in tags. HOWEVER for this type they have the same size? Perhaps is a bad test? - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) - eq_(len(im2.tostring()),len(im3.tostring())) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + # Now premultiply the first image and they will be exactly the same. + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) # Both of these started out premultiplied, so this round trip should be exactly the same! - eq_(len(im2.tostring('tiff:method=tiled')),len(im3.tostring('tiff:method=tiled'))) + eq_(hashstr(im2.tostring('tiff:method=tiled')),hashstr(im3.tostring('tiff:method=tiled'))) def test_tiff_rgb8_compare(): filepath1 = '../data/tiff/ndvi_256x256_rgb8_striped.tif' filepath2 = '/tmp/mapnik-tiff-rgb8.tiff' im = mapnik.Image.open(filepath1) - im.save(filepath2,'tiff:method=stripped:rows_per_strip=10') + im.save(filepath2,'tiff') im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff')),len(im2.tostring('tiff'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff')),hashstr(im2.tostring('tiff'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -140,10 +184,10 @@ def test_tiff_rgba8_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -153,10 +197,10 @@ def test_tiff_rgba8_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -166,10 +210,10 @@ def test_tiff_rgba8_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_gray8_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -179,10 +223,10 @@ def test_tiff_gray8_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray8_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -192,10 +236,10 @@ def test_tiff_gray8_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray8_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -205,10 +249,10 @@ def test_tiff_gray8_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray16_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -218,10 +262,10 @@ def test_tiff_gray16_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray16_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -231,10 +275,10 @@ def test_tiff_gray16_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray16_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -244,10 +288,10 @@ def test_tiff_gray16_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray32f_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -257,10 +301,10 @@ def test_tiff_gray32f_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) def test_tiff_gray32f_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -270,10 +314,10 @@ def test_tiff_gray32f_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) def test_tiff_gray32f_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -283,10 +327,10 @@ def test_tiff_gray32f_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("tiff")) != len(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) if __name__ == "__main__": setup() diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png index dafaec41d62a934e8a5656aa735cc1321a8e712c..9b909e0278044ade99893ef8caca3b6a04af603d 100644 GIT binary patch delta 6854 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
  • l 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png index dafaec41d62a934e8a5656aa735cc1321a8e712c..9b909e0278044ade99893ef8caca3b6a04af603d 100644 GIT binary patch delta 6854 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
  • l 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png index b23e716ab470b0a83c184a3277dc67e33db1108f..828cdce7cf57e315a55d25f3880b1230c10c21f4 100644 GIT binary patch delta 6878 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png index b23e716ab470b0a83c184a3277dc67e33db1108f..828cdce7cf57e315a55d25f3880b1230c10c21f4 100644 GIT binary patch delta 6878 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 From f616367ac2d4ef4f7138d292f1899898474d8421 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Sat, 24 Jan 2015 21:16:36 -0600 Subject: [PATCH 60/91] Including std library that was missing. --- include/mapnik/tiff_io.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index a887b975a..f729ca31a 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -35,6 +35,9 @@ extern "C" #define RealTIFFClose TIFFClose } +//std +#include + #define TIFF_WRITE_SCANLINE 0 #define TIFF_WRITE_STRIPPED 1 #define TIFF_WRITE_TILED 2 From 997da1e630fc98af0bc4a597a1adc7f1c41e9eba Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Sat, 24 Jan 2015 21:29:50 -0600 Subject: [PATCH 61/91] Fix for benchmark --- benchmark/test_rendering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp index fc7984b15..30e80be77 100644 --- a/benchmark/test_rendering.cpp +++ b/benchmark/test_rendering.cpp @@ -59,7 +59,7 @@ public: ren.apply(); if (!preview_.empty()) { std::clog << "preview available at " << preview_ << "\n"; - mapnik::save_to_file(im.data(),preview_); + mapnik::save_to_file(im,preview_); } return true; } From 84b5194130cae274c24d4126e11328e9e5412b7e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 26 Jan 2015 21:35:02 -0800 Subject: [PATCH 62/91] image.composite: source should be immutable --- bindings/python/mapnik_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index a7142e699..4b8e3485a 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -239,7 +239,7 @@ void clear(image_any & im) mapnik::fill(im, 0); } -void composite(image_any & dst, image_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) +void composite(image_any & dst, image_any const& src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) { bool demultiply_dst = mapnik::premultiply_alpha(dst); bool demultiply_src = mapnik::premultiply_alpha(src); From 921c058d7dff3ffd2a462e28c74db2049de83994 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 26 Jan 2015 21:35:35 -0800 Subject: [PATCH 63/91] use image.blend is gone so use image.composite --- tests/python_tests/utilities.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/python_tests/utilities.py b/tests/python_tests/utilities.py index 9d413a97f..45be868b8 100644 --- a/tests/python_tests/utilities.py +++ b/tests/python_tests/utilities.py @@ -83,6 +83,6 @@ def side_by_side_image(left_im, right_im): width = left_im.width() + 1 + right_im.width() height = max(left_im.height(), right_im.height()) im = mapnik.Image(width, height) - im.blend(0, 0, left_im, 1.0) - im.blend(left_im.width() + 1, 0, right_im, 1.0) + im.composite(left_im,mapnik.CompositeOp.src_over,1.0,0,0) + im.composite(right_im,mapnik.CompositeOp.src_over,1.0,left_im.width() + 1, 0) return im From ebfbbef454e782ae08fd933f46e3af4eaea9ef9a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 26 Jan 2015 21:36:47 -0800 Subject: [PATCH 64/91] add visual tests for pgraster to try to make sense of failures --- ...subquery-data_16bsi_subquery-16BSI-135.png | Bin 0 -> 90 bytes ...subquery-data_16bui_subquery-16BUI-126.png | Bin 0 -> 90 bytes ...ata_subquery-data_2bui_subquery-2BUI-3.png | Bin 0 -> 90 bytes ...a_subquery-data_32bf_subquery-32BF-450.png | Bin 0 -> 90 bytes ...subquery-data_32bsi_subquery-32BSI-264.png | Bin 0 -> 90 bytes ...subquery-data_32bui_subquery-32BUI-255.png | Bin 0 -> 90 bytes ...ta_subquery-data_4bui_subquery-4BUI-15.png | Bin 0 -> 90 bytes ..._subquery-data_64bf_subquery-64BF-3072.png | Bin 0 -> 90 bytes ...ta_subquery-data_8bsi_subquery-8BSI-69.png | Bin 0 -> 90 bytes ...ta_subquery-data_8bui_subquery-8BUI-63.png | Bin 0 -> 90 bytes ...ery-grayscale_16bsi_subquery-16BSI-144.png | Bin 0 -> 96 bytes ...ery-grayscale_16bui_subquery-16BUI-126.png | Bin 0 -> 96 bytes ...ubquery-grayscale_2bui_subquery-2BUI-3.png | Bin 0 -> 96 bytes ...ery-grayscale_32bsi_subquery-32BSI-129.png | Bin 0 -> 96 bytes ...ery-grayscale_32bui_subquery-32BUI-255.png | Bin 0 -> 92 bytes ...bquery-grayscale_4bui_subquery-4BUI-15.png | Bin 0 -> 96 bytes ...bquery-grayscale_8bsi_subquery-8BSI-69.png | Bin 0 -> 96 bytes ...bquery-grayscale_8bui_subquery-8BUI-63.png | Bin 0 -> 95 bytes ...dataedge-rgb_8bui C T:64x64 Cl--1-box1.png | Bin 0 -> 124081 bytes ...dataedge-rgb_8bui C T:64x64 Cl--1-box2.png | Bin 0 -> 4378 bytes ...aedge-rgb_8bui C T:64x64 Sc Cl--1-box1.png | Bin 0 -> 124277 bytes ...aedge-rgb_8bui C T:64x64 Sc Cl--1-box2.png | Bin 0 -> 4378 bytes ...dataedge-rgb_8bui C T:64x64 Sc--0-box1.png | Bin 0 -> 124277 bytes ...dataedge-rgb_8bui C T:64x64 Sc--0-box2.png | Bin 0 -> 4378 bytes ...-nodataedge-rgb_8bui C T:64x64--0-box1.png | Bin 0 -> 124081 bytes ...-nodataedge-rgb_8bui C T:64x64--0-box2.png | Bin 0 -> 4378 bytes .../rgba_8bui-rgba_8bui C O:2 Cl-2-1-box1.png | Bin 0 -> 12436 bytes .../rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png | Bin 0 -> 3647 bytes ...ba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box1.png | Bin 0 -> 12436 bytes ...ba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png | Bin 0 -> 3647 bytes .../rgba_8bui-rgba_8bui C O:2 Sc-2-0-box1.png | Bin 0 -> 12436 bytes .../rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png | Bin 0 -> 3637 bytes .../rgba_8bui-rgba_8bui C O:2-2-0-box1.png | Bin 0 -> 12436 bytes .../rgba_8bui-rgba_8bui C O:2-2-0-box2.png | Bin 0 -> 3637 bytes ...ui-rgba_8bui C T:16x16 O:2 Cl-2-1-box1.png | Bin 0 -> 12436 bytes ...ui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png | Bin 0 -> 3650 bytes ...rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png | Bin 0 -> 12436 bytes ...rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png | Bin 0 -> 3650 bytes ...ui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png | Bin 0 -> 12436 bytes ...ui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png | Bin 0 -> 3638 bytes ..._8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png | Bin 0 -> 12436 bytes ..._8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png | Bin 0 -> 3638 bytes .../rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png | Bin 0 -> 5248 bytes .../rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png | Bin 0 -> 2158 bytes ...rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box1.png | Bin 0 -> 5248 bytes ...rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png | Bin 0 -> 2158 bytes .../rgba_8bui-rgba_8bui O:2 Sc-2-0-box1.png | Bin 0 -> 5248 bytes .../rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png | Bin 0 -> 2170 bytes .../rgba_8bui-rgba_8bui O:2-2-0-box1.png | Bin 0 -> 5248 bytes .../rgba_8bui-rgba_8bui O:2-2-0-box2.png | Bin 0 -> 2170 bytes ...8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png | Bin 0 -> 5248 bytes ...8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png | Bin 0 -> 2158 bytes ...i-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box1.png | Bin 0 -> 5248 bytes ...i-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png | Bin 0 -> 2158 bytes ...8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box1.png | Bin 0 -> 5248 bytes ...8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png | Bin 0 -> 2137 bytes ...ba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png | Bin 0 -> 5248 bytes ...ba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png | Bin 0 -> 2137 bytes ...8bui_subquery-8BUI-255-0-0-255-255-255.png | Bin 0 -> 93 bytes tests/python_tests/pgraster_test.py | 40 ++++++++++++++---- 60 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_16bui_subquery-16BUI-126.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_2bui_subquery-2BUI-3.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_32bf_subquery-32BF-450.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_32bsi_subquery-32BSI-264.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_32bui_subquery-32BUI-255.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_4bui_subquery-4BUI-15.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_64bf_subquery-64BF-3072.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_8bsi_subquery-8BSI-69.png create mode 100644 tests/python_tests/images/support/pgraster/data_subquery-data_8bui_subquery-8BUI-63.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bsi_subquery-16BSI-144.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bui_subquery-16BUI-126.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_2bui_subquery-2BUI-3.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bsi_subquery-32BSI-129.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bui_subquery-32BUI-255.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_4bui_subquery-4BUI-15.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bsi_subquery-8BSI-69.png create mode 100644 tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bui_subquery-8BUI-63.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png create mode 100644 tests/python_tests/images/support/pgraster/rgba_subquery-rgba_8bui_subquery-8BUI-255-0-0-255-255-255.png diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png b/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png new file mode 100644 index 0000000000000000000000000000000000000000..38be9e295375ffcaa96c07047683393f1984a2c2 GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^{2cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6cxAsQ2t6B2&>pI>9MN>blV nT;i&a=-C|#fq|wkOqm%@tUloPV1wvSpkfA3S3j3^P6Ygr+AsQ2tXBZ?NsxLA;ydv$- ujROZ5So^bYgr+AsQ2tSFB$B+g~qD;%bk4 tc4p?n2Z3j=T#ykGY7!L|4Q-A$X1Ml{lVk6Rf7w7S44$rjF6*2UngDjB9Ap3h literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_2bui_subquery-2BUI-3.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_2bui_subquery-2BUI-3.png new file mode 100644 index 0000000000000000000000000000000000000000..62aa1631a61f0e081daf1d9e3f69ff42fff76442 GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^{2Ygr+AsQ2t6VlTD`Rk=gTH&pgQu&X%Q~loCIDkH8_@s& literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bsi_subquery-32BSI-129.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bsi_subquery-32BSI-129.png new file mode 100644 index 0000000000000000000000000000000000000000..b134b2d24a0471555c8de5c2a82fe4c7ef903f96 GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^{2Ygr+AsQ2tGjekN`0J%fTG2ZKA@Wq0RBe3_qF#BsV7SSOL_+;OXk;vd$@?2>?kT8yWxr literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bui_subquery-32BUI-255.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bui_subquery-32BUI-255.png new file mode 100644 index 0000000000000000000000000000000000000000..5f8035a2da5ff05918abc014df816218324a4715 GIT binary patch literal 92 zcmeAS@N?(olHy`uVBq!ia0vp^{2Ygr+AsQ2tA3T5l-(N3H;%bll u=1rRxJqSE|<-(bxM_WaOMMIn8jTwFgGPktNuy+S)VeoYIb6Mw<&;$VM5gyC{ literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bsi_subquery-8BSI-69.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bsi_subquery-8BSI-69.png new file mode 100644 index 0000000000000000000000000000000000000000..85abadd9e0950ef1bb8398d2774e2694872d4a0e GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^{2Ygr+AsQ2t3rb7>`s<}hT9SZ;e literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bui_subquery-8BUI-63.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bui_subquery-8BUI-63.png new file mode 100644 index 0000000000000000000000000000000000000000..06d6249a2c2e78962e74a3403bb17171450abe40 GIT binary patch literal 95 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 z�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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..846981baa4719a01a8cb2a5bae95cae6723bce64 GIT binary patch literal 4378 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 z�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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..846981baa4719a01a8cb2a5bae95cae6723bce64 GIT binary patch literal 4378 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..0669f5288bcc390fcbf8044eb0adfefd8d51c41b GIT binary patch literal 3647 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..0669f5288bcc390fcbf8044eb0adfefd8d51c41b GIT binary patch literal 3647 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..04135187e241578c4fa4909b2d37058ac5289e38 GIT binary patch literal 3637 zcmb7{c~leE7sp>f5Cy6&t*EFVtw=QywE}`5QCUP}iIPA_2%@r_prApK&4BcWs0g?b z1!ZwzO9CmxutTbVfJ2Hv0-7LE0V60N3CI@VH{lcU zy16)LFJ8GA0HE!-*Y*GaDEJlyG}PgaOw0F&pDP`0ce#h(8G0FVdDZFFjVIf8h!;0y z0etaO{Y4ia#TeV}zpzBhe#@o$zQfzjE$`LQ54_j5KCoo%bbWojyXxCDfqU?mb&4hu zUZ!PwmZ_v}3?AqiZrMf6Q4UGD69ECq>g(RGa=qN8nZk0XDDp4OdCw8153~}T8%Q00_;Lyk!cS4^uRk{(5O(4 zjaCJ#L0@H)bnI0dfsMyO(I|Nk-@a;-Cl1(6-BLiP&e+k1{Q7P%`v z*OAcB;GH<*3RjF>_RqRT(gWN(t_QpQ7Qu7R&bUa^0`ZLg&b6HJko)7?oPMR^)}vIIkBGDI`} z&2clsswO@~44H+l5u6j8Kx#NYTRvVyQv}=$#w!M2+fj3MJk=a9_cx?Y|K>-uE^FSC zp(nD>TdA8*OvWc!ma%eth7-_EZ5H>++TCskVtUyAk--aF$%S9=641~xxXu6|g`THn zl`bG{%qQfhbyrxLzkuTI9czvZI!SiGO3q8w)MD zXC?~oU(91u9D)~>x`1a#;B0;xAW{o}Y%LTv1>WU1)`E9i0EpeX09eDj-R(TcZiJ(r zE(K%D0l=LmErq<4?RIwO8IPPl--4tkcEcxwL|4FulXj6$7$XALU zPoj7RmwX7^RnR38Au1><6SV{e5{5Gl0U3sR7sBj2ke!X-c?!5aL$J04#({7U?D>8h z90Yq7uY`kO&kd5!!s{$y^^-IwwB+oe0U9rfUaR-=Xy|J%UX24~ggJ$y?Z>b}OO=hK zmF#2(3w316Y;!}w`~z)wWM^Pie?a!kGpyQIT*ou; zt_4%v<}jXD=zw~~C%L(hofV@QObM48no8Q#KQ`_|!BhK6JEZZa0E082b7rgP-sCr? z(2Af^OVFi&-zQtaljGh=*IV?)1S{-=z8ar*-d+cFeZ|9{aZ z)MLlRI-4jQ|BAR)8aq29+Og0~GL@a)@5xWIh%WZ)Xss6G7581T--_xIg<<9{wXQ=~ z!<4?f?A0;$f*@t@cTkTwPsS(Gj|wN2gy5jTXm*lI4eeZde}a!<=ST~@|C$UDG5{bh z0BYJWoy2u?>A~WC|4<9o#Qu7B)yk z=tg;6_>-+r>Ip`#vnizl3yWcqM}hl!QP=~w{NrPacR{SOl7n3Mm7DjXV%H+PZczn$ z5PlDm^cS`Iher(y4$0kQPk69g zaSlR*&dp4N!R~zBIYG&%ePt|$;pRL-; zLZ{uPP{@zdIQbPaOR<)hG<*3IH}fizGWN|^xrXHpt|Z)E%`G%IJL*#8J*~cw7JAV{ zw_$>XubT{_5?|7fRnx}~KvY~b$18GpMz|)bSb}HSXNr$K*^Ebs$Pk>Uf+w!o=V2H(?U#9VII_McWGGQ=Iq=4l}}4zlt{W zCI7!P*;?R1$mGE3Que2tx|QC%wT7k7WCp^-uR%yI9hsD zHE%4_>TZDQW+HLNzZ;+Nw}8HU&Ua|`RG-wF_j{Oh`_!Hr15)e2=M+;&w>i?)N^>9m zMm3X>*%eA+Hi zyk{SH5z3NEw!I*i6OJ=$!V~@Ix0HJ^w-WW;6r@pE-`i^rBD6=G8p~t-rT!^8+pN>7 z*12$5!Rm&OddJIRY*k0 z$>qL(#nWFt$C)tI3UgfZiBd_%_%s1Njc&6{r_&oYP|As|*SXOt?IwM>q3WPU4IT_I zM9h5J^QE8@k{?QqJnM!^$)&a14>rg}~L zQAwpEQ^6j`T_4i+VK#R^J?47j4qj2$FA<_SSNk<9ETJQ*mPqFL9{^4~*j3Ifx)9;J z_?#z?7oG--{D9PZeOK}bf!j@gpF}z#SSQ74J`N`fQV6wqrBT5HGVW8^K#P!w20jPlSZWV zJ$DH~XKLAHB9N=MV-l+O(k`Ao*bIaIhmTE*37XE*UAMs=jMD4YoQ78yk;56jwEY zCQbqx?;l^f-vv8|sFJ>U|GZu%#glOI)p9atyNn27s-|Y!zqJ2dDqBrl2HJfcv;NZP zkaf6=cnG>~Xb@>=Xc(41MRrVF*$A@3NtMB@|A&{v^P;x4fOf2v^F#dwk-%neWVE5S zKa}&3#Vx?9eFxN1A|2@0bkP$);Wr3R)K!Y?dc1;|Z`8X3G=Ir@CAhFv_SgxbEqJ&} zvqCqhFe(7=@nPaMw`toEF;AnF1heYV${0wOR#kWdntgO8_w)ysb7su_zaK|l&cvgW zv^sA(^`qOpE*O=EC~Z<6D~8YJzm_S!L}k(m-e(d4Xsk`qH~*&pgh~{VOx4W+N*%(LvG6OBB#Z(`(|) zbpvdc**{>ney_s-FhyTh<@`WGk&;LXVg3v$uU+0V=YY)`;ib;4y0In&))^r1euGXP z9mjD0(vyX?uqUjCWFn2>e*C)k>U-`eK)D#p5vR6eL$;mNRcr5o;#UYgHoilUcX95@ zDuQ|nz_?NoL{c*+t_XH;_a+^Z+_~gm=we7Dzdr z2_mI?q^fSGrxqu$LK8tH)K4;wWlYm>2%+rUi{>{oH{4FRHg5?@Z`~8rz~c;EB%(-s8<lcRB3gB_^{NH^Yvg^xLI58JmkDK_heb6nkoe zS^3zVVQ{8tY5DrRSrE*i&bY}G&DNpzZ(~>AZ|hEzkHQkKyYKp*Q(Ql*K9UR9$x zaPo8O4oWOg^|XLfacG-$N#hs3fD7zwseI?w?ogig?yUPgGYL3YPj3cr+nyzv#tlV$75>FJ@2=sb zv(^);F1n?9)liOYj7O82y85$tg1Fl#ES3LWVYU*7Z~$mBdLPsjjah+smBan2vI zvhhLR7o9ccwNCVrdUu6H)P(t7l9v?1e;uj`H=g@cuC_g1543-8blN$5xv{KC&HOxn zKz@o51;Oc#5ZhwG!%{8=O@a;{5S#~Ygk&M_D_5_&*y;O7YyjY6W%rL#0|fnWE&kb4 z1wI;czWW6q?+y(hTELl|`x*0kzc@}fIFqw+_ihd6OV3fioQSi8VWm+-F|@6WeX>pt z1iz!S!8AoKGMqD}LdL!f`#`0`#Jw3A#b-EVg1Cw7i5~Y2%c~ojzN|zd+JE&Mc{TT9 zYnm>0wx+AmQfm0*)1jgZM_8CvEVW5iPh{BEI0z+*iV?9Fgtz=$3FcpAc+}J8Y^(7M z#|ngX{Bq-Nuq0<=I*ulU00;YeDJebAIq)HUOkG67F~ z5=Y=^V(=HRO>bYVnDSgIUYfQ5@_`7O85ADJ5Te3P@|P7-h*g?9hL=iJqY4&xvyZZ00PL z>1kXf%jp5e@k{1APufWdvauC3$r#&Q|e;{WX ze5}1Q_NF>0>iD%*MeT>$J1#rl6=H$*;M>dBD}>Cozw@Lb1k}v^g9pxGReO*ZnK)Ri z?40D1Wc8=toN7zaFleCA5d#_v!g_ChhU|B$c->CAmgqZj`s`~YmZE65%~ijq6e(#v z)&8CQG0;Nsl7tu=JE9*HN1XKCB5?LqQXk&VS7wd9k&=nylNDlQb#tY`LHqVikknez zIggz~7S>iscbkSlqc#BnZ*rzi;BA!p(oD17LJhVbQzah{w zZKC_d-y7IW{^JIjg&$V66OJDX7za;QNQH5yuoU5Fg_YGaPv->nqTKCi?B?kC@wH%A z%*dc20<)dPJoh(cKGbua%_x)ySqT~By#{y1BdoJG0=){-Z1;>@Z{z02FAkG)W1T+b z`l<|ZsNsdi>B(Eb2XkB8ADqtK^93LC{PI_8^=RLMacqGU5|>cQ0rwiVm(e@sADj0E z%|77ysi@Hd4=8_CI`Cb{#kXBf(O5~e;teP-lKkq1&}*Ai-}ij0e)?wpbK>(CF8CYp zT%|zwf4HK^XwvU4MN+O}QHQaX;~FwMf-N=@9eNAbi(JacQgNQukF@ZtV@Q+r@!E2i zqEgBXW_nChN_m8{D5=o8TQpK6{(UyKv3tXkM%R#d9-fknRKIHYlS!>6-TJS#lg6sc zNFL!D(Ah@`@z{|vkRHiqA)z+8qB{?6`ThfG+J4rvpg7khePSbo?3}9^>`wL#XIY6H zc}q+7Vn(mz-|&8CD<5Qr$Sk(cAG8iz=Ff>;C@8^#zIi}NNAx3>T-{%c*8f>awi_G2 zt9jYpvv&91gopGou92OulgESr*ta}qYXp*dm>DLEN9WB)^k^|5BRnZYfK`uN>~3jF zIw)yLf`I4TQiR9WUuIk?BNro-fS4gJf5HM?u*7m?skmFjIRl{-;1k89G)#k5`!$m3y6LrU}BMrq0HObjjG zBV&M~gKD*)1VP7Ysg`&Bu9+tnPiucw+Id#BNF$q?2+Hz4G5_cZBzCQnS_#UXqrit(+ou63j=<0;Pe(??z!q@2^3vmc6NV$)CVa-P)4fbRct>{K{+|sx*r1^_#Edwe=SFD z$W3)75&qF>@aJh7y4fSkV2|i)@Jd%JR{&1%z}E+^GjLgnGae*}m0YW3T;Ebze}EtY zxYGEh9unM*phMQGxN@tj2v_)Y^NuFh)>X4Dw%Ss_$)j?sS?Nbo{SPlnYZy@EX3+(K zwCzS>V$WhPIp~>*!lDC7C;aW1eqxq`=Z&Ey|K$G?Lx@$Y$YM-7kHU!S#V7DeHpGCI zPH%U8sF}39bi#VXrrarwLeeN07`EPR(d8<*8Ql!%+nrV$Bi*@mf`H%pJ-eE)pAgZq z5#xcv(mG(JA4V>FKb3;AWt(l9I<$+bzxd28KYFQxjF@=iW`RX-W^GuXPw-59sj z_La^ZmksLw#`j8_zinDq%wVVf$}LstFH0JO>8GRKMuu$r_M#c<&^r}tFj1Ouo4XpP zi8QGcg+B=>Dz)8rucuRnRWGZR_l#b53SI8xE0p>|5qJ3dp2Bi7y5eO5U2IU*Q3lL* z@T23LXWz=M&lO|k;NZ6APXy3v;mo%6u^7FM-FX~EwijZ=(Fdh6@me=ve~qhR4!ICR zy&ZX|lgMEd1H^eYaFsA9E*fKW*&y?2_{YnqT4!%e8-4OmBc0j5GiIclz(~JikEJge z+YXrM-yGUGQ57~G!m7ufgkZ1iKe2B^!Bm~>#RNdGpVIX7QTFtKj}@FM9sFY5X0{<5 zayFi*_FCea=-ZI5ZhcIWC0@so4+nouIag_)50<$C z>Fh)UcBA^`+K1xgY503>gj%~4GVKx#1G($L}{quivY!%PKU+a9^bW2!kIqr>^ zh(CJdad;6gDMovXsh??|xmitn*cvpSLr)={T;bW&j^(XNdL+ zrCq1qg^?^}3vXCFI(Dm+Pl*#LA8*>#R9BI#RQ8WG1E0=rJ$PK{GAsS3sf!mm?QnmU z3;W+oG=CG{8hiyCckcOCGY!SEW^NkB**rXveYlP?+G za5u@$x?jK)B}tm<1A;6-LOS2`-HLk6yO)Cy=5SpEz1D`JUd0XskvRNWJGpB;IQDDV z8!Op?cljr=aby|iIv*LV>fBd9e81=Yi6FU-&~7G~p<9DLQ1{lnt8$^@L5qi*EDCsT zxs*SJq|$f*Js%1zO@9hQivYmq4XCI~c5#v599{gZXUn`yPjIID(@ffymHSx)JCuR{JeN?h z;L~)~+6icYh~ABgya}_D%Pbu?oSF@L#?`%A08gtroaUbN2g#|~>ndMa^QzvRXuE)k ztmaCz_JcDmKsCjv{p<-NA5IhYovNs@Odv6^5tYe()10nZ3chA){e;XD)%_7)<}mJ3qh#C7N%})SC2Yp+op-F zMKR9>>2y%yLrsL)J}QRbg}u1oUcZDkW$_zSwB;E`))t)On+6H%@QFsKum&+J9F~u4E3fs!c;kub(N^q`RLp0ug759|X z87_OmT-j0-g_HTy-q88}tqkpiwOJ5d|X%+h(^p0AqQCkncpX_(tx!V=CZ$zi?T9vWE zPzd6NFHJ%hC%N_`ZD^W}(|Xi|)?ObX-?GeJ%3uUiM}F!g2yYMqsCr=al>O~MznB$) z|4;;_F@h+F$XAQ(-Md3Wf8%Xof4+>mUwQOE67#zfvzQ-D$I)q|EV^>2DT{`tSYBMQF7knJne zLN0`IcwyWD^7`9vO8kM#pE3i-@VH_V*O~hPK*E&0KS;$htzlt7K9|3zz*Br4;>{rN zr>Trz^&F;7z#&4^6WA9wr)er3w}IX2FMI*=X(tkw3Lm|gEq_Piff2z7f=e^=SArwn zz7g7*-m4#azv=Yt47y7@vsbDY?@T`u^<69PAi*PH9^|N?pk^=<2C=5;f8iE* zW8puMb8wk(Y7=PBcvUVj9hvkY=9!|s1mRcFT)*IvLUP2fP(OAJaPp2)r?==@!SRs3 zp<|ekPxuF$A+w7dOJ^vs&~&fgU&k=vlrO8tbCLYtJ--9aJEMNui2NMxG)Jk;iKnDn zr*))`uy4uAK93nI{BT8>Ewl2__P<((5(eXlXug04U367*rfJ0XK@(RB_OpzMEa+Yt z<^Uyl-bEq!3azs2^2Ie6w| zsqSAEv~#nKVKb0&`f=236h9kAH7E;9g;Wsk{S5aFO?J%%>o=)U$NX1kL2<+TZz*_9%Wr zlQ_yg+G8HlS0i*8asH5r{anR(oL5>luXP}>t~lZKfvmpoLm0c{AP;n>t0vy*auaV3 zZU4Tld=bYu%tjMW`E`Oc9&T-`LfSutic!ak+3lZl?42y@c9U@ftn(eM=(`@S5A?EQ z2;Wh=Qr~IkG_?mD`0*Qgyf2YEsa@4boorw@?!s3xEx~)L-=B(uOsa!GARM`twFvUy zCe%Nh2buhPBTkEZ!wV7XJS1M@Q(ECVz8*+yk)f0L^n11!4rg@C5z~AG=zn={RCH|b z?^u4M&5GAuMxJSGQHxw5A_Pmhy5otBitiE`zKZ{zc>USTLPaNOr)2a~QuU`RWaIY2 z(d$$5*te_fh;4iL{2yfbe1Rqjm9{@cTv`fZB5F?&82lN(2V-8cGsMC;dH5dV5do!( zc7os=wtwnvzUvF=epDecbTArpT5P7W34MQKVf7=yz7sb|W@bU@E#Y%{ePjtkMCA8* zTN*NV==dg{O#o_XF`7=A4x-1an9R@gVadMM>CwZ|7gTLaKe{rPkctHnaXb}Y@N!;x z$baYMoPBdynwHU2qx`H3#96#83 zXUw8tMBaUt+A%O6gi7Oia2{&{tuViE%=u&kfj{7^0g1pjNW*IM>97|+mn?Qp@&+cQG-jXx6fH7q}Zx zj+j#RJhEN~!Npc|pZ%lX8u`Z~1eI^MmV+y_I&8@KI=e|f-g$4kziz{a=CuBpB09<1 zHXusdPx8_haz9kZBEp2Nk;qm_<%gB*-^jiH#tBe1`>0$_>v7b_&6goCFWrY?oRuGEtc#B^ z)+98DIWBd-RF)Y=DBM5A((v@Itw+v%kQEGeX`Kl`15+Atni?yDYVR#cq7MlNs^?A5 zzRp+wA&YTJs1~g^vOO5rp1QylLFtTUSYKI@&BC(4{mLQjNJ;Fp}8Gj|a@lLuL^`4r4Jm*Ev zpPN>u^Xey#qnXHD)nQ>J%nR=3^cx@)O#df-Z1@sfW(7BiFxVc9p%0B2TVO<3Us(wI zmabYB!kp|0N@GjK7#w{lWMYvOr@6r-LxALRn`K_uGdPOO@T)3LDLRZYBHdo7k7o5v&jF^=Kl5AeeEb#*k7eaWXf##3dcK);t#4oOH(BI4dG1G8UhH z$)q-8bnubL<6b$mG(*5eHJZVTS*BM@sL3>9HF-c*x%uO^F^iHkcQ_p$LbmX6aT7@> z5%`j{$oATY$Q%-m@xz``N5Jz6AfV)zq+apn0m7u&(eH+*&3#$#+lh#Brb6feT!f6F z!*7x(&EcWTuI>`bFLje>hS|9H!;;se7619opHC<68E;jGpKNpbk<2DxztQls11ft#8c4^IL16064N@j)J4Z(8a}nx`m8J+QdnMJ{MD zJhuL*Q&V2xGw(u@$w^=Qhsf49wKS~>op2RoPdFfxNV3iljjaF_#EKUIW+XldCs4@p z&o2e)`*~kK9b+ckyeuYDW4#gizLck{I`Aa7hQAAoTrGc>Ve^x}3q02ehDk4^0eQu; zv;Lw}jRcz|y57R`*y3#SEI#+UzBP-)On%lM5)&H3-FuEn6cS>(1FznDKadHlmcBk6 zPER-#?6(0$_+>aYL<$K#tpB#O@ywh&(O-*O^Py|Gr<%Q*dC-5r&t&7MIERGdf#i-4 zsW0-2PS%#)R9#BPk$Xz%%uMuQSRG}!VF-RSbr zp6&W7qQIJx)&r!ZvYb*7Na4+alTV76sjUIkZ9L+ zSbj!UejvG_zShNoSSJfB-cYQhQG}3x4%CsC-uf)4NNCS-W-sO76;G3mm{i-oM;8A~ zk3!{RS7E&9hJ?61FH(rLC%NCz*wrt^RX--8$#r6%wY>rU!n$Jhg!hzJiYmidCPJqY zt6j_64;J>-^HX(laq#y(bP(!qPL(^iEMkM|lacA9!l2pjD*{iBv8XH#|5;JD{Jt=l za;2|H$+4yM*=h2^GGS7B7+b4)LeE}Jz`e@VxAo-- zto;W&n%*5+prwh>U>gu(?M&-9|E8(^Kd?afE_tu-A^NI4?KIvNorLdjaj8qw?Hj>j zXl@9dBBiCR%Y7XRrn3{OXt5m~9LM;&>NsG^UHCVWLDIhxB|6J06AU-wn}Rr56gbhC zh$D3gZ52?NhGm%~s{j&I@n#kSD62(o$2m!#dVfY}G1t64ebE@L2J^2V4KYgxIF$Sg zE5v1q01(0VsVQJXwadPT;?wXcAf*&mKFaT1E)gK|zt}u`^f7?7AbPyC>h{XbK*i)$ zQH|>H2S9N;HKL(DIJ#wb)Qx3ZBk5Fr=OnZ#aM`Tg@8aQ0TiAXu)4(2@ZnWZ_j4Hel znXm&_AG(?!KQTpsI&9?t%2CgQ&xj|lWPiJPZ5c^F(f6u9d<2hF*hdg zOY?Sj*V2ctncQTAw+39AOfHKGzI~6ag;Cd##mCYIzp3_4-AR>S+66{ibqyT2x!SH9 zi!tqVp0~9K!m#K<<^DcSx`wP64EL!-Od2CB1hBw#U)zu8ZGIq?ebhST%txisKBfKX zo=w}ne<{hT1>eeS-K>Y_6?yHUC$EsEGzh~!D=-$}= zn^A^}p=yB~g$e3d*?JJYhI=`_@Zh5&;ger{RfhG7lYiC{V5i z!y1C3+iN+Vu79NmWOn}iBt~7eOco^x+$h9&E;F-Ze)kEDZACNAgJ_|TE^G;%{07oh z{g)&?eDSYLGp1ON_D51YdMAokFBYs5{Ut!8P221=77AnbbQ#B2Pc=AP@PtSAbRKEh z`O=d4tXzk~MmA~*_VOIKuj}Z*nNiTgATz%f43VR_@xsQeb<8^F>-D|JRyacqRajf+ z96w7eke+s88Y86&PWF1~-pg%OkK%GQ`BEj629HSEESH(+!tWgQahn;@D+giS!JCq{ zcMLSL=f4=o<%Oj2HFucHj6Z)+tD{S-;AgjX!$p{(l`E#}$;2;C((pXEb{#B8HJms^`-ktYiycVd&WeG!yP%V-_EYbwFZ;RooEajfo94q=6 zS8Z!5Le?)HJSYoMqJJ))vi&yO$FtmtNU0;KRwc53zn-?&GAh*teQm|(HmO8A7w*i} zn)CNMA3NI~8jEJ*?iOi7tcyzdQ7wxrG1CxVi;2<206ExZz!{0O3Zp z=tKZoM+zlsntVVFO-z0bMiZ{+{cWcZKG2G!Q+RF`($%t0r+-V#9Qz#w#d?0}c}Svs zDCFE%%sNQJwgfgOK2m9WY7g9fABP!9j=GnJqu)_s%qjbq`DsLW4uZ1e=lJid?FnM* zUMBS6XKXF^WyZwi1FD3d0oDXr^PA?2@e5iwoYwS~cfk1rEcil!Tx%3S1dK_u zOWs8KVJwRvLc5DgK)0XtBNv)>p)MUPWE-Pc9t$~lSa zUP!X)WtRf|w^yR`76fq{iRsetF=ir}l9CZ6Wxu={E;(jJx-hrbXFEg&>Vk-BSbsAa zs|)RQjb8WqG#ePzybiMma$xv~B^(Tor#c1;t`bo&PG0XC*amJ-^(8jQv!)Q0o*5=2 zG#c9d&^bJc$FkbgS1$woNb`C9$ zLF%+#O>5tZoNck|OJMTyZu!*Pdcq!?i<=bi85Q`t2er%ZO*{V>NFTmzZo^cL~fAa;@i z9O7YtL%ce?yPX0i#BvzQ=dP9ai(d)g<|Yoq2^^(QC6?MYPO&M-l3Zn$Z-P69F$PIeF@$zc{ye4tLlb zuG)p@ z2Wtd!UQ{Gk4^5MoPS_P05k&LDbyqM-F@&wgZFRVRXCMbm8$J*k%5rl* zMIv+zRQM_eyV91lE6j| z5N1Ws&By1|1$Y zS5IR(wD|w=UsqtY-sY&hvog26iQiU&f=5s@A_3@k7x#Lr>uFc(ndbAC@g5y7m51yL zoV-UbCtUp^0x)bsJReR-LU4VxTk>(FFt=&6v(h3CpP(e&2c==Bf9;?zEeu-6(PW7j zf<;T&n>fKyj%_~y;y(zzY3ng1L&0oK(aGMOt+`(luvr~SoNYsV@Uo62*-0m!SHOf_ zL)QS93MAF4Jgr+j0Y(omqi$E2Q5d(wug|DVwZd2HYfTpRt7zS86NHJj2h8O<>E|pk z4wu=bXXX2Ql9>sn(Nk6M5;hyWDU+e9ZTZKDh~|R2k}TaII*mDkrrYrHozg&@8wLXF zUl0n9Q)C@|VnI8HWmxy+H8`RE_XgLSUYSrRB)edNvF7wSxJ<$uoYj2u54Y*UJaU8BfvZ&?aVX`^kUvvnddQM5_Z!sr?XzG`wueSZ)|SsQkkuMn z$Is$-PRVH)GsQmB)s;1j6y}H3?lojWT$N z-f=#J>qb&J*al$u<*xus!JteWSc$u#3g3gv;&tmV^4 z8puqIn2G$Ggijn|G@IQ+jI)Q2#1)}B8~B+zK8Y= zpWZWafHOtyO9eIj3MB11++=3&EgF|wu@oYMBj)y_%M%#UZQ8TU+4KNby~M(eV#n2> z@QUvm1CYh2U8cpBHX=C!1y(&q{Y}-Lm(J{aEX-IdSAt}((G?Lk=RH0KZa|Lz1DpT< fk^X7-dzMMrk)b+Iw+GC>4FJzowV~C@mf`;o%69@T literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..04135187e241578c4fa4909b2d37058ac5289e38 GIT binary patch literal 3637 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..62e35be3072b81af5661858727e57452b927558e GIT binary patch literal 3650 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..981cf74dfd8b238a693a6785561b124fdf904137 GIT binary patch literal 12436 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..62e35be3072b81af5661858727e57452b927558e GIT binary patch literal 3650 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..981cf74dfd8b238a693a6785561b124fdf904137 GIT binary patch literal 12436 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..5460a3836a1c743caf0caf94d159f9ceaf2f08df GIT binary patch literal 3638 zcmbVP4K$S58^6Y?HVK<(Bdpzx)(oYvg@#QjU*n@0JCh}~*nJD_NHM}}|FSEUN=7M+ z#4^KFrV05hl{BQ4G38@y7~`Wc4Gm39_P*`eb9VQfE&IRcyw9EYy?5T{-sk!Ke)oA( ze7xPX7A{{10MOdD)zuFGHTY8vESLwoKx$DKe6HH&>asodqO>RKxKYfC#vj^@BQypG zbk^76v?F(Z!|R!?yfc4Z{<6)xsB5yEkIPfE*Zn%QWZhGpgk8IKvDBiquV4G(-iN~J zhA~e*p8d!4$-G5tCFUtp7)3z8fm$AtT!1}+?I^mIFzrgn{rS(j)WeZY^{F% ztxdcrEN0c5}5_ z3HkY=L0;FeiHH>z_gt=OEN6S!8ASQ9Z}iL98WWb>!p%*`LvXfrJ<5w&VyAJ(C~oJ4 z=_4s3Qy3WPm+v@DFO5`QEnHl*UNO;TjYPn1&Lp-hU-%GxXqXa1fp z;*}_W{z$@SjTit-e^P(1d7WFWZr;nW6Md;zY|F=8^PISiL*nY(ZXKElvBkS%c#dgL z$2U^&>49ku`7+;}#=s%qJRht#wg&@-UejhrEgUW!I;DLDI|yUQ*? zYj`5rV$L_D)=;HWgFrPYH?Z>Onue?|l!qOxqUhY6VhI*`2K%Rf|VCi?Tg7d{7Tes{j>jS zS)~R14l5O17Vs8LT*p~jrkVCg+khuum-BLMrFX=5%Ht^FTBiVq+O9IaR0Bbqtm#!@5E zanY+Q35&BDO#)B8j@(h%MnD0(5152HYZpmjk3J_MLdbkcs{^9Y@^ z0a$zoC&3Y)NH1egPFeGwid{>0|w;}iLhM)9B#daIZuWpK*l}iy(aL}RD&apwc zrl4?eLpj7JF(`dLA-F)_RW56vSuH9irJk8?XNAms&oh1AT|8LcpG#&KPwO`1_)SR8 ztU!2Sl6jSrsE}b_)Ft=#z-`N(S(*9=~SX@st_s1QR`EVU4 zT~$K`h+wE$fG{Lwf#T4bHg?BJnQ#0{We_1^@F|y?W|ZhPb}f@eCFDHPyfkn&XvUw< zl8UETWYHcE#_U!kWNHce-yq+c@r7}D6w;L>rdoaFUmgDG`0qU(o;;?hU?=^L*sqK^NyldU0&koGE z@R%!-+*|g{s6OJosk4=YDNnfc;;V@`{%*e$UUk$TLm9mZ%@Y-Cwcfger~u$wU7)uP zA{>iBK?6>0MnM8V*#Z<(z*+w-hQNI@6f*#jKR_Xdu9e9oCmKbURmP@gi7N~JJli2d zy96ayTD1Ggw)}#t3`tgGHTB0VMa4H9zvAOXQqMe}t|8%?M!hs$7&E|DJ?4xqR0Hucjlj!Dw%32FNNf?4rNJ7oP8@nG224xPK+}8Me!rpU7 z--THXm9f8*xWhwO9ID9smZ%dGbshJHO^GiM`g`b}3t(?<`UV;9Rc&iY>q}x4BxM#! z@g1YZ1xW`xpnTlZuC`I#QAUpDthOZB)9qG-mR!#XE_w8_cVGL%q46uX4OyC z#+eJDa;jG@i#i(0-k448-R0~bQ2iIUlaPX@xPSI?vGL#joa|$ zOAu}QDj65cwjO)+roT&Y_&f3C&L!4UG-Nn@+^}+=xQju|7q_y>iI2;cTP1F78CP97 z+GEX*BbZcCrSDndKZcpE;Ihf<;g}mGlM(}%y}>e3U`hD;)00~)8?hevflrY{J$zmm zX5Yp*FO-ZR6E+HrlVkRv;E>}#X|r1k?RqP zd>SKqpng@2IbrB2@FaCC{)hiL-97+xlY4c+Rd{1%00DQk$KLzRve4HD>umPsW{F)X z+2Yz*{j)O`aYURGN79a+y5lkHZ4D*NF6PC60^xPEwJ?Y~n%vq84Z}sHgRSOxKaada zK`rA?W!Z!SZ0YwoH*b|uxcS19cs3~_rmmQgm|4rwUzS*6tJ2;V`F})oRwtKhkwaoX z#3cpd*wgpOS%_88o~QfchxKjoo{3ET=0@!zW$CN6)QP4~5r*Zh!vgk_yW=yCB*Q4< zUJfa>&!N4|I+n>Wd*aKVRv4H;rEt*z8VewQebk)QV6nDrJMf{y=*?RS^i1D9%v2;^ zUCnOfZ2#g@WcP`CN(4Rl_#@{^mC@Nd1a0YKRY>A8*}A%DCiBocFZ91*NFkF#FzF}YJC zDO}*38eL0mXAM@HR4jCBw{hxs?Xc#ED{5YP1#pcXd(XZg*N?dOx4Qem-l($|i4zUtu6C^KwD`z%NAKacEJZ6>0OoGpmM8O()N=-f zIzL10$b=P>rK)Olpi|z16i&-p%zMkQ3;I8_#Z#0gJ9Cuqz-CO{-@od)4yky%-EhI| zniNF>_+#&XmFl_c{3WgV^w)c9rrG4N@(#DE@GJwC*Y#Ps74K5w>0~MEF_s&MLn_Pr zw$v@2!qB_X{MQ20a=6E2Yj7V2^Z!f}P&FYuUcGbJREP}-CmV;eV)`Nw-hru9j%P5lQ5oRFkTnFywV7o_3t);B=B|QL1M&#jqqE>%KNiR$1%VR vM*d$fT0_}ayPo8v{tQck(+&TAW#lEP>)4#%^(4~rZ8o=U_IBlbwe#@rAq{(^ literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..981cf74dfd8b238a693a6785561b124fdf904137 GIT binary patch literal 12436 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..5460a3836a1c743caf0caf94d159f9ceaf2f08df GIT binary patch literal 3638 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 literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..14206c495d0f1e63c8b24667f576983bcb44b703 GIT binary patch literal 5248 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e59d38f3104fd68bac1ae9c8f93ba04a28087 GIT binary patch literal 2158 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e59d38f3104fd68bac1ae9c8f93ba04a28087 GIT binary patch literal 2158 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbbf95585cec6c98d374ed443e2adf3ec5c44c9 GIT binary patch literal 2170 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJC^M^6{Wkcv5P@A!A8gv%a( zXmD9^!2}K`F(J+$QcAl{7)i%Fi0u;-FMlk3q4h#EvmV#6mW9Et92=cGEDrXS7{xaG zunDS|xzxnF7b;cnUd;`eXUZ=Sa`-&lTr-an(H)3;~G zyX3sGRq^Fu2s+N_@XCV0LzbOkQh8aQ(lUNuSd^j0AnHU(Bu{5Xv-4e{?Fo_!4mOM@GueVD5ZTJ0X+ru9U zS%K+Rdn!N8?T}qNf1lvSt5wDNS?_E9z1Z3zTl)(XTzfaa13H4?0x)107(gMz-~b95 zh8MuFVPF6S4#NUa=rEK3!;ql?6o{lLUXXv^Aci~gQQPO=t~#%5+S}F7yXS7bS0}J> z#qO153=+Hy3@4-++<@kOVr#evv|{tB zo!cCtv(8=jmCq^(hF5G1rlNEp8&vl0zV|2R)IGa@pQ;6KfB&oh`tbU)-5q=DzuPPR zzHDEn7`@hfe_zy<&HFwc|E=#147vMXZh!aNFTL@Eacm?*g&8PLZ~=z^h8x8cs!%f)oadk*zw4>+J5a^iFK`SHUZFnCR#|X6KeQuKTqB_@~OMQt*pI2i|=eJZ~E50Ah-Ej>6K~e zw>M8%yM2H6jeYy~ug=*R5z~KTsXZw9I^3q013`fitI63z+w_3|!nKpASq+H1Eb=$@aqM{eWc!=K+9Wdy$8zqKuKM;W-hLkhQ9 zzqc(06@>TzNH0Elpq#^%-}$--H4Xon7kK}AcF;v<#rFLFzuN`7t^8BgE|k5wep-2a z$BljOFUB*h5CfK|aRWk4*tYocar@32v-9=Vx#!$J@BB&&Yt_n!uiizHgcc0^p2AF! iIvGh0USVIU`pkn(i(b6Mw<&;$TcBbP(~ literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..14206c495d0f1e63c8b24667f576983bcb44b703 GIT binary patch literal 5248 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..fbbbf95585cec6c98d374ed443e2adf3ec5c44c9 GIT binary patch literal 2170 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJC^M^6{Wkcv5P@A!A8gv%a( zXmD9^!2}K`F(J+$QcAl{7)i%Fi0u;-FMlk3q4h#EvmV#6mW9Et92=cGEDrXS7{xaG zunDS|xzxnF7b;cnUd;`eXUZ=Sa`-&lTr-an(H)3;~G zyX3sGRq^Fu2s+N_@XCV0LzbOkQh8aQ(lUNuSd^j0AnHU(Bu{5Xv-4e{?Fo_!4mOM@GueVD5ZTJ0X+ru9U zS%K+Rdn!N8?T}qNf1lvSt5wDNS?_E9z1Z3zTl)(XTzfaa13H4?0x)107(gMz-~b95 zh8MuFVPF6S4#NUa=rEK3!;ql?6o{lLUXXv^Aci~gQQPO=t~#%5+S}F7yXS7bS0}J> z#qO153=+Hy3@4-++<@kOVr#evv|{tB zo!cCtv(8=jmCq^(hF5G1rlNEp8&vl0zV|2R)IGa@pQ;6KfB&oh`tbU)-5q=DzuPPR zzHDEn7`@hfe_zy<&HFwc|E=#147vMXZh!aNFTL@Eacm?*g&8PLZ~=z^h8x8cs!%f)oadk*zw4>+J5a^iFK`SHUZFnCR#|X6KeQuKTqB_@~OMQt*pI2i|=eJZ~E50Ah-Ej>6K~e zw>M8%yM2H6jeYy~ug=*R5z~KTsXZw9I^3q013`fitI63z+w_3|!nKpASq+H1Eb=$@aqM{eWc!=K+9Wdy$8zqKuKM;W-hLkhQ9 zzqc(06@>TzNH0Elpq#^%-}$--H4Xon7kK}AcF;v<#rFLFzuN`7t^8BgE|k5wep-2a z$BljOFUB*h5CfK|aRWk4*tYocar@32v-9=Vx#!$J@BB&&Yt_n!uiizHgcc0^p2AF! iIvGh0USVIU`pkn(i(b6Mw<&;$TcBbP(~ literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..14206c495d0f1e63c8b24667f576983bcb44b703 GIT binary patch literal 5248 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e59d38f3104fd68bac1ae9c8f93ba04a28087 GIT binary patch literal 2158 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..bc4e59d38f3104fd68bac1ae9c8f93ba04a28087 GIT binary patch literal 2158 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..3dbbb594233a820b64cf3c8587ad86df627b61e0 GIT binary patch literal 2137 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJC^1y2{pkcv5P@A!A8gi9X( zXmD9^!2}K`F(J+$QcAl{7)i%Fi0u;-FMlj;z`bxgmmb%#mW9Et92=Wm<|MdV&0Obr ztdWJ&=R)BO`%nQEP3zn9+N$^3)V_LBX&3(^clWuS+h1*d^L*ayo4eEf>m@fneS214 z$?Ut_q%;d-I!=$*AaDPCSU%%8ucXi*UR%=a<|^Q(|yBwzHOCmlKXs{8q=h}_iJK+k;(uH zABF|M0HQMU%YSp8>rT^lJp5B9*llz9;lq=k1*6w)mv_^i3=m1awsk@cpXJZ@KU?!rSpt}-|ET8Ows!pO zd|_MTZ>yx!o8LyBxOV$KFnI6pU!AitBBuYw(s~(SpgG*9pA$g=606DZT>taQIdko9 z0;BkN{gF3++N1dt=KlYZoBQ|m-2C}FJ|5%&+JYA>4QJ0x-y!P>zf2Reb*KJ?j;d)oQc>mt74~}*Nb8#ALLw-ESd9)}=rZW{(6n**w zEOw2=rThB%7m1ZF17&2TZ|Bti|8l%y_a|w4_l>N*yf;6+Ir&=9+Q#O89GmW|zu&JJ z@Lbp9Lk%^D^80UBpbBB|9IpI+uZtmyDj@LnUo|(X5CcPr=Y5+Q9jsr!y{-RmkQJET zwaR>p^6#sk-f;`w{%-q$Aj&(LqawVaXwK vs5=Hc>>$6WoaJB$ddQ$4%7;lUxc6KB;TijtZ+<&J1BH;MtDnm{r-UW|C;EE( literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png new file mode 100644 index 0000000000000000000000000000000000000000..14206c495d0f1e63c8b24667f576983bcb44b703 GIT binary patch literal 5248 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 TqFDaR>tKIlK literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png new file mode 100644 index 0000000000000000000000000000000000000000..3dbbb594233a820b64cf3c8587ad86df627b61e0 GIT binary patch literal 2137 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJC^1y2{pkcv5P@A!A8gi9X( zXmD9^!2}K`F(J+$QcAl{7)i%Fi0u;-FMlj;z`bxgmmb%#mW9Et92=Wm<|MdV&0Obr ztdWJ&=R)BO`%nQEP3zn9+N$^3)V_LBX&3(^clWuS+h1*d^L*ayo4eEf>m@fneS214 z$?Ut_q%;d-I!=$*AaDPCSU%%8ucXi*UR%=a<|^Q(|yBwzHOCmlKXs{8q=h}_iJK+k;(uH zABF|M0HQMU%YSp8>rT^lJp5B9*llz9;lq=k1*6w)mv_^i3=m1awsk@cpXJZ@KU?!rSpt}-|ET8Ows!pO zd|_MTZ>yx!o8LyBxOV$KFnI6pU!AitBBuYw(s~(SpgG*9pA$g=606DZT>taQIdko9 z0;BkN{gF3++N1dt=KlYZoBQ|m-2C}FJ|5%&+JYA>4QJ0x-y!P>zf2Reb*KJ?j;d)oQc>mt74~}*Nb8#ALLw-ESd9)}=rZW{(6n**w zEOw2=rThB%7m1ZF17&2TZ|Bti|8l%y_a|w4_l>N*yf;6+Ir&=9+Q#O89GmW|zu&JJ z@Lbp9Lk%^D^80UBpbBB|9IpI+uZtmyDj@LnUo|(X5CcPr=Y5+Q9jsr!y{-RmkQJET zwaR>p^6#sk-f;`w{%-q$Aj&(LqawVaXwK vs5=Hc>>$6WoaJB$ddQ$4%7;lUxc6KB;TijtZ+<&J1BH;MtDnm{r-UW|C;EE( literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/pgraster/rgba_subquery-rgba_8bui_subquery-8BUI-255-0-0-255-255-255.png b/tests/python_tests/images/support/pgraster/rgba_subquery-rgba_8bui_subquery-8BUI-255-0-0-255-255-255.png new file mode 100644 index 0000000000000000000000000000000000000000..d83016d2a86753dbdbe9f03e1b28fe887570711e GIT binary patch literal 93 zcmeAS@N?(olHy`uVBq!ia0vp^{2 Date: Mon, 26 Jan 2015 21:44:25 -0800 Subject: [PATCH 65/91] actually src needs to be non-const --- bindings/python/mapnik_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 4b8e3485a..a7142e699 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -239,7 +239,7 @@ void clear(image_any & im) mapnik::fill(im, 0); } -void composite(image_any & dst, image_any const& src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) +void composite(image_any & dst, image_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) { bool demultiply_dst = mapnik::premultiply_alpha(dst); bool demultiply_src = mapnik::premultiply_alpha(src); From c8f70d32602b73aa22603a1ec7653e6e91943f1f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 26 Jan 2015 21:58:27 -0800 Subject: [PATCH 66/91] embed help text labeling expected vs actual for side-by-side images --- tests/python_tests/images/actual.png | Bin 0 -> 899 bytes tests/python_tests/images/expected.png | Bin 0 -> 1263 bytes tests/python_tests/utilities.py | 6 ++++++ 3 files changed, 6 insertions(+) create mode 100644 tests/python_tests/images/actual.png create mode 100644 tests/python_tests/images/expected.png diff --git a/tests/python_tests/images/actual.png b/tests/python_tests/images/actual.png new file mode 100644 index 0000000000000000000000000000000000000000..adfa8568b8b7b1890af131f1b2d872ea934b82b5 GIT binary patch literal 899 zcmV-}1AP36P)# zUr19?9LGyvG{k%e6*GuAR2U=-4g7=R!w~o4LxN(6BE9$|2pZyEEdQiIDwCQCBF$dh z!c|ODK`h4v$M&F6bCQZN3NIBBO}E)zEJBDlu@EeoNW)! za^~jdLZ{Q66CyYZR{=FFTefthQYjJ=5|EOTg2BN-aUzH8N2}FBCX*pPJ|3y5shFOg zMrUUyqNAgcl$3OGr#igxzlEZKKi1Cv3CXc-!T2VP$3I)Cyc&T;yW|t)QU5KW2G( z8Eb26{Cab9lluk+2Etmv*J8$Vb921%)M_;{GBPkUG{pN$OH0w(+A0n^2o&dc1r$Xb z9v((tUmuTMU0ofX0#cHfS>EC@%gM<>TU#3!kS(+B?ruJl?Cfm5gau<8{(WNiA_B5% zlSm{`sZ{9g?L}Ex8A?h@!dAd*EYt1nZA3&wU}tB?Kk2NjEWdyi6%}Z1ZpLYrpP!GB zkr97;b#)anF)=5`u)S3jFf%g~nnwo+_q2Se2SXhYp z`FY;IzP^sy+FB@;O8;RnGc&`NeR_I2y1Ke}mCer1avwXTi;9Z)Nnc)G&bNk^mKN?~ ze-4Wy*j}i$3CbwZTZHG-^?7W&zvw?a=e|D~Zwj?GK^rA2Az1l*CcX$0_(2$myToJilkp{-*)}Zyb#PdBpJ)p0z4>L0}jLXYQ7#kY{D=RA) z9vFMc^l9B=<_(n!XP*+#S0V2EF+S+O%@LjS#I5-GyZf;6fAU8J`Dk>^?e06mN zzP`Sk4JIZgu(h?NSVsg>)(N4^)z#JIabsg6L_|a=*^Q5nht}3sI5{~14Gj$@_P(gP z!r|fJ(A?at_XJ>G5aDd|C zVue$qqoY7uYHDf}ehLCRJ3AHYh!|Q&9gwah5h1s0Z*R|;LfJ}LBFW!~w-7(7Adngq zXP=#&osumZ8ygM)-HMEi3?;%T;OZbSo2<9Dw}ZdG|7)2bcy|S{hAT~CZ$8@#j&Juy{?(PaAGBYzFAt8as zv|mq8kF!_E($W%aZ*TKBEG&%Ii+W16jf5H&1%Vov5DF3nQS7A#BpMk7O-DzEvzmm6 zrq5GX7v`r1)h-_&A22mF1#@$Az9N&8ll<{iA4S$tHd4Kzh9C%}CgbSn$a|@q%4_7v z$O!MZu&`jgr>7^ANJ3;pM@MtEk)9fvkn-|!aB_0unoG@$2%|Y_Le!Y3#>umr>MA7x zU3I!CQBhGaFravyy?9CjZ4iHnlc?hn9*~3k6GUKdZ!dRf`LhD$H^hnfK}G-i`dY5P z5(Ap2z&uu{ai|g%J_zx6G6E$MjSy7Gpn-&-C~vnfij_5_6g!S z!W!`<;#j8NfLCu%I|Oy9b(wBU^5X@(`d6|n`LTeYRzH4^7z)yd2rA&;s~~QT^#3(q Z{{VVnGrhK%bn^fJ002ovPDHLkV1je&LHPgx literal 0 HcmV?d00001 diff --git a/tests/python_tests/utilities.py b/tests/python_tests/utilities.py index 45be868b8..3902e6858 100644 --- a/tests/python_tests/utilities.py +++ b/tests/python_tests/utilities.py @@ -6,6 +6,8 @@ from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin import os, sys, inspect, traceback import mapnik +HERE = os.path.dirname(__file__) + def execution_path(filename): return os.path.join(os.path.dirname(sys._getframe(1).f_code.co_filename), filename) @@ -84,5 +86,9 @@ def side_by_side_image(left_im, right_im): height = max(left_im.height(), right_im.height()) im = mapnik.Image(width, height) im.composite(left_im,mapnik.CompositeOp.src_over,1.0,0,0) + if width > 80: + im.composite(mapnik.Image.open(HERE+'/images/expected.png'),mapnik.CompositeOp.difference,1.0,0,0) im.composite(right_im,mapnik.CompositeOp.src_over,1.0,left_im.width() + 1, 0) + if width > 80: + im.composite(mapnik.Image.open(HERE+'/images/actual.png'),mapnik.CompositeOp.difference,1.0,left_im.width() + 1, 0) return im From d94f5a0ceeb014a69c1f43f95a990f05fe04733a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 26 Jan 2015 22:14:38 -0800 Subject: [PATCH 67/91] get pgraster tests passing again + update expected images - refs #2639 --- .../input/pgraster/pgraster_wkb_reader.cpp | 5 ----- ...subquery-data_16bsi_subquery-16BSI-135.png | Bin 90 -> 87 bytes ...subquery-data_16bui_subquery-16BUI-126.png | Bin 90 -> 87 bytes ...ata_subquery-data_2bui_subquery-2BUI-3.png | Bin 90 -> 87 bytes ...a_subquery-data_32bf_subquery-32BF-450.png | Bin 90 -> 87 bytes ...subquery-data_32bsi_subquery-32BSI-264.png | Bin 90 -> 87 bytes ...subquery-data_32bui_subquery-32BUI-255.png | Bin 90 -> 87 bytes ...ta_subquery-data_4bui_subquery-4BUI-15.png | Bin 90 -> 87 bytes ..._subquery-data_64bf_subquery-64BF-3072.png | Bin 90 -> 87 bytes ...ta_subquery-data_8bsi_subquery-8BSI-69.png | Bin 90 -> 87 bytes ...ta_subquery-data_8bui_subquery-8BUI-63.png | Bin 90 -> 87 bytes .../rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png | Bin 5248 -> 12436 bytes .../rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png | Bin 2158 -> 3647 bytes ...rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box1.png | Bin 5248 -> 12436 bytes ...rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png | Bin 2158 -> 3647 bytes .../rgba_8bui-rgba_8bui O:2 Sc-2-0-box1.png | Bin 5248 -> 12436 bytes .../rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png | Bin 2170 -> 3637 bytes .../rgba_8bui-rgba_8bui O:2-2-0-box1.png | Bin 5248 -> 12436 bytes .../rgba_8bui-rgba_8bui O:2-2-0-box2.png | Bin 2170 -> 3637 bytes ...8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png | Bin 5248 -> 12436 bytes ...8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png | Bin 2158 -> 3650 bytes ...i-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box1.png | Bin 5248 -> 12436 bytes ...i-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png | Bin 2158 -> 3650 bytes ...8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box1.png | Bin 5248 -> 12436 bytes ...8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png | Bin 2137 -> 3638 bytes ...ba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png | Bin 5248 -> 12436 bytes ...ba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png | Bin 2137 -> 3638 bytes tests/python_tests/pgraster_test.py | 15 +-------------- 28 files changed, 1 insertion(+), 19 deletions(-) diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp index 076ead40b..bea039e37 100644 --- a/plugins/input/pgraster/pgraster_wkb_reader.cpp +++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp @@ -184,11 +184,6 @@ mapnik::raster_ptr read_data_band(mapnik::box2d const& bbox, bool hasnodata, T reader) { mapnik::image_gray32f image(width, height); - //image.set(std::numeric_limits::max()); - // Start with plain white (ABGR or RGBA depending on endiannes) - // TODO: set to transparent instead? - image.set(0xffffffff); - float* data = image.getData(); double val; val = reader(); // nodata value, need to read anyway diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png b/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_16bui_subquery-16BUI-126.png b/tests/python_tests/images/support/pgraster/data_subquery-data_16bui_subquery-16BUI-126.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_2bui_subquery-2BUI-3.png b/tests/python_tests/images/support/pgraster/data_subquery-data_2bui_subquery-2BUI-3.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_32bf_subquery-32BF-450.png b/tests/python_tests/images/support/pgraster/data_subquery-data_32bf_subquery-32BF-450.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_32bsi_subquery-32BSI-264.png b/tests/python_tests/images/support/pgraster/data_subquery-data_32bsi_subquery-32BSI-264.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_32bui_subquery-32BUI-255.png b/tests/python_tests/images/support/pgraster/data_subquery-data_32bui_subquery-32BUI-255.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_4bui_subquery-4BUI-15.png b/tests/python_tests/images/support/pgraster/data_subquery-data_4bui_subquery-4BUI-15.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_64bf_subquery-64BF-3072.png b/tests/python_tests/images/support/pgraster/data_subquery-data_64bf_subquery-64BF-3072.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_8bsi_subquery-8BSI-69.png b/tests/python_tests/images/support/pgraster/data_subquery-data_8bsi_subquery-8BSI-69.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_8bui_subquery-8BUI-63.png b/tests/python_tests/images/support/pgraster/data_subquery-data_8bui_subquery-8BUI-63.png index 38be9e295375ffcaa96c07047683393f1984a2c2..e6fad0d0b2b9c697e4f5a2a3ce28bd74593a1e74 100644 GIT binary patch delta 56 zcmazFpP*ta=jq}YqA@W!L4tJ)^Z!N;$^NWmUC;hoC`=6FDLTvW?^XQ5{gSUAF#v(5 LtDnm{r-UW|SL7Ap delta 59 zcmWHKnxJB)=;`7ZqA@W!A>qgW`877HB=z0IC9e92p537k7-;&!l$qhg>H~fcHi-UY O00K`}KbLh*2~7Z>)D}|! diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png index 14206c495d0f1e63c8b24667f576983bcb44b703..981cf74dfd8b238a693a6785561b124fdf904137 100644 GIT binary patch literal 12436 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 literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png index bc4e59d38f3104fd68bac1ae9c8f93ba04a28087..0669f5288bcc390fcbf8044eb0adfefd8d51c41b 100644 GIT binary patch literal 3647 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 literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png index bc4e59d38f3104fd68bac1ae9c8f93ba04a28087..0669f5288bcc390fcbf8044eb0adfefd8d51c41b 100644 GIT binary patch literal 3647 zcmbW4c~n!!9)Krm&=M8v0xAml`cx_jP%xqf2nw=@BA^6vLBwLvhSg9JB1^OfrP2pf z<)Wa7qHF=dqyd4jXp2DuBA9@zQ6OxJG=PRc2yfE%kN3y(Y2Tc4XYRR^GxM9d-|xGV zA6;D>mT0ck1OO~?a

    ?00VC^V37uFd>DBF04&vTvfFhi^7?3ZXu`VF>jkn)m7DGt z&DwV65j)7}IZ>Qg+i0b};~paNmu}EmM;9fYEr_F5lHTBYuzqeD#XiwGjGIM z6i5|ovEi}{go*5bx(X-wgyKGf9)T&l$*pJba6PbD2oxG%hX&XQ>McP1H{dzOrW#|D zgkdcO<4XWzG58*&gn|@*kTstbJ)gC1K3EU>bwU4XFa!)Fz(Al38{S3~T67gk7`ih4 z2BNSpGFh+Oy-}_e;w~JCrfA;ox8|)po8xme+P0DDLOoWV{Q7B2Vu%-^if=JQ^T-rz zIRU}i0t`?7-Nr3Y5u7h3TTU~DBVMRJadypr{g8VM~|aBp~v`OL_lX*nyrb~zBT zx1>&&AOTHA!Q(b^dtP(?V=Nu@_sD)XN*~6mvJlN@8>*z|X)B8AGQ|6ug6Hzt;!Wu| zi+rlYB6ps8<_q&byJnYan~=hXb)#$2$>wqQX=tC$xJ5Vq1TC^>c!qJK&rL3e6s+=EC9e21zE{((x=P8B-{cU>O7V;48_nH zJa>SPXhL{IyeyZ+MZYF>%dXl0;tLTyt?k`gc_cO-&q+y;3F}*yt%TyRn~<8<*)drvmlYG zC*X{}|20EgSbUK1lfEnN_S8nA@P6UVC-~O6&AC9$YY@f;qsH^)Jk~rl&?Q)aRr3oa zpsB{SRvWA|g@8jH82Uk;fj4liRcAmc$YT9D0Fbu+rt059EIv81oOfepXBxXm9)5Ui zQwFXLDV=#9XhkINP0FL4>OtqaI6Jka>p;H_cwUPI3M|+fhOvpofF(X4WL3{dPrB&Zt$zp2is=F4V2F*^+syqd#bn!Yizn67SFTd!Sf1C5cG>sVrZt zP9pm1IE1i>bhI(3{r9Hnpe&WRYet-XK}7!i^ZXcDu(al8ldn|RcxLk+0x6(y$* zC>w3zg4OTf(AmW^Y~$w1-kSv;oz7#thUpz{RMl7c@!bdVs7W-1{czIoKs-u& zuWZ{2wv#>`O9^B&We+GhkEv~k;cv&*jzq*Kwy~+zRb^&E*|~^uEUzO-J`2N|We&Wm zqrW&%({gYkJH+prrgmcIe2cF!ADUTckxz?q zDQM15GjZiA2l}3lTaGnA{Oh5F{9tg@KfnP7Y&91E99yO42CxeM;0mO8sIdWnqp8LU z*iayLT;;YNyYSbWgm^*5zFlrGOG7=m>x5c;YoHom7Zyul3gSeC$x=q@UYb|1w`P0? zlblQpmPSO-Q8<-)eyKYGmsc zgT-oOFRlTrpK5}ds>sBSe%0iotqlx*bMs>b9TnvBNb)?ZS$c7G(^#JVC8|sN1C@89X10`h3!6#H$jMT+>1e(a1^sncI zqY!Rm-sG6-&VYlAEN-cB7JbkgelKdNAr(P)hj(6bZ5;1Rh`nNI*ftVt6I?~k4x~yP z)q~r}{xGNd_M?UMr-}aR4_gZEnDofZ)2bhy?egi((5{oSJ${`sqEox$!uYXM?mT3r zgpFp(^@Mscx7rS}$?P(i_Y73vB&qbLYgtr|9TblLKq{3F!S4%Veec7Rb5$lXovE}p z_ED80L}Z#zL-lz@=W+V(+-OzcQMr)bbI{?QkJU#b{I4B`UxML`ScVuCsg%*h$Eo2? zq1#%yK8}^QrC-sZ{~a5Xdj;YK@N8po!G3ahMJ`%Bka&K**gMuSI4B^Noi4SGHNri5 zm)5UV$0Tts1DQU(S(J&qeJ{$i%=aV*Wk}bypWZ$8qd#*SxGWWadME!gPS$eFs|&KR zrY?Q0S$3}W>JZ&k%E4B*ae?8Bnwiw2m14ZkB`NBqouV|1s^d)ZGd;Ln%Z+A9RVCrM z5Y)alwirpYV0(B!almKLuQSWi$!SVQLj3p+qHv}r(763pDL1NDgNJbay-BJK+LkcOT1fx;+x2&W62txz!$zXyrkk6eyi%Ok|KPph4;x0P@u<| zXH5#QMb88x{MhIRW(+r7N<`X+PE0FSu_IsGTOD}DSbtZi|NPtYdBFt}i;t!T>Z}LYk zq6fSn4zyCEy)JCU>y}_BlX}K3MAF&vH%|mhd6|+tBf9U^-F{v?UgWiOY2>iv@aDFp zF^YM2Y@o3MMV3A8Llw>Ar$rIZP8oZ0`Sv-XkCymB#s1(see<%HWHSJRdVeVz^8J7M zy@&)v4#lTKiNe{|=^(-P6T5k`59FS^6p>a-R?MiS5Pw9ctjqgk)y)gu7@K<#hQ$<+ z5(qc?hgG0|EqwWYSWpgEZ|e0wyHmW;&;Y7_Am`NEU^*{Co=6W=M0*~u*n9_bDV6%} zp@muRl63^0Ic0?v8W2$)io6CZ?KFXsZWNg) zD5FdqYoiDSN^m?%1_T%zl?an(K}9hzIt>!0SND%OM-ShI?b%yH&`a4vpS>a|~FFkqo}VD#U(LHAFbJ79Md51~Cc%A7j{ znCpP>30S3@!L33K_Rx7K^3X@1dCjuKP$XD&mbA)KyFQ2?j~lwVep&?>MEmy!&eZxb%?o%OmrP30*eQJ;UT(I>en` zgC(WuMgU}cu+s%7HH2bKfFrsPxC5YClWm924%zVECW5 zB`BVD(t}3ZrA$$byEo_LOqqTyf8CMcKi`u=O%%%}3dWT516eK%fBFQ=o^hE^JAwV& z=ZFXZj0vd3sDL!Y1+X#3;69=Z0OJfO7-|15_`Z6I9H|@eIB!*X$a&5yKYy>(FG(!R zH4_P1gc)E=0O&OZKXlNFHhU1A*@}yP7r-iITcL1aci(H0ZPRkj4`1_^*W*c;VvM-A ziChof+dAxTag?K4+xoQ%w7lacxn3_Xl&H>k{lZjpnJYgglf=AawP!3#)w3`5_S&<| z5N`JJS^gx`i4ijUv9j~QY?V=Z_4@=khIQiB#^ylXEc_h1brgnj@Q|bb*OYcT)00w5 zRqXdSbJc?<3}l>98*%o!!AzS|OdC1xGxRpb6-q)~wh5zo85vl(R~C)eA2NlSv{U zrfI{fkId7$MI7a~*eQ8k#~o4ROnp8gHkE%=I5xNNf<~m>bz|{H=#~o^L{F7RGGD#_ z6hD{Lu)5sw>M?fx?XpI#j%Tl~99Pu_R7FV?)3Zd{%ITkt zDCwW5A8>x_r{QeV`lq8+4{bBDvQ%xmPR`6ueb`Bkytgs${y=2{Ht9AsY6Y6&r=2#% z5kQ$KLkwI+BKosMJ!kO@#g(!aMJ*p2fS1Mi%y3DREO#G6+3rurRh~h6X>Zt#6$V+V zY#1r+_fT6fCHX_ge}6rHB9N=MV-l+O(k`Ao*bIaIhmTE*37XE*UAMs=jMD4YoQ78yk;56jwEY zCQbqx?;l^f-vv8|sFJ>U|GZu%#glOI)p9atyNn27s-|Y!zqJ2dDqBrl2HJfcv;NZP zkaf6=cnG>~Xb@>=Xc(41MRrVF*$A@3NtMB@|A&{v^P;x4fOf2v^F#dwk-%neWVE5S zKa}&3#Vx?9eFxN1A|2@0bkP$);Wr3R)K!Y?dc1;|Z`8X3G=Ir@CAhFv_SgxbEqJ&} zvqCqhFe(7=@nPaMw`toEF;AnF1heYV${0wOR#kWdntgO8_w)ysb7su_zaK|l&cvgW zv^sA(^`qOpE*O=EC~Z<6D~8YJzm_S!L}k(m-e(d4Xsk`qH~*&pgh~{VOx4W+N*%(LvG6OBB#Z(`(|) zbpvdc**{>ney_s-FhyTh<@`WGk&;LXVg3v$uU+0V=YY)`;ib;4y0In&))^r1euGXP z9mjD0(vyX?uqUjCWFn2>e*C)k>U-`eK)D#p5vR6eL$;mNRcr5o;#UYgHoilUcX95@ zDuQ|nz_?NoL{c*+t_XH;_a+^Z+_~gm=we7Dzdr z2_mI?q^fSGrxqu$LK8tH)K4;wWlYm>2%+rUi{>{oH{4FRHg5?@Z`~8rz~c;EB%(-s8<lcRB3gB_^{NH^Yvg^xLI58JmkDK_heb6nkoe zS^3zVVQ{8tY5DrRSrE*i&bY}G&DNpzZ(~>AZ|hEzkHQkKyYKp*Q(Ql*K9UR9$x zaPo8O4oWOg^|XLfacG-$N#hs3fD7zwseI?w?ogig?yUPgGYL3YPj3cr+nyzv#tlV$75>FJ@2=sb zv(^);F1n?9)liOYj7O82y85$tg1Fl#ES3LWVYU*7Z~$mBdLPsjjah+smBan2vI zvhhLR7o9ccwNCVrdUu6H)P(t7l9v?1e;uj`H=g@cuC_g1543-8blN$5xv{KC&HOxn zKz@o51;Oc#5ZhwG!%{8=O@a;{5S#~Ygk&M_D_5_&*y;O7YyjY6W%rL#0|fnWE&kb4 z1wI;czWW6q?+y(hTELl|`x*0kzc@}fIFqw+_ihd6OV3fioQSi8VWm+-F|@6WeX>pt z1iz!S!8AoKGMqD}LdL!f`#`0`#Jw3A#b-EVg1Cw7i5~Y2%c~ojzN|zd+JE&Mc{TT9 zYnm>0wx+AmQfm0*)1jgZM_8CvEVW5iPh{BEI0z+*iV?9Fgtz=$3FcpAc+}J8Y^(7M z#|ngX{Bq-Nuq0<=I*ulU00;YeDJebAIq)HUOkG67F~ z5=Y=^V(=HRO>bYVnDSgIUYfQ5@_`7O85ADJ5Te3P@|P7-h*g?9hL=iJqY4&xvyZZ00PL z>1kXf%jp5e@k{1APufWdvauC3$r#&Q|e;{WX ze5}1Q_NF>0>iD%*MeT>$J1#rl6=H$*;M>dBD}>Cozw@Lb1k}v^g9pxGReO*ZnK)Ri z?40D1Wc8=toN7zaFleCA5d#_v!g_ChhU|B$c->CAmgqZj`s`~YmZE65%~ijq6e(#v z)&8CQG0;Nsl7tu=JE9*HN1XKCB5?LqQXk&VS7wd9k&=nylNDlQb#tY`LHqVikknez zIggz~7S>iscbkSlqc#BnZ*rzi;BA!p(oD17LJhVbQzah{w zZKC_d-y7IW{^JIjg&$V66OJDX7za;QNQH5yuoU5Fg_YGaPv->nqTKCi?B?kC@wH%A z%*dc20<)dPJoh(cKGbua%_x)ySqT~By#{y1BdoJG0=){-Z1;>@Z{z02FAkG)W1T+b z`l<|ZsNsdi>B(Eb2XkB8ADqtK^93LC{PI_8^=RLMacqGU5|>cQ0rwiVm(e@sADj0E z%|77ysi@Hd4=8_CI`Cb{#kXBf(O5~e;teP-lKkq1&}*Ai-}ij0e)?wpbK>(CF8CYp zT%|zwf4HK^XwvU4MN+O}QHQaX;~FwMf-N=@9eNAbi(JacQgNQukF@ZtV@Q+r@!E2i zqEgBXW_nChN_m8{D5=o8TQpK6{(UyKv3tXkM%R#d9-fknRKIHYlS!>6-TJS#lg6sc zNFL!D(Ah@`@z{|vkRHiqA)z+8qB{?6`ThfG+J4rvpg7khePSbo?3}9^>`wL#XIY6H zc}q+7Vn(mz-|&8CD<5Qr$Sk(cAG8iz=Ff>;C@8^#zIi}NNAx3>T-{%c*8f>awi_G2 zt9jYpvv&91gopGou92OulgESr*ta}qYXp*dm>DLEN9WB)^k^|5BRnZYfK`uN>~3jF zIw)yLf`I4TQiR9WUuIk?BNro-fS4gJf5HM?u*7m?skmFjIRl{-;1k89G)#k5`!$m3y6LrU}BMrq0HObjjG zBV&M~gKD*)1VP7Ysg`&Bu9+tnPiucw+Id#BNF$q?2+Hz4G5_cZBzCQnS_#UXqrit(+ou63j=<0;Pe(??z!q@2^3vmc6NV$)CVa-P)4fbRct>{K{+|sx*r1^_#Edwe=SFD z$W3)75&qF>@aJh7y4fSkV2|i)@Jd%JR{&1%z}E+^GjLgnGae*}m0YW3T;Ebze}EtY zxYGEh9unM*phMQGxN@tj2v_)Y^NuFh)>X4Dw%Ss_$)j?sS?Nbo{SPlnYZy@EX3+(K zwCzS>V$WhPIp~>*!lDC7C;aW1eqxq`=Z&Ey|K$G?Lx@$Y$YM-7kHU!S#V7DeHpGCI zPH%U8sF}39bi#VXrrarwLeeN07`EPR(d8<*8Ql!%+nrV$Bi*@mf`H%pJ-eE)pAgZq z5#xcv(mG(JA4V>FKb3;AWt(l9I<$+bzxd28KYFQxjF@=iW`RX-W^GuXPw-59sj z_La^ZmksLw#`j8_zinDq%wVVf$}LstFH0JO>8GRKMuu$r_M#c<&^r}tFj1Ouo4XpP zi8QGcg+B=>Dz)8rucuRnRWGZR_l#b53SI8xE0p>|5qJ3dp2Bi7y5eO5U2IU*Q3lL* z@T23LXWz=M&lO|k;NZ6APXy3v;mo%6u^7FM-FX~EwijZ=(Fdh6@me=ve~qhR4!ICR zy&ZX|lgMEd1H^eYaFsA9E*fKW*&y?2_{YnqT4!%e8-4OmBc0j5GiIclz(~JikEJge z+YXrM-yGUGQ57~G!m7ufgkZ1iKe2B^!Bm~>#RNdGpVIX7QTFtKj}@FM9sFY5X0{<5 zayFi*_FCea=-ZI5ZhcIWC0@so4+nouIag_)50<$C z>Fh)UcBA^`+K1xgY503>gj%~4GVKx#1G($L}{quivY!%PKU+a9^bW2!kIqr>^ zh(CJdad;6gDMovXsh??|xmitn*cvpSLr)={T;bW&j^(XNdL+ zrCq1qg^?^}3vXCFI(Dm+Pl*#LA8*>#R9BI#RQ8WG1E0=rJ$PK{GAsS3sf!mm?QnmU z3;W+oG=CG{8hiyCckcOCGY!SEW^NkB**rXveYlP?+G za5u@$x?jK)B}tm<1A;6-LOS2`-HLk6yO)Cy=5SpEz1D`JUd0XskvRNWJGpB;IQDDV z8!Op?cljr=aby|iIv*LV>fBd9e81=Yi6FU-&~7G~p<9DLQ1{lnt8$^@L5qi*EDCsT zxs*SJq|$f*Js%1zO@9hQivYmq4XCI~c5#v599{gZXUn`yPjIID(@ffymHSx)JCuR{JeN?h z;L~)~+6icYh~ABgya}_D%Pbu?oSF@L#?`%A08gtroaUbN2g#|~>ndMa^QzvRXuE)k ztmaCz_JcDmKsCjv{p<-NA5IhYovNs@Odv6^5tYe()10nZ3chA){e;XD)%_7)<}mJ3qh#C7N%})SC2Yp+op-F zMKR9>>2y%yLrsL)J}QRbg}u1oUcZDkW$_zSwB;E`))t)On+6H%@QFsKum&+J9F~u4E3fs!c;kub(N^q`RLp0ug759|X z87_OmT-j0-g_HTy-q88}tqkpiwOJ5d|X%+h(^p0AqQCkncpX_(tx!V=CZ$zi?T9vWE zPzd6NFHJ%hC%N_`ZD^W}(|Xi|)?ObX-?GeJ%3uUiM}F!g2yYMqsCr=al>O~MznB$) z|4;;_F@h+F$XAQ(-Md3Wf8%Xof4+>mUwQOE67#zfvzQ-D$I)q|EV^>2DT{`tSYBMQF7knJne zLN0`IcwyWD^7`9vO8kM#pE3i-@VH_V*O~hPK*E&0KS;$htzlt7K9|3zz*Br4;>{rN zr>Trz^&F;7z#&4^6WA9wr)er3w}IX2FMI*=X(tkw3Lm|gEq_Piff2z7f=e^=SArwn zz7g7*-m4#azv=Yt47y7@vsbDY?@T`u^<69PAi*PH9^|N?pk^=<2C=5;f8iE* zW8puMb8wk(Y7=PBcvUVj9hvkY=9!|s1mRcFT)*IvLUP2fP(OAJaPp2)r?==@!SRs3 zp<|ekPxuF$A+w7dOJ^vs&~&fgU&k=vlrO8tbCLYtJ--9aJEMNui2NMxG)Jk;iKnDn zr*))`uy4uAK93nI{BT8>Ewl2__P<((5(eXlXug04U367*rfJ0XK@(RB_OpzMEa+Yt z<^Uyl-bEq!3azs2^2Ie6w| zsqSAEv~#nKVKb0&`f=236h9kAH7E;9g;Wsk{S5aFO?J%%>o=)U$NX1kL2<+TZz*_9%Wr zlQ_yg+G8HlS0i*8asH5r{anR(oL5>luXP}>t~lZKfvmpoLm0c{AP;n>t0vy*auaV3 zZU4Tld=bYu%tjMW`E`Oc9&T-`LfSutic!ak+3lZl?42y@c9U@ftn(eM=(`@S5A?EQ z2;Wh=Qr~IkG_?mD`0*Qgyf2YEsa@4boorw@?!s3xEx~)L-=B(uOsa!GARM`twFvUy zCe%Nh2buhPBTkEZ!wV7XJS1M@Q(ECVz8*+yk)f0L^n11!4rg@C5z~AG=zn={RCH|b z?^u4M&5GAuMxJSGQHxw5A_Pmhy5otBitiE`zKZ{zc>USTLPaNOr)2a~QuU`RWaIY2 z(d$$5*te_fh;4iL{2yfbe1Rqjm9{@cTv`fZB5F?&82lN(2V-8cGsMC;dH5dV5do!( zc7os=wtwnvzUvF=epDecbTArpT5P7W34MQKVf7=yz7sb|W@bU@E#Y%{ePjtkMCA8* zTN*NV==dg{O#o_XF`7=A4x-1an9R@gVadMM>CwZ|7gTLaKe{rPkctHnaXb}Y@N!;x z$baYMoPBdynwHU2qx`H3#96#83 zXUw8tMBaUt+A%O6gi7Oia2{&{tuViE%=u&kfj{7^0g1pjNW*IM>97|+mn?Qp@&+cQG-jXx6fH7q}Zx zj+j#RJhEN~!Npc|pZ%lX8u`Z~1eI^MmV+y_I&8@KI=e|f-g$4kziz{a=CuBpB09<1 zHXusdPx8_haz9kZBEp2Nk;qm_<%gB*-^jiH#tBe1`>0$_>v7b_&6goCFWrY?oRuGEtc#B^ z)+98DIWBd-RF)Y=DBM5A((v@Itw+v%kQEGeX`Kl`15+Atni?yDYVR#cq7MlNs^?A5 zzRp+wA&YTJs1~g^vOO5rp1QylLFtTUSYKI@&BC(4{mLQjNJ;Fp}8Gj|a@lLuL^`4r4Jm*Ev zpPN>u^Xey#qnXHD)nQ>J%nR=3^cx@)O#df-Z1@sfW(7BiFxVc9p%0B2TVO<3Us(wI zmabYB!kp|0N@GjK7#w{lWMYvOr@6r-LxALRn`K_uGdPOO@T)3LDLRZYBHdo7k7o5v&jF^=Kl5AeeEb#*k7eaWXf##3dcK);t#4oOH(BI4dG1G8UhH z$)q-8bnubL<6b$mG(*5eHJZVTS*BM@sL3>9HF-c*x%uO^F^iHkcQ_p$LbmX6aT7@> z5%`j{$oATY$Q%-m@xz``N5Jz6AfV)zq+apn0m7u&(eH+*&3#$#+lh#Brb6feT!f6F z!*7x(&EcWTuI>`bFLje>hS|9H!;;se7619opHC<68E;jGpKNpbk<2DxztQls11ft#8c4^IL16064N@j)J4Z(8a}nx`m8J+QdnMJ{MD zJhuL*Q&V2xGw(u@$w^=Qhsf49wKS~>op2RoPdFfxNV3iljjaF_#EKUIW+XldCs4@p z&o2e)`*~kK9b+ckyeuYDW4#gizLck{I`Aa7hQAAoTrGc>Ve^x}3q02ehDk4^0eQu; zv;Lw}jRcz|y57R`*y3#SEI#+UzBP-)On%lM5)&H3-FuEn6cS>(1FznDKadHlmcBk6 zPER-#?6(0$_+>aYL<$K#tpB#O@ywh&(O-*O^Py|Gr<%Q*dC-5r&t&7MIERGdf#i-4 zsW0-2PS%#)R9#BPk$Xz%%uMuQSRG}!VF-RSbr zp6&W7qQIJx)&r!ZvYb*7Na4+alTV76sjUIkZ9L+ zSbj!UejvG_zShNoSSJfB-cYQhQG}3x4%CsC-uf)4NNCS-W-sO76;G3mm{i-oM;8A~ zk3!{RS7E&9hJ?61FH(rLC%NCz*wrt^RX--8$#r6%wY>rU!n$Jhg!hzJiYmidCPJqY zt6j_64;J>-^HX(laq#y(bP(!qPL(^iEMkM|lacA9!l2pjD*{iBv8XH#|5;JD{Jt=l za;2|H$+4yM*=h2^GGS7B7+b4)LeE}Jz`e@VxAo-- zto;W&n%*5+prwh>U>gu(?M&-9|E8(^Kd?afE_tu-A^NI4?KIvNorLdjaj8qw?Hj>j zXl@9dBBiCR%Y7XRrn3{OXt5m~9LM;&>NsG^UHCVWLDIhxB|6J06AU-wn}Rr56gbhC zh$D3gZ52?NhGm%~s{j&I@n#kSD62(o$2m!#dVfY}G1t64ebE@L2J^2V4KYgxIF$Sg zE5v1q01(0VsVQJXwadPT;?wXcAf*&mKFaT1E)gK|zt}u`^f7?7AbPyC>h{XbK*i)$ zQH|>H2S9N;HKL(DIJ#wb)Qx3ZBk5Fr=OnZ#aM`Tg@8aQ0TiAXu)4(2@ZnWZ_j4Hel znXm&_AG(?!KQTpsI&9?t%2CgQ&xj|lWPiJPZ5c^F(f6u9d<2hF*hdg zOY?Sj*V2ctncQTAw+39AOfHKGzI~6ag;Cd##mCYIzp3_4-AR>S+66{ibqyT2x!SH9 zi!tqVp0~9K!m#K<<^DcSx`wP64EL!-Od2CB1hBw#U)zu8ZGIq?ebhST%txisKBfKX zo=w}ne<{hT1>eeS-K>Y_6?yHUC$EsEGzh~!D=-$}= zn^A^}p=yB~g$e3d*?JJYhI=`_@Zh5&;ger{RfhG7lYiC{V5i z!y1C3+iN+Vu79NmWOn}iBt~7eOco^x+$h9&E;F-Ze)kEDZACNAgJ_|TE^G;%{07oh z{g)&?eDSYLGp1ON_D51YdMAokFBYs5{Ut!8P221=77AnbbQ#B2Pc=AP@PtSAbRKEh z`O=d4tXzk~MmA~*_VOIKuj}Z*nNiTgATz%f43VR_@xsQeb<8^F>-D|JRyacqRajf+ z96w7eke+s88Y86&PWF1~-pg%OkK%GQ`BEj629HSEESH(+!tWgQahn;@D+giS!JCq{ zcMLSL=f4=o<%Oj2HFucHj6Z)+tD{S-;AgjX!$p{(l`E#}$;2;C((pXEb{#B8HJms^`-ktYiycVd&WeG!yP%V-_EYbwFZ;RooEajfo94q=6 zS8Z!5Le?)HJSYoMqJJ))vi&yO$FtmtNU0;KRwc53zn-?&GAh*teQm|(HmO8A7w*i} zn)CNMA3NI~8jEJ*?iOi7tcyzdQ7wxrG1CxVi;2<206ExZz!{0O3Zp z=tKZoM+zlsntVVFO-z0bMiZ{+{cWcZKG2G!Q+RF`($%t0r+-V#9Qz#w#d?0}c}Svs zDCFE%%sNQJwgfgOK2m9WY7g9fABP!9j=GnJqu)_s%qjbq`DsLW4uZ1e=lJid?FnM* zUMBS6XKXF^WyZwi1FD3d0oDXr^PA?2@e5iwoYwS~cfk1rEcil!Tx%3S1dK_u zOWs8KVJwRvLc5DgK)0XtBNv)>p)MUPWE-Pc9t$~lSa zUP!X)WtRf|w^yR`76fq{iRsetF=ir}l9CZ6Wxu={E;(jJx-hrbXFEg&>Vk-BSbsAa zs|)RQjb8WqG#ePzybiMma$xv~B^(Tor#c1;t`bo&PG0XC*amJ-^(8jQv!)Q0o*5=2 zG#c9d&^bJc$FkbgS1$woNb`C9$ zLF%+#O>5tZoNck|OJMTyZu!*Pdcq!?i<=bi85Q`t2er%ZO*{V>NFTmzZo^cL~fAa;@i z9O7YtL%ce?yPX0i#BvzQ=dP9ai(d)g<|Yoq2^^(QC6?MYPO&M-l3Zn$Z-P69F$PIeF@$zc{ye4tLlb zuG)p@ z2Wtd!UQ{Gk4^5MoPS_P05k&LDbyqM-F@&wgZFRVRXCMbm8$J*k%5rl* zMIv+zRQM_eyV91lE6j| z5N1Ws&By1|1$Y zS5IR(wD|w=UsqtY-sY&hvog26iQiU&f=5s@A_3@k7x#Lr>uFc(ndbAC@g5y7m51yL zoV-UbCtUp^0x)bsJReR-LU4VxTk>(FFt=&6v(h3CpP(e&2c==Bf9;?zEeu-6(PW7j zf<;T&n>fKyj%_~y;y(zzY3ng1L&0oK(aGMOt+`(luvr~SoNYsV@Uo62*-0m!SHOf_ zL)QS93MAF4Jgr+j0Y(omqi$E2Q5d(wug|DVwZd2HYfTpRt7zS86NHJj2h8O<>E|pk z4wu=bXXX2Ql9>sn(Nk6M5;hyWDU+e9ZTZKDh~|R2k}TaII*mDkrrYrHozg&@8wLXF zUl0n9Q)C@|VnI8HWmxy+H8`RE_XgLSUYSrRB)edNvF7wSxJ<$uoYj2u54Y*UJaU8BfvZ&?aVX`^kUvvnddQM5_Z!sr?XzG`wueSZ)|SsQkkuMn z$Is$-PRVH)GsQmB)s;1j6y}H3?lojWT$N z-f=#J>qb&J*al$u<*xus!JteWSc$u#3g3gv;&tmV^4 z8puqIn2G$Ggijn|G@IQ+jI)Q2#1)}B8~B+zK8Y= zpWZWafHOtyO9eIj3MB11++=3&EgF|wu@oYMBj)y_%M%#UZQ8TU+4KNby~M(eV#n2> z@QUvm1CYh2U8cpBHX=C!1y(&q{Y}-Lm(J{aEX-IdSAt}((G?Lk=RH0KZa|Lz1DpT< fk^X7-dzMMrk)b+Iw+GC>4FJzowV~C@mf`;o%69@T literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png index fbbbf95585cec6c98d374ed443e2adf3ec5c44c9..04135187e241578c4fa4909b2d37058ac5289e38 100644 GIT binary patch literal 3637 zcmb7{c~leE7sp>f5Cy6&t*EFVtw=QywE}`5QCUP}iIPA_2%@r_prApK&4BcWs0g?b z1!ZwzO9CmxutTbVfJ2Hv0-7LE0V60N3CI@VH{lcU zy16)LFJ8GA0HE!-*Y*GaDEJlyG}PgaOw0F&pDP`0ce#h(8G0FVdDZFFjVIf8h!;0y z0etaO{Y4ia#TeV}zpzBhe#@o$zQfzjE$`LQ54_j5KCoo%bbWojyXxCDfqU?mb&4hu zUZ!PwmZ_v}3?AqiZrMf6Q4UGD69ECq>g(RGa=qN8nZk0XDDp4OdCw8153~}T8%Q00_;Lyk!cS4^uRk{(5O(4 zjaCJ#L0@H)bnI0dfsMyO(I|Nk-@a;-Cl1(6-BLiP&e+k1{Q7P%`v z*OAcB;GH<*3RjF>_RqRT(gWN(t_QpQ7Qu7R&bUa^0`ZLg&b6HJko)7?oPMR^)}vIIkBGDI`} z&2clsswO@~44H+l5u6j8Kx#NYTRvVyQv}=$#w!M2+fj3MJk=a9_cx?Y|K>-uE^FSC zp(nD>TdA8*OvWc!ma%eth7-_EZ5H>++TCskVtUyAk--aF$%S9=641~xxXu6|g`THn zl`bG{%qQfhbyrxLzkuTI9czvZI!SiGO3q8w)MD zXC?~oU(91u9D)~>x`1a#;B0;xAW{o}Y%LTv1>WU1)`E9i0EpeX09eDj-R(TcZiJ(r zE(K%D0l=LmErq<4?RIwO8IPPl--4tkcEcxwL|4FulXj6$7$XALU zPoj7RmwX7^RnR38Au1><6SV{e5{5Gl0U3sR7sBj2ke!X-c?!5aL$J04#({7U?D>8h z90Yq7uY`kO&kd5!!s{$y^^-IwwB+oe0U9rfUaR-=Xy|J%UX24~ggJ$y?Z>b}OO=hK zmF#2(3w316Y;!}w`~z)wWM^Pie?a!kGpyQIT*ou; zt_4%v<}jXD=zw~~C%L(hofV@QObM48no8Q#KQ`_|!BhK6JEZZa0E082b7rgP-sCr? z(2Af^OVFi&-zQtaljGh=*IV?)1S{-=z8ar*-d+cFeZ|9{aZ z)MLlRI-4jQ|BAR)8aq29+Og0~GL@a)@5xWIh%WZ)Xss6G7581T--_xIg<<9{wXQ=~ z!<4?f?A0;$f*@t@cTkTwPsS(Gj|wN2gy5jTXm*lI4eeZde}a!<=ST~@|C$UDG5{bh z0BYJWoy2u?>A~WC|4<9o#Qu7B)yk z=tg;6_>-+r>Ip`#vnizl3yWcqM}hl!QP=~w{NrPacR{SOl7n3Mm7DjXV%H+PZczn$ z5PlDm^cS`Iher(y4$0kQPk69g zaSlR*&dp4N!R~zBIYG&%ePt|$;pRL-; zLZ{uPP{@zdIQbPaOR<)hG<*3IH}fizGWN|^xrXHpt|Z)E%`G%IJL*#8J*~cw7JAV{ zw_$>XubT{_5?|7fRnx}~KvY~b$18GpMz|)bSb}HSXNr$K*^Ebs$Pk>Uf+w!o=V2H(?U#9VII_McWGGQ=Iq=4l}}4zlt{W zCI7!P*;?R1$mGE3Que2tx|QC%wT7k7WCp^-uR%yI9hsD zHE%4_>TZDQW+HLNzZ;+Nw}8HU&Ua|`RG-wF_j{Oh`_!Hr15)e2=M+;&w>i?)N^>9m zMm3X>*%eA+Hi zyk{SH5z3NEw!I*i6OJ=$!V~@Ix0HJ^w-WW;6r@pE-`i^rBD6=G8p~t-rT!^8+pN>7 z*12$5!Rm&OddJIRY*k0 z$>qL(#nWFt$C)tI3UgfZiBd_%_%s1Njc&6{r_&oYP|As|*SXOt?IwM>q3WPU4IT_I zM9h5J^QE8@k{?QqJnM!^$)&a14>rg}~L zQAwpEQ^6j`T_4i+VK#R^J?47j4qj2$FA<_SSNk<9ETJQ*mPqFL9{^4~*j3Ifx)9;J z_?#z?7oG--{D9PZeOK}bf!j@gpF}z#SSQ74J`N`fQV6wqrBT5HGVW8^K#P!w20jPlSZWV zJ$DH~XKLAS|xzxnF7b;cnUd;`eXUZ=Sa`-&lTr-an(H)3;~G zyX3sGRq^Fu2s+N_@XCV0LzbOkQh8aQ(lUNuSd^j0AnHU(Bu{5Xv-4e{?Fo_!4mOM@GueVD5ZTJ0X+ru9U zS%K+Rdn!N8?T}qNf1lvSt5wDNS?_E9z1Z3zTl)(XTzfaa13H4?0x)107(gMz-~b95 zh8MuFVPF6S4#NUa=rEK3!;ql?6o{lLUXXv^Aci~gQQPO=t~#%5+S}F7yXS7bS0}J> z#qO153=+Hy3@4-++<@kOVr#evv|{tB zo!cCtv(8=jmCq^(hF5G1rlNEp8&vl0zV|2R)IGa@pQ;6KfB&oh`tbU)-5q=DzuPPR zzHDEn7`@hfe_zy<&HFwc|E=#147vMXZh!aNFTL@Eacm?*g&8PLZ~=z^h8x8cs!%f)oadk*zw4>+J5a^iFK`SHUZFnCR#|X6KeQuKTqB_@~OMQt*pI2i|=eJZ~E50Ah-Ej>6K~e zw>M8%yM2H6jeYy~ug=*R5z~KTsXZw9I^3q013`fitI63z+w_3|!nKpASq+H1Eb=$@aqM{eWc!=K+9Wdy$8zqKuKM;W-hLkhQ9 zzqc(06@>TzNH0Elpq#^%-}$--H4Xon7kK}AcF;v<#rFLFzuN`7t^8BgE|k5wep-2a z$BljOFUB*h5CfK|aRWk4*tYocar@32v-9=Vx#!$J@BB&&Yt_n!uiizHgcc0^p2AF! iIvGh0USVIU`pkn(i(b6Mw<&;$TcBbP(~ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png index 14206c495d0f1e63c8b24667f576983bcb44b703..981cf74dfd8b238a693a6785561b124fdf904137 100644 GIT binary patch literal 12436 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 literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png index fbbbf95585cec6c98d374ed443e2adf3ec5c44c9..04135187e241578c4fa4909b2d37058ac5289e38 100644 GIT binary patch literal 3637 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 iIvGh0USVIU`pkn(i(b6Mw<&;$TcBbP(~ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png index 14206c495d0f1e63c8b24667f576983bcb44b703..981cf74dfd8b238a693a6785561b124fdf904137 100644 GIT binary patch literal 12436 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 literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png index bc4e59d38f3104fd68bac1ae9c8f93ba04a28087..62e35be3072b81af5661858727e57452b927558e 100644 GIT binary patch literal 3650 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 literal 2158 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 literal 5248 zcmb7Ic|4SDxPI(D5|J%glI0{Bsfc7t$zI8lU7;q7>`capFXc%8JDqcW=ihVQe`bEa_j#Y^e(w9a@B6y$_-j@s0(?jK0007}SB-A~ zzy|$g1H9bOk8|K#ZvYOPm>L`241Yz>K_w}8q1y4B2Yz52%1Rjk27^C-C zY|1@(fDBh{AEy&7Hn|Vebg84v?uqrqO8=lUcuJo2V97sGIVG5fO@rgT1HA(S9FRr- z_oq*i!C>Sn@LW;Og$+=G9v*c255Lihw&b-K@_JQuF;_Is2mk{Seom(zx=wh8>fg&H zQrzo4o?1j+p!^p*07ypM6Kf3f%TGxSw|C6Uh0r>X&mjbWqymPRqvSU#I7xvPa{}oY z0HS4J3EZA|A{%gt2B1R-g=#G!N)K*jS5c)NJxZ<4DJ%8<+m9(D%~PgvWxsW5QK@z087tN@V&eor_4lm@YcIPn_w9*gVF@mB13PRj zI*?`25r<=D-K6YZZ+=B!cz_Ns6zq%Jm3s%_k19!+nBa5V4zVm7yi@V}7Bu@g|0E*n z#0X`cy){!dGdy#_IFl{k5?YXX1y4s=XYt3(iUfYSn=PHvCG(f6T(~hfuXqdqcQO4} zdaCxwMoXjmpkUv^wNJD2Bpl_i7yZO3P$SB^`N;8T@geGQKLX)!jT2*HVj`}4@)OxM z@F9He2JP|kcvT%ihk1m?^^vIHlE`Ld$hz?vt+)4fZ_!lfr)kfv8l4ZO$s*qbQ}oE{ z35ys+UcfEhx#14GnXm%&6Bi;ZL8UP-0JElo@^d@`vZ<|`%JHgy_d9u(hf}pl8`a(| zb*o+6W?pk)UL_SAz>bA_OHy~(Mt|Rp3tP37TMudWg+5-?O8$R-)a8R{8wn@^b_o|X zwhU{W$Vh%6$aST6Agfegw{w()9GW;}j8@@Ke>d;hq`O@cXUH6{qI}_s4uv9b!0_^D z5=I#z)3MI}^uyGse}#K`>y2!~ukR zED-+(7D;e#o!ya}9~PCVh3ibJjb{+;R-X2xIH23;z@oqw{z+-Z^Coug#E z2kRZ1(|U3w4>dZgvOTWh_MTw*CNYo_+G%v2X$7ATs&kKBSPDy2vyu@78BlnWJVH5_ z?|PN+Fe*(FrNWlb@4GO{ZgMVDdh!^gOvMqjgP2OcaEjfK0Q z;eLhW9L7caTlkKG{yVT_+(bp2ehTqop6$XIbidBE4Wn!O32Q3-`W=HAvhFU1P`XR# zzmiF#>-jS>D1xtH#I>kxx%zA68=DJfrXywq+tIhkRUyGEu_LKirc3lW0mweX(z-5~ zHQ|cb`~IDxGB^4*fBLKroESSre&(ekQF@7VAKjb9Rwg;Xf4}*}z)r-(-WjhT?F17q zWb^hE@~2uS@Zn>356y%yX(N$Sd!?STs-KKy@^;w1k*>OyS#PD8y%{rWBY<7j@{9_e z8`Qx2tmxK}UtAz8ZZvP!nt+P4A;lI;cVqL&f&1>uzL|pa{uxmc%&Q2Pb<>UM&3cok zgrGzrFwe&hVPSR|+b^o&Vo2V*;IWG)Wf1P~YE|L!n`cKiWN*IJHLNU(E!nQzp(?`pnfI0GbAPe@{wxHNPWaxqrvG%`hRm=NrKnU=!vpNlK}{O#j&MrZ z?U`1_g(C6K_>LDY))Iuv2r0b>e(VaYHS@rO+A-P?P|f@&gqre&#PVq zH}>b_3T>L@DYiY+K)!ma3jGxBKXGO~7~VcbO!d!j6{2Slw+PCMZ)-Zt+t!WhIWVX$ zukMC%RjC>__WY@(L*OE(!SwGKhDot(+a{5Yr!o&`PV~ASd6PZhn}4uEhpARKM)emx zuQk4rT4EZuc+yMnZL^;alKhU zVlcj!$D3&qVYA$~P137c?p!BIaYMO@U3GNtLPZAuY}b6;&p0R0I{S>o9Fiq|(X&(G zTu(H&AIdsfrWn6VjXmRN@78?eVc?9QtZ5M?%mOivT9c=py!mSJ^sH;0zlQ0r-;X3W zb#*7{`Z@j5Qaxmerm^((Ypv>guY3NJaM8*j*;TX3l z`*OfG>mOAabK$ygD}JZ+c2#LA>p7&X_0q}f$o+pie_@NYd`E*g?UPr8H`ghcaDJB^K*_ z0CJ=p$d5f(QGNgBUmtz~ge|J07x&G$w%^|^NV#?_Mx@kJ-!GshW$|8m3UneL2n684*( zsvonb|HE@q7G;e3JJAyC?If366@R^dj43w(qaT{9J#*^( zVaJASDUas{pvwS?Yo+T|H^Rya-hnx)>=dIfJ?L?w^tJ=@Rd1yKH@PTytVb zpJ{WK4|j~^KaS54_s;LUP11AIxfb|krzhD}8;P}8qRu6E#d%WBP0JX*8Y=ba&ZpN$ zIouTj#8{|1Js)QmSNW))Hsm#uRma`Ae%FjbjidKKY$t78b!WN8$6@75k3Vd6rFa=z zY}*z5yOy%d7BRn%l22r#VS%y z=G?nO*Syf}yfh|s-#SvdyebOoan9;UkJa~|dpk2E+m-zkbLRS36HneTzfm3c(ZD7R zrsHUNyoY;^5hy*(4u;fe({Fw!DxByFr>p$X%+d=W$u`-=AKAGi2Ci3AO|7# z@86<9^b7Uo*xogzZDyWAe2rRB5QlTu*`<)`F3_j+hmwkpz9GtFLK#aTR5smW7((kr zjDoW>y}v-kzGu9#<+Cy%#sCK&AyCOj!ZS1to`h(xf0|`#pq?!~4!FKT;&m6e1a;3O zZ~Jefm~hv3dvD@44w;^dx{1@7(6gd>{x|>ZJ9BubJVi5j7{7!n{V^t^990^$nwzKR zQlB((EK`X6zjk@)6t#6veun$i)5R3rxa-OkartBsc1<4&^BGVBaeO%rhak768#}Ra z$3gYDrfzUk7uOTCDLKsv*Z6Jql--9V zou4vXVlOR(LH!>J#0TZO86maT`Bzchlzg})==Y&%9PvH`IhRx;dOau=Tm-vnpL8yF#Q7OrJ*8kzl~PH zgslU~ClCWw->(ka#T26u7a%UV=UzBzRcSa)v>Ar7n*TK#GxV=AiyKZf-kqaWMf|kY zT$R);#S4f|t1xS8=;fsO4fN-9+S0H4XhAs}NZQQ*lNqnEP)sq1*bRiYdJA&dG%LFl z6C4kwk5vt@x2UWcs7J(i@q85Q{P#9JGIQ^oR6W*3v?*fZTVX8rmklYSY_wmn(7#&( z;9aj{W2nAedEesU*L&dp7~nVkm#y_9}iim3w(RC!HnE;l(yX z60vza-uL507MZVakMY0CuN%kp#DdlHk`%rD3Haw0uTJ8{WTP@_3aY0=v*FWcvhj=W z=w&_B0xbL|&$1pZy%67NnH%<|Ch(yL>Pd~^W#;|0M{()1B2@!ZT(bu`At1P)J-PK$ z`hk_{u3UYIhXm6IHwH^M_;sv2cINB9E8l!Pm5F>0Iw2a{l2tfbD*ibS{*o^`Qli?;BB&G(={$21uAx&;$*&Gw8ID`9g0tn9K|YmK zy6EXpaCUEg1;>+OOb-5m8?V<1E2#l2#s%)BU>)&P=cnWwmH6WcE!(7Lr+711KBEWg}Jds1xaH-sVjB`MQ1fV(2gA8jzG?8Dx= zD1||kEOWxYCRZWw!)ipK2n?fn_GOu@s*H{ku3;CdlB~Mw(fy$NtC_h8EM-x1|BYlJ zPZ6C;b<@2>E_(A=eXpiwowkacA}9aB0MofUy9OV)Q!>)79NgSkxYPbBmUdSWrC zFlkF+II-?0YUXO#Lv+*FB4XbwK-bjsZUrC6fD~tv$AXxi+q>rLNRQxr4T+Q7PFMEJHW$1NU1j zJLEBxkc_eG@vbWVbu<0ONW;dkJyR^ykiT5piN_uq3DyW`*KT zH*#oMxp{N8qH|j$va9jH8n(Z>s0`2am3W|^ubAEPSI20UIso}4&3$l>p9T4V^o`&@w9jdYs~>TTcM@;z zQ*JJ+?@&%~2*rH^ePVxdld}088e2iL8fO09>Cu(rxi{^hNmVQ4!2j1%3HAj?!ed1K TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png index bc4e59d38f3104fd68bac1ae9c8f93ba04a28087..62e35be3072b81af5661858727e57452b927558e 100644 GIT binary patch literal 3650 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 literal 2158 zcmcgtdrXs86hD<$K?{~RN_fA81xzzXAb?O@<>3^0Ic0?v8W2$)io6CZ?KFXsZWNg) zD5FdqYoiDSN^m?%1_T%zl?an(K}9hzIt>!0SND%OM-ShI?b%yH&`a4vpS>a|~FFkqo}VD#U(LHAFbJ79Md51~Cc%A7j{ znCpP>30S3@!L33K_Rx7K^3X@1dCjuKP$XD&mbA)KyFQ2?j~lwVep&?>MEmy!&eZxb%?o%OmrP30*eQJ;UT(I>en` zgC(WuMgU}cu+s%7HH2bKfFrsPxC5YClWm924%zVECW5 zB`BVD(t}3ZrA$$byEo_LOqqTyf8CMcKi`u=O%%%}3dWT516eK%fBFQ=o^hE^JAwV& z=ZFXZj0vd3sDL!Y1+X#3;69=Z0OJfO7-|15_`Z6I9H|@eIB!*X$a&5yKYy>(FG(!R zH4_P1gc)E=0O&OZKXlNFHhU1A*@}yP7r-iITcL1aci(H0ZPRkj4`1_^*W*c;VvM-A ziChof+dAxTag?K4+xoQ%w7lacxn3_Xl&H>k{lZjpnJYgglf=AawP!3#)w3`5_S&<| z5N`JJS^gx`i4ijUv9j~QY?V=Z_4@=khIQiB#^ylXEc_h1brgnj@Q|bb*OYcT)00w5 zRqXdSbJc?<3}l>98*%o!!AzS|OdC1xGxRpb6-q)~wh5zo85vl(R~C)eA2NlSv{U zrfI{fkId7$MI7a~*eQ8k#~o4ROnp8gHkE%=I5xNNf<~m>bz|{H=#~o^L{F7RGGD#_ z6hD{Lu)5sw>M?fx?XpI#j%Tl~99Pu_R7FV?)3Zd{%ITkt zDCwW5A8>x_r{QeV`lq8+4{bBDvQ%xmPR`6ueb`Bkytgs${y=2{Ht9AsY6Y6&r=2#% z5kQ$KLkwI+BKosMJ!kO@#g(!aMJ*p2fS1Mi%y3DREO#G6+3rurRh~h6X>Zt#6$V+V zY#1r+_fT6fCHX_ge}6rHB9N=MV-l+O(k`Ao*bIaIhmTE*37XE*UAMs=jMD4YoQ78yk;56jwEY zCQbqx?;l^f-vv8|sFJ>U|GZu%#glOI)p9atyNn27s-|Y!zqJ2dDqBrl2HJfcv;NZP zkaf6=cnG>~Xb@>=Xc(41MRrVF*$A@3NtMB@|A&{v^P;x4fOf2v^F#dwk-%neWVE5S zKa}&3#Vx?9eFxN1A|2@0bkP$);Wr3R)K!Y?dc1;|Z`8X3G=Ir@CAhFv_SgxbEqJ&} zvqCqhFe(7=@nPaMw`toEF;AnF1heYV${0wOR#kWdntgO8_w)ysb7su_zaK|l&cvgW zv^sA(^`qOpE*O=EC~Z<6D~8YJzm_S!L}k(m-e(d4Xsk`qH~*&pgh~{VOx4W+N*%(LvG6OBB#Z(`(|) zbpvdc**{>ney_s-FhyTh<@`WGk&;LXVg3v$uU+0V=YY)`;ib;4y0In&))^r1euGXP z9mjD0(vyX?uqUjCWFn2>e*C)k>U-`eK)D#p5vR6eL$;mNRcr5o;#UYgHoilUcX95@ zDuQ|nz_?NoL{c*+t_XH;_a+^Z+_~gm=we7Dzdr z2_mI?q^fSGrxqu$LK8tH)K4;wWlYm>2%+rUi{>{oH{4FRHg5?@Z`~8rz~c;EB%(-s8<lcRB3gB_^{NH^Yvg^xLI58JmkDK_heb6nkoe zS^3zVVQ{8tY5DrRSrE*i&bY}G&DNpzZ(~>AZ|hEzkHQkKyYKp*Q(Ql*K9UR9$x zaPo8O4oWOg^|XLfacG-$N#hs3fD7zwseI?w?ogig?yUPgGYL3YPj3cr+nyzv#tlV$75>FJ@2=sb zv(^);F1n?9)liOYj7O82y85$tg1Fl#ES3LWVYU*7Z~$mBdLPsjjah+smBan2vI zvhhLR7o9ccwNCVrdUu6H)P(t7l9v?1e;uj`H=g@cuC_g1543-8blN$5xv{KC&HOxn zKz@o51;Oc#5ZhwG!%{8=O@a;{5S#~Ygk&M_D_5_&*y;O7YyjY6W%rL#0|fnWE&kb4 z1wI;czWW6q?+y(hTELl|`x*0kzc@}fIFqw+_ihd6OV3fioQSi8VWm+-F|@6WeX>pt z1iz!S!8AoKGMqD}LdL!f`#`0`#Jw3A#b-EVg1Cw7i5~Y2%c~ojzN|zd+JE&Mc{TT9 zYnm>0wx+AmQfm0*)1jgZM_8CvEVW5iPh{BEI0z+*iV?9Fgtz=$3FcpAc+}J8Y^(7M z#|ngX{Bq-Nuq0<=I*ulU00;YeDJebAIq)HUOkG67F~ z5=Y=^V(=HRO>bYVnDSgIUYfQ5@_`7O85ADJ5Te3P@|P7-h*g?9hL=iJqY4&xvyZZ00PL z>1kXf%jp5e@k{1APufWdvauC3$r#&Q|e;{WX ze5}1Q_NF>0>iD%*MeT>$J1#rl6=H$*;M>dBD}>Cozw@Lb1k}v^g9pxGReO*ZnK)Ri z?40D1Wc8=toN7zaFleCA5d#_v!g_ChhU|B$c->CAmgqZj`s`~YmZE65%~ijq6e(#v z)&8CQG0;Nsl7tu=JE9*HN1XKCB5?LqQXk&VS7wd9k&=nylNDlQb#tY`LHqVikknez zIggz~7S>iscbkSlqc#BnZ*rzi;BA!p(oD17LJhVbQzah{w zZKC_d-y7IW{^JIjg&$V66OJDX7za;QNQH5yuoU5Fg_YGaPv->nqTKCi?B?kC@wH%A z%*dc20<)dPJoh(cKGbua%_x)ySqT~By#{y1BdoJG0=){-Z1;>@Z{z02FAkG)W1T+b z`l<|ZsNsdi>B(Eb2XkB8ADqtK^93LC{PI_8^=RLMacqGU5|>cQ0rwiVm(e@sADj0E z%|77ysi@Hd4=8_CI`Cb{#kXBf(O5~e;teP-lKkq1&}*Ai-}ij0e)?wpbK>(CF8CYp zT%|zwf4HK^XwvU4MN+O}QHQaX;~FwMf-N=@9eNAbi(JacQgNQukF@ZtV@Q+r@!E2i zqEgBXW_nChN_m8{D5=o8TQpK6{(UyKv3tXkM%R#d9-fknRKIHYlS!>6-TJS#lg6sc zNFL!D(Ah@`@z{|vkRHiqA)z+8qB{?6`ThfG+J4rvpg7khePSbo?3}9^>`wL#XIY6H zc}q+7Vn(mz-|&8CD<5Qr$Sk(cAG8iz=Ff>;C@8^#zIi}NNAx3>T-{%c*8f>awi_G2 zt9jYpvv&91gopGou92OulgESr*ta}qYXp*dm>DLEN9WB)^k^|5BRnZYfK`uN>~3jF zIw)yLf`I4TQiR9WUuIk?BNro-fS4gJf5HM?u*7m?skmFjIRl{-;1k89G)#k5`!$m3y6LrU}BMrq0HObjjG zBV&M~gKD*)1VP7Ysg`&Bu9+tnPiucw+Id#BNF$q?2+Hz4G5_cZBzCQnS_#UXqrit(+ou63j=<0;Pe(??z!q@2^3vmc6NV$)CVa-P)4fbRct>{K{+|sx*r1^_#Edwe=SFD z$W3)75&qF>@aJh7y4fSkV2|i)@Jd%JR{&1%z}E+^GjLgnGae*}m0YW3T;Ebze}EtY zxYGEh9unM*phMQGxN@tj2v_)Y^NuFh)>X4Dw%Ss_$)j?sS?Nbo{SPlnYZy@EX3+(K zwCzS>V$WhPIp~>*!lDC7C;aW1eqxq`=Z&Ey|K$G?Lx@$Y$YM-7kHU!S#V7DeHpGCI zPH%U8sF}39bi#VXrrarwLeeN07`EPR(d8<*8Ql!%+nrV$Bi*@mf`H%pJ-eE)pAgZq z5#xcv(mG(JA4V>FKb3;AWt(l9I<$+bzxd28KYFQxjF@=iW`RX-W^GuXPw-59sj z_La^ZmksLw#`j8_zinDq%wVVf$}LstFH0JO>8GRKMuu$r_M#c<&^r}tFj1Ouo4XpP zi8QGcg+B=>Dz)8rucuRnRWGZR_l#b53SI8xE0p>|5qJ3dp2Bi7y5eO5U2IU*Q3lL* z@T23LXWz=M&lO|k;NZ6APXy3v;mo%6u^7FM-FX~EwijZ=(Fdh6@me=ve~qhR4!ICR zy&ZX|lgMEd1H^eYaFsA9E*fKW*&y?2_{YnqT4!%e8-4OmBc0j5GiIclz(~JikEJge z+YXrM-yGUGQ57~G!m7ufgkZ1iKe2B^!Bm~>#RNdGpVIX7QTFtKj}@FM9sFY5X0{<5 zayFi*_FCea=-ZI5ZhcIWC0@so4+nouIag_)50<$C z>Fh)UcBA^`+K1xgY503>gj%~4GVKx#1G($L}{quivY!%PKU+a9^bW2!kIqr>^ zh(CJdad;6gDMovXsh??|xmitn*cvpSLr)={T;bW&j^(XNdL+ zrCq1qg^?^}3vXCFI(Dm+Pl*#LA8*>#R9BI#RQ8WG1E0=rJ$PK{GAsS3sf!mm?QnmU z3;W+oG=CG{8hiyCckcOCGY!SEW^NkB**rXveYlP?+G za5u@$x?jK)B}tm<1A;6-LOS2`-HLk6yO)Cy=5SpEz1D`JUd0XskvRNWJGpB;IQDDV z8!Op?cljr=aby|iIv*LV>fBd9e81=Yi6FU-&~7G~p<9DLQ1{lnt8$^@L5qi*EDCsT zxs*SJq|$f*Js%1zO@9hQivYmq4XCI~c5#v599{gZXUn`yPjIID(@ffymHSx)JCuR{JeN?h z;L~)~+6icYh~ABgya}_D%Pbu?oSF@L#?`%A08gtroaUbN2g#|~>ndMa^QzvRXuE)k ztmaCz_JcDmKsCjv{p<-NA5IhYovNs@Odv6^5tYe()10nZ3chA){e;XD)%_7)<}mJ3qh#C7N%})SC2Yp+op-F zMKR9>>2y%yLrsL)J}QRbg}u1oUcZDkW$_zSwB;E`))t)On+6H%@QFsKum&+J9F~u4E3fs!c;kub(N^q`RLp0ug759|X z87_OmT-j0-g_HTy-q88}tqkpiwOJ5d|X%+h(^p0AqQCkncpX_(tx!V=CZ$zi?T9vWE zPzd6NFHJ%hC%N_`ZD^W}(|Xi|)?ObX-?GeJ%3uUiM}F!g2yYMqsCr=al>O~MznB$) z|4;;_F@h+F$XAQ(-Md3Wf8%Xof4+>mUwQOE67#zfvzQ-D$I)q|EV^>2DT{`tSYBMQF7knJne zLN0`IcwyWD^7`9vO8kM#pE3i-@VH_V*O~hPK*E&0KS;$htzlt7K9|3zz*Br4;>{rN zr>Trz^&F;7z#&4^6WA9wr)er3w}IX2FMI*=X(tkw3Lm|gEq_Piff2z7f=e^=SArwn zz7g7*-m4#azv=Yt47y7@vsbDY?@T`u^<69PAi*PH9^|N?pk^=<2C=5;f8iE* zW8puMb8wk(Y7=PBcvUVj9hvkY=9!|s1mRcFT)*IvLUP2fP(OAJaPp2)r?==@!SRs3 zp<|ekPxuF$A+w7dOJ^vs&~&fgU&k=vlrO8tbCLYtJ--9aJEMNui2NMxG)Jk;iKnDn zr*))`uy4uAK93nI{BT8>Ewl2__P<((5(eXlXug04U367*rfJ0XK@(RB_OpzMEa+Yt z<^Uyl-bEq!3azs2^2Ie6w| zsqSAEv~#nKVKb0&`f=236h9kAH7E;9g;Wsk{S5aFO?J%%>o=)U$NX1kL2<+TZz*_9%Wr zlQ_yg+G8HlS0i*8asH5r{anR(oL5>luXP}>t~lZKfvmpoLm0c{AP;n>t0vy*auaV3 zZU4Tld=bYu%tjMW`E`Oc9&T-`LfSutic!ak+3lZl?42y@c9U@ftn(eM=(`@S5A?EQ z2;Wh=Qr~IkG_?mD`0*Qgyf2YEsa@4boorw@?!s3xEx~)L-=B(uOsa!GARM`twFvUy zCe%Nh2buhPBTkEZ!wV7XJS1M@Q(ECVz8*+yk)f0L^n11!4rg@C5z~AG=zn={RCH|b z?^u4M&5GAuMxJSGQHxw5A_Pmhy5otBitiE`zKZ{zc>USTLPaNOr)2a~QuU`RWaIY2 z(d$$5*te_fh;4iL{2yfbe1Rqjm9{@cTv`fZB5F?&82lN(2V-8cGsMC;dH5dV5do!( zc7os=wtwnvzUvF=epDecbTArpT5P7W34MQKVf7=yz7sb|W@bU@E#Y%{ePjtkMCA8* zTN*NV==dg{O#o_XF`7=A4x-1an9R@gVadMM>CwZ|7gTLaKe{rPkctHnaXb}Y@N!;x z$baYMoPBdynwHU2qx`H3#96#83 zXUw8tMBaUt+A%O6gi7Oia2{&{tuViE%=u&kfj{7^0g1pjNW*IM>97|+mn?Qp@&+cQG-jXx6fH7q}Zx zj+j#RJhEN~!Npc|pZ%lX8u`Z~1eI^MmV+y_I&8@KI=e|f-g$4kziz{a=CuBpB09<1 zHXusdPx8_haz9kZBEp2Nk;qm_<%gB*-^jiH#tBe1`>0$_>v7b_&6goCFWrY?oRuGEtc#B^ z)+98DIWBd-RF)Y=DBM5A((v@Itw+v%kQEGeX`Kl`15+Atni?yDYVR#cq7MlNs^?A5 zzRp+wA&YTJs1~g^vOO5rp1QylLFtTUSYKI@&BC(4{mLQjNJ;Fp}8Gj|a@lLuL^`4r4Jm*Ev zpPN>u^Xey#qnXHD)nQ>J%nR=3^cx@)O#df-Z1@sfW(7BiFxVc9p%0B2TVO<3Us(wI zmabYB!kp|0N@GjK7#w{lWMYvOr@6r-LxALRn`K_uGdPOO@T)3LDLRZYBHdo7k7o5v&jF^=Kl5AeeEb#*k7eaWXf##3dcK);t#4oOH(BI4dG1G8UhH z$)q-8bnubL<6b$mG(*5eHJZVTS*BM@sL3>9HF-c*x%uO^F^iHkcQ_p$LbmX6aT7@> z5%`j{$oATY$Q%-m@xz``N5Jz6AfV)zq+apn0m7u&(eH+*&3#$#+lh#Brb6feT!f6F z!*7x(&EcWTuI>`bFLje>hS|9H!;;se7619opHC<68E;jGpKNpbk<2DxztQls11ft#8c4^IL16064N@j)J4Z(8a}nx`m8J+QdnMJ{MD zJhuL*Q&V2xGw(u@$w^=Qhsf49wKS~>op2RoPdFfxNV3iljjaF_#EKUIW+XldCs4@p z&o2e)`*~kK9b+ckyeuYDW4#gizLck{I`Aa7hQAAoTrGc>Ve^x}3q02ehDk4^0eQu; zv;Lw}jRcz|y57R`*y3#SEI#+UzBP-)On%lM5)&H3-FuEn6cS>(1FznDKadHlmcBk6 zPER-#?6(0$_+>aYL<$K#tpB#O@ywh&(O-*O^Py|Gr<%Q*dC-5r&t&7MIERGdf#i-4 zsW0-2PS%#)R9#BPk$Xz%%uMuQSRG}!VF-RSbr zp6&W7qQIJx)&r!ZvYb*7Na4+alTV76sjUIkZ9L+ zSbj!UejvG_zShNoSSJfB-cYQhQG}3x4%CsC-uf)4NNCS-W-sO76;G3mm{i-oM;8A~ zk3!{RS7E&9hJ?61FH(rLC%NCz*wrt^RX--8$#r6%wY>rU!n$Jhg!hzJiYmidCPJqY zt6j_64;J>-^HX(laq#y(bP(!qPL(^iEMkM|lacA9!l2pjD*{iBv8XH#|5;JD{Jt=l za;2|H$+4yM*=h2^GGS7B7+b4)LeE}Jz`e@VxAo-- zto;W&n%*5+prwh>U>gu(?M&-9|E8(^Kd?afE_tu-A^NI4?KIvNorLdjaj8qw?Hj>j zXl@9dBBiCR%Y7XRrn3{OXt5m~9LM;&>NsG^UHCVWLDIhxB|6J06AU-wn}Rr56gbhC zh$D3gZ52?NhGm%~s{j&I@n#kSD62(o$2m!#dVfY}G1t64ebE@L2J^2V4KYgxIF$Sg zE5v1q01(0VsVQJXwadPT;?wXcAf*&mKFaT1E)gK|zt}u`^f7?7AbPyC>h{XbK*i)$ zQH|>H2S9N;HKL(DIJ#wb)Qx3ZBk5Fr=OnZ#aM`Tg@8aQ0TiAXu)4(2@ZnWZ_j4Hel znXm&_AG(?!KQTpsI&9?t%2CgQ&xj|lWPiJPZ5c^F(f6u9d<2hF*hdg zOY?Sj*V2ctncQTAw+39AOfHKGzI~6ag;Cd##mCYIzp3_4-AR>S+66{ibqyT2x!SH9 zi!tqVp0~9K!m#K<<^DcSx`wP64EL!-Od2CB1hBw#U)zu8ZGIq?ebhST%txisKBfKX zo=w}ne<{hT1>eeS-K>Y_6?yHUC$EsEGzh~!D=-$}= zn^A^}p=yB~g$e3d*?JJYhI=`_@Zh5&;ger{RfhG7lYiC{V5i z!y1C3+iN+Vu79NmWOn}iBt~7eOco^x+$h9&E;F-Ze)kEDZACNAgJ_|TE^G;%{07oh z{g)&?eDSYLGp1ON_D51YdMAokFBYs5{Ut!8P221=77AnbbQ#B2Pc=AP@PtSAbRKEh z`O=d4tXzk~MmA~*_VOIKuj}Z*nNiTgATz%f43VR_@xsQeb<8^F>-D|JRyacqRajf+ z96w7eke+s88Y86&PWF1~-pg%OkK%GQ`BEj629HSEESH(+!tWgQahn;@D+giS!JCq{ zcMLSL=f4=o<%Oj2HFucHj6Z)+tD{S-;AgjX!$p{(l`E#}$;2;C((pXEb{#B8HJms^`-ktYiycVd&WeG!yP%V-_EYbwFZ;RooEajfo94q=6 zS8Z!5Le?)HJSYoMqJJ))vi&yO$FtmtNU0;KRwc53zn-?&GAh*teQm|(HmO8A7w*i} zn)CNMA3NI~8jEJ*?iOi7tcyzdQ7wxrG1CxVi;2<206ExZz!{0O3Zp z=tKZoM+zlsntVVFO-z0bMiZ{+{cWcZKG2G!Q+RF`($%t0r+-V#9Qz#w#d?0}c}Svs zDCFE%%sNQJwgfgOK2m9WY7g9fABP!9j=GnJqu)_s%qjbq`DsLW4uZ1e=lJid?FnM* zUMBS6XKXF^WyZwi1FD3d0oDXr^PA?2@e5iwoYwS~cfk1rEcil!Tx%3S1dK_u zOWs8KVJwRvLc5DgK)0XtBNv)>p)MUPWE-Pc9t$~lSa zUP!X)WtRf|w^yR`76fq{iRsetF=ir}l9CZ6Wxu={E;(jJx-hrbXFEg&>Vk-BSbsAa zs|)RQjb8WqG#ePzybiMma$xv~B^(Tor#c1;t`bo&PG0XC*amJ-^(8jQv!)Q0o*5=2 zG#c9d&^bJc$FkbgS1$woNb`C9$ zLF%+#O>5tZoNck|OJMTyZu!*Pdcq!?i<=bi85Q`t2er%ZO*{V>NFTmzZo^cL~fAa;@i z9O7YtL%ce?yPX0i#BvzQ=dP9ai(d)g<|Yoq2^^(QC6?MYPO&M-l3Zn$Z-P69F$PIeF@$zc{ye4tLlb zuG)p@ z2Wtd!UQ{Gk4^5MoPS_P05k&LDbyqM-F@&wgZFRVRXCMbm8$J*k%5rl* zMIv+zRQM_eyV91lE6j| z5N1Ws&By1|1$Y zS5IR(wD|w=UsqtY-sY&hvog26iQiU&f=5s@A_3@k7x#Lr>uFc(ndbAC@g5y7m51yL zoV-UbCtUp^0x)bsJReR-LU4VxTk>(FFt=&6v(h3CpP(e&2c==Bf9;?zEeu-6(PW7j zf<;T&n>fKyj%_~y;y(zzY3ng1L&0oK(aGMOt+`(luvr~SoNYsV@Uo62*-0m!SHOf_ zL)QS93MAF4Jgr+j0Y(omqi$E2Q5d(wug|DVwZd2HYfTpRt7zS86NHJj2h8O<>E|pk z4wu=bXXX2Ql9>sn(Nk6M5;hyWDU+e9ZTZKDh~|R2k}TaII*mDkrrYrHozg&@8wLXF zUl0n9Q)C@|VnI8HWmxy+H8`RE_XgLSUYSrRB)edNvF7wSxJ<$uoYj2u54Y*UJaU8BfvZ&?aVX`^kUvvnddQM5_Z!sr?XzG`wueSZ)|SsQkkuMn z$Is$-PRVH)GsQmB)s;1j6y}H3?lojWT$N z-f=#J>qb&J*al$u<*xus!JteWSc$u#3g3gv;&tmV^4 z8puqIn2G$Ggijn|G@IQ+jI)Q2#1)}B8~B+zK8Y= zpWZWafHOtyO9eIj3MB11++=3&EgF|wu@oYMBj)y_%M%#UZQ8TU+4KNby~M(eV#n2> z@QUvm1CYh2U8cpBHX=C!1y(&q{Y}-Lm(J{aEX-IdSAt}((G?Lk=RH0KZa|Lz1DpT< fk^X7-dzMMrk)b+Iw+GC>4FJzowV~C@mf`;o%69@T literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png index 3dbbb594233a820b64cf3c8587ad86df627b61e0..5460a3836a1c743caf0caf94d159f9ceaf2f08df 100644 GIT binary patch literal 3638 zcmbVP4K$S58^6Y?HVK<(Bdpzx)(oYvg@#QjU*n@0JCh}~*nJD_NHM}}|FSEUN=7M+ z#4^KFrV05hl{BQ4G38@y7~`Wc4Gm39_P*`eb9VQfE&IRcyw9EYy?5T{-sk!Ke)oA( ze7xPX7A{{10MOdD)zuFGHTY8vESLwoKx$DKe6HH&>asodqO>RKxKYfC#vj^@BQypG zbk^76v?F(Z!|R!?yfc4Z{<6)xsB5yEkIPfE*Zn%QWZhGpgk8IKvDBiquV4G(-iN~J zhA~e*p8d!4$-G5tCFUtp7)3z8fm$AtT!1}+?I^mIFzrgn{rS(j)WeZY^{F% ztxdcrEN0c5}5_ z3HkY=L0;FeiHH>z_gt=OEN6S!8ASQ9Z}iL98WWb>!p%*`LvXfrJ<5w&VyAJ(C~oJ4 z=_4s3Qy3WPm+v@DFO5`QEnHl*UNO;TjYPn1&Lp-hU-%GxXqXa1fp z;*}_W{z$@SjTit-e^P(1d7WFWZr;nW6Md;zY|F=8^PISiL*nY(ZXKElvBkS%c#dgL z$2U^&>49ku`7+;}#=s%qJRht#wg&@-UejhrEgUW!I;DLDI|yUQ*? zYj`5rV$L_D)=;HWgFrPYH?Z>Onue?|l!qOxqUhY6VhI*`2K%Rf|VCi?Tg7d{7Tes{j>jS zS)~R14l5O17Vs8LT*p~jrkVCg+khuum-BLMrFX=5%Ht^FTBiVq+O9IaR0Bbqtm#!@5E zanY+Q35&BDO#)B8j@(h%MnD0(5152HYZpmjk3J_MLdbkcs{^9Y@^ z0a$zoC&3Y)NH1egPFeGwid{>0|w;}iLhM)9B#daIZuWpK*l}iy(aL}RD&apwc zrl4?eLpj7JF(`dLA-F)_RW56vSuH9irJk8?XNAms&oh1AT|8LcpG#&KPwO`1_)SR8 ztU!2Sl6jSrsE}b_)Ft=#z-`N(S(*9=~SX@st_s1QR`EVU4 zT~$K`h+wE$fG{Lwf#T4bHg?BJnQ#0{We_1^@F|y?W|ZhPb}f@eCFDHPyfkn&XvUw< zl8UETWYHcE#_U!kWNHce-yq+c@r7}D6w;L>rdoaFUmgDG`0qU(o;;?hU?=^L*sqK^NyldU0&koGE z@R%!-+*|g{s6OJosk4=YDNnfc;;V@`{%*e$UUk$TLm9mZ%@Y-Cwcfger~u$wU7)uP zA{>iBK?6>0MnM8V*#Z<(z*+w-hQNI@6f*#jKR_Xdu9e9oCmKbURmP@gi7N~JJli2d zy96ayTD1Ggw)}#t3`tgGHTB0VMa4H9zvAOXQqMe}t|8%?M!hs$7&E|DJ?4xqR0Hucjlj!Dw%32FNNf?4rNJ7oP8@nG224xPK+}8Me!rpU7 z--THXm9f8*xWhwO9ID9smZ%dGbshJHO^GiM`g`b}3t(?<`UV;9Rc&iY>q}x4BxM#! z@g1YZ1xW`xpnTlZuC`I#QAUpDthOZB)9qG-mR!#XE_w8_cVGL%q46uX4OyC z#+eJDa;jG@i#i(0-k448-R0~bQ2iIUlaPX@xPSI?vGL#joa|$ zOAu}QDj65cwjO)+roT&Y_&f3C&L!4UG-Nn@+^}+=xQju|7q_y>iI2;cTP1F78CP97 z+GEX*BbZcCrSDndKZcpE;Ihf<;g}mGlM(}%y}>e3U`hD;)00~)8?hevflrY{J$zmm zX5Yp*FO-ZR6E+HrlVkRv;E>}#X|r1k?RqP zd>SKqpng@2IbrB2@FaCC{)hiL-97+xlY4c+Rd{1%00DQk$KLzRve4HD>umPsW{F)X z+2Yz*{j)O`aYURGN79a+y5lkHZ4D*NF6PC60^xPEwJ?Y~n%vq84Z}sHgRSOxKaada zK`rA?W!Z!SZ0YwoH*b|uxcS19cs3~_rmmQgm|4rwUzS*6tJ2;V`F})oRwtKhkwaoX z#3cpd*wgpOS%_88o~QfchxKjoo{3ET=0@!zW$CN6)QP4~5r*Zh!vgk_yW=yCB*Q4< zUJfa>&!N4|I+n>Wd*aKVRv4H;rEt*z8VewQebk)QV6nDrJMf{y=*?RS^i1D9%v2;^ zUCnOfZ2#g@WcP`CN(4Rl_#@{^mC@Nd1a0YKRY>A8*}A%DCiBocFZ91*NFkF#FzF}YJC zDO}*38eL0mXAM@HR4jCBw{hxs?Xc#ED{5YP1#pcXd(XZg*N?dOx4Qem-l($|i4zUtu6C^KwD`z%NAKacEJZ6>0OoGpmM8O()N=-f zIzL10$b=P>rK)Olpi|z16i&-p%zMkQ3;I8_#Z#0gJ9Cuqz-CO{-@od)4yky%-EhI| zniNF>_+#&XmFl_c{3WgV^w)c9rrG4N@(#DE@GJwC*Y#Ps74K5w>0~MEF_s&MLn_Pr zw$v@2!qB_X{MQ20a=6E2Yj7V2^Z!f}P&FYuUcGbJREP}-CmV;eV)`Nw-hru9j%P5lQ5oRFkTnFywV7o_3t);B=B|QL1M&#jqqE>%KNiR$1%VR vM*d$fT0_}ayPo8v{tQck(+&TAW#lEP>)4#%^(4~rZ8o=U_IBlbwe#@rAq{(^ literal 2137 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJC^1y2{pkcv5P@A!A8gi9X( zXmD9^!2}K`F(J+$QcAl{7)i%Fi0u;-FMlj;z`bxgmmb%#mW9Et92=Wm<|MdV&0Obr ztdWJ&=R)BO`%nQEP3zn9+N$^3)V_LBX&3(^clWuS+h1*d^L*ayo4eEf>m@fneS214 z$?Ut_q%;d-I!=$*AaDPCSU%%8ucXi*UR%=a<|^Q(|yBwzHOCmlKXs{8q=h}_iJK+k;(uH zABF|M0HQMU%YSp8>rT^lJp5B9*llz9;lq=k1*6w)mv_^i3=m1awsk@cpXJZ@KU?!rSpt}-|ET8Ows!pO zd|_MTZ>yx!o8LyBxOV$KFnI6pU!AitBBuYw(s~(SpgG*9pA$g=606DZT>taQIdko9 z0;BkN{gF3++N1dt=KlYZoBQ|m-2C}FJ|5%&+JYA>4QJ0x-y!P>zf2Reb*KJ?j;d)oQc>mt74~}*Nb8#ALLw-ESd9)}=rZW{(6n**w zEOw2=rThB%7m1ZF17&2TZ|Bti|8l%y_a|w4_l>N*yf;6+Ir&=9+Q#O89GmW|zu&JJ z@Lbp9Lk%^D^80UBpbBB|9IpI+uZtmyDj@LnUo|(X5CcPr=Y5+Q9jsr!y{-RmkQJET zwaR>p^6#sk-f;`w{%-q$Aj&(LqawVaXwK vs5=Hc>>$6WoaJB$ddQ$4%7;lUxc6KB;TijtZ+<&J1BH;MtDnm{r-UW|C;EE( diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png index 14206c495d0f1e63c8b24667f576983bcb44b703..981cf74dfd8b238a693a6785561b124fdf904137 100644 GIT binary patch literal 12436 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 literal 5248 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 TqFDaR>tKIlK diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png index 3dbbb594233a820b64cf3c8587ad86df627b61e0..5460a3836a1c743caf0caf94d159f9ceaf2f08df 100644 GIT binary patch literal 3638 zcmbVP4K$S58^6Y?HVK<(Bdpzx)(oYvg@#QjU*n@0JCh}~*nJD_NHM}}|FSEUN=7M+ z#4^KFrV05hl{BQ4G38@y7~`Wc4Gm39_P*`eb9VQfE&IRcyw9EYy?5T{-sk!Ke)oA( ze7xPX7A{{10MOdD)zuFGHTY8vESLwoKx$DKe6HH&>asodqO>RKxKYfC#vj^@BQypG zbk^76v?F(Z!|R!?yfc4Z{<6)xsB5yEkIPfE*Zn%QWZhGpgk8IKvDBiquV4G(-iN~J zhA~e*p8d!4$-G5tCFUtp7)3z8fm$AtT!1}+?I^mIFzrgn{rS(j)WeZY^{F% ztxdcrEN0c5}5_ z3HkY=L0;FeiHH>z_gt=OEN6S!8ASQ9Z}iL98WWb>!p%*`LvXfrJ<5w&VyAJ(C~oJ4 z=_4s3Qy3WPm+v@DFO5`QEnHl*UNO;TjYPn1&Lp-hU-%GxXqXa1fp z;*}_W{z$@SjTit-e^P(1d7WFWZr;nW6Md;zY|F=8^PISiL*nY(ZXKElvBkS%c#dgL z$2U^&>49ku`7+;}#=s%qJRht#wg&@-UejhrEgUW!I;DLDI|yUQ*? zYj`5rV$L_D)=;HWgFrPYH?Z>Onue?|l!qOxqUhY6VhI*`2K%Rf|VCi?Tg7d{7Tes{j>jS zS)~R14l5O17Vs8LT*p~jrkVCg+khuum-BLMrFX=5%Ht^FTBiVq+O9IaR0Bbqtm#!@5E zanY+Q35&BDO#)B8j@(h%MnD0(5152HYZpmjk3J_MLdbkcs{^9Y@^ z0a$zoC&3Y)NH1egPFeGwid{>0|w;}iLhM)9B#daIZuWpK*l}iy(aL}RD&apwc zrl4?eLpj7JF(`dLA-F)_RW56vSuH9irJk8?XNAms&oh1AT|8LcpG#&KPwO`1_)SR8 ztU!2Sl6jSrsE}b_)Ft=#z-`N(S(*9=~SX@st_s1QR`EVU4 zT~$K`h+wE$fG{Lwf#T4bHg?BJnQ#0{We_1^@F|y?W|ZhPb}f@eCFDHPyfkn&XvUw< zl8UETWYHcE#_U!kWNHce-yq+c@r7}D6w;L>rdoaFUmgDG`0qU(o;;?hU?=^L*sqK^NyldU0&koGE z@R%!-+*|g{s6OJosk4=YDNnfc;;V@`{%*e$UUk$TLm9mZ%@Y-Cwcfger~u$wU7)uP zA{>iBK?6>0MnM8V*#Z<(z*+w-hQNI@6f*#jKR_Xdu9e9oCmKbURmP@gi7N~JJli2d zy96ayTD1Ggw)}#t3`tgGHTB0VMa4H9zvAOXQqMe}t|8%?M!hs$7&E|DJ?4xqR0Hucjlj!Dw%32FNNf?4rNJ7oP8@nG224xPK+}8Me!rpU7 z--THXm9f8*xWhwO9ID9smZ%dGbshJHO^GiM`g`b}3t(?<`UV;9Rc&iY>q}x4BxM#! z@g1YZ1xW`xpnTlZuC`I#QAUpDthOZB)9qG-mR!#XE_w8_cVGL%q46uX4OyC z#+eJDa;jG@i#i(0-k448-R0~bQ2iIUlaPX@xPSI?vGL#joa|$ zOAu}QDj65cwjO)+roT&Y_&f3C&L!4UG-Nn@+^}+=xQju|7q_y>iI2;cTP1F78CP97 z+GEX*BbZcCrSDndKZcpE;Ihf<;g}mGlM(}%y}>e3U`hD;)00~)8?hevflrY{J$zmm zX5Yp*FO-ZR6E+HrlVkRv;E>}#X|r1k?RqP zd>SKqpng@2IbrB2@FaCC{)hiL-97+xlY4c+Rd{1%00DQk$KLzRve4HD>umPsW{F)X z+2Yz*{j)O`aYURGN79a+y5lkHZ4D*NF6PC60^xPEwJ?Y~n%vq84Z}sHgRSOxKaada zK`rA?W!Z!SZ0YwoH*b|uxcS19cs3~_rmmQgm|4rwUzS*6tJ2;V`F})oRwtKhkwaoX z#3cpd*wgpOS%_88o~QfchxKjoo{3ET=0@!zW$CN6)QP4~5r*Zh!vgk_yW=yCB*Q4< zUJfa>&!N4|I+n>Wd*aKVRv4H;rEt*z8VewQebk)QV6nDrJMf{y=*?RS^i1D9%v2;^ zUCnOfZ2#g@WcP`CN(4Rl_#@{^mC@Nd1a0YKRY>A8*}A%DCiBocFZ91*NFkF#FzF}YJC zDO}*38eL0mXAM@HR4jCBw{hxs?Xc#ED{5YP1#pcXd(XZg*N?dOx4Qem-l($|i4zUtu6C^KwD`z%NAKacEJZ6>0OoGpmM8O()N=-f zIzL10$b=P>rK)Olpi|z16i&-p%zMkQ3;I8_#Z#0gJ9Cuqz-CO{-@od)4yky%-EhI| zniNF>_+#&XmFl_c{3WgV^w)c9rrG4N@(#DE@GJwC*Y#Ps74K5w>0~MEF_s&MLn_Pr zw$v@2!qB_X{MQ20a=6E2Yj7V2^Z!f}P&FYuUcGbJREP}-CmV;eV)`Nw-hru9j%P5lQ5oRFkTnFywV7o_3t);B=B|QL1M&#jqqE>%KNiR$1%VR vM*d$fT0_}ayPo8v{tQck(+&TAW#lEP>)4#%^(4~rZ8o=U_IBlbwe#@rAq{(^ literal 2137 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|GzJC^1y2{pkcv5P@A!A8gi9X( zXmD9^!2}K`F(J+$QcAl{7)i%Fi0u;-FMlj;z`bxgmmb%#mW9Et92=Wm<|MdV&0Obr ztdWJ&=R)BO`%nQEP3zn9+N$^3)V_LBX&3(^clWuS+h1*d^L*ayo4eEf>m@fneS214 z$?Ut_q%;d-I!=$*AaDPCSU%%8ucXi*UR%=a<|^Q(|yBwzHOCmlKXs{8q=h}_iJK+k;(uH zABF|M0HQMU%YSp8>rT^lJp5B9*llz9;lq=k1*6w)mv_^i3=m1awsk@cpXJZ@KU?!rSpt}-|ET8Ows!pO zd|_MTZ>yx!o8LyBxOV$KFnI6pU!AitBBuYw(s~(SpgG*9pA$g=606DZT>taQIdko9 z0;BkN{gF3++N1dt=KlYZoBQ|m-2C}FJ|5%&+JYA>4QJ0x-y!P>zf2Reb*KJ?j;d)oQc>mt74~}*Nb8#ALLw-ESd9)}=rZW{(6n**w zEOw2=rThB%7m1ZF17&2TZ|Bti|8l%y_a|w4_l>N*yf;6+Ir&=9+Q#O89GmW|zu&JJ z@Lbp9Lk%^D^80UBpbBB|9IpI+uZtmyDj@LnUo|(X5CcPr=Y5+Q9jsr!y{-RmkQJET zwaR>p^6#sk-f;`w{%-q$Aj&(LqawVaXwK vs5=Hc>>$6WoaJB$ddQ$4%7;lUxc6KB;TijtZ+<&J1BH;MtDnm{r-UW|C;EE( diff --git a/tests/python_tests/pgraster_test.py b/tests/python_tests/pgraster_test.py index 8c55c6c1a..ddc991cfa 100644 --- a/tests/python_tests/pgraster_test.py +++ b/tests/python_tests/pgraster_test.py @@ -113,7 +113,7 @@ def drop_imported(tabname, overview): psql_run('DROP TABLE IF EXISTS "o_' + of + '_' + tabname + '";') def compare_images(expected,im): - if not os.path.exists(expected): + if not os.path.exists(expected) or os.environ.get('UPDATE'): print 'generating expected image %s' % expected im.save(expected,'png32') expected_im = mapnik.Image.open(expected) @@ -622,19 +622,6 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ log('T ' + str(lap) + ' -- ' + lbl + ' E:full') expected = 'images/support/pgraster/%s-%s-%s-%s.png' % (lyr.name,lbl,pixtype,value) compare_images(expected,im) - h = format(value, '02x') - hex_v = '0000ffff' - hex_a = 'ff0000ff' - hex_b = '00ff00ff' - eq_(hexlify(im.view( 3, 3,1,1).tostring()), hex_v); - eq_(hexlify(im.view( 8, 3,1,1).tostring()), hex_v); - eq_(hexlify(im.view(13, 3,1,1).tostring()), hex_v); - eq_(hexlify(im.view( 3, 8,1,1).tostring()), hex_v); - eq_(hexlify(im.view( 8, 8,1,1).tostring()), hex_v); - eq_(hexlify(im.view(13, 8,1,1).tostring()), hex_a); - eq_(hexlify(im.view( 3,13,1,1).tostring()), hex_v); - eq_(hexlify(im.view( 8,13,1,1).tostring()), hex_b); - eq_(hexlify(im.view(13,13,1,1).tostring()), hex_v); def test_data_2bui_subquery(): _test_data_subquery('data_2bui_subquery', '2BUI', 3) From b090882902d9b41e85f7c19171f47394ed16cf7b Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 27 Jan 2015 11:41:05 -0600 Subject: [PATCH 68/91] Added compare utility to python bindings and image_util, modified set_grayscale_to_alpha to take a color optionally. --- bindings/python/mapnik_image.cpp | 24 +++- include/mapnik/image_util.hpp | 6 + src/image_util.cpp | 185 ++++++++++++++++++++++++++++++- 3 files changed, 203 insertions(+), 12 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index a7142e699..4a4fcae6f 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -116,11 +116,6 @@ mapnik::image_view_any get_view(mapnik::image_any const& data,unsigned x,unsigne return mapnik::create_view(data,x,y,w,h); } -bool painted(mapnik::image_any const& im) -{ - return im.painted(); -} - bool is_solid(mapnik::image_any const& im) { return mapnik::is_solid(im); @@ -131,6 +126,11 @@ void background(mapnik::image_any & im, mapnik::color const& c) mapnik::fill(im, c); } +void compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha) +{ + mapnik::compare(im1, im2, threshold, alpha); +} + uint32_t get_pixel(mapnik::image_any const& im, unsigned x, unsigned y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) @@ -209,6 +209,11 @@ void set_grayscale_to_alpha(image_any & im) mapnik::set_grayscale_to_alpha(im); } +void set_grayscale_to_alpha_c(image_any & im, mapnik::color const& c) +{ + mapnik::set_grayscale_to_alpha(im, c); +} + void set_color_to_alpha(image_any & im, mapnik::color const& c) { mapnik::set_color_to_alpha(im, c); @@ -322,10 +327,11 @@ void export_image() .def("width",&image_any::width) .def("height",&image_any::height) .def("view",&get_view) - .def("painted",&painted) + .def("painted",&image_any::painted) .def("is_solid",&is_solid) .def("background",&background, "Set the background color of the image.") .def("set_grayscale_to_alpha",&set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") + .def("set_grayscale_to_alpha",&set_grayscale_to_alpha_c, "Set the grayscale values to the alpha channel of the Image") .def("set_color_to_alpha",&set_color_to_alpha, "Set a given color to the alpha channel of the Image") .def("set_alpha",&set_alpha, "Set the overall alpha channel of the Image") .def("composite",&composite, @@ -336,6 +342,12 @@ void export_image() arg("dx")=0, arg("dy")=0 )) + .def("compare",&compare, + ( arg("self"), + arg("image"), + arg("threshold")=0.0, + arg("alpha")=true + )) .def("premultiplied",&premultiplied) .def("premultiply",&premultiply) .def("demultiply",&demultiply) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 58f976e26..e42c8b1fe 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -128,6 +128,9 @@ MAPNIK_DECL void set_alpha (T & image, float opacity); template MAPNIK_DECL void set_grayscale_to_alpha (T & image); +template +MAPNIK_DECL void set_grayscale_to_alpha (T & image, color const& c); + template MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); @@ -156,6 +159,9 @@ MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream MAPNIK_DECL image_view_any create_view (image_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); +template +MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold = 0, bool alpha = true); + inline bool is_png(std::string const& filename) { return boost::algorithm::iends_with(filename,std::string(".png")); diff --git a/src/image_util.cpp b/src/image_util.cpp index 02f5fdd32..33d62022c 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -468,9 +468,9 @@ namespace detail { struct premultiply_visitor { template - bool operator() (T & data) + bool operator() (T &) { - throw std::runtime_error("Error: Premultiply with " + std::string(typeid(data).name()) + " is not supported"); + return false; } }; @@ -492,9 +492,9 @@ bool premultiply_visitor::operator() (image_rgba8 & data) struct demultiply_visitor { template - bool operator() (T & data) + bool operator() (T &) { - throw std::runtime_error("Error: Premultiply with " + std::string(typeid(data).name()) + " is not supported"); + return false; } }; @@ -654,7 +654,7 @@ struct visitor_set_grayscale_to_alpha template void operator() (T & data) { - throw std::runtime_error("Error: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported"); + std::clog << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified" << std::endl; } }; @@ -680,6 +680,43 @@ void visitor_set_grayscale_to_alpha::operator() (image_rgba8 & data } } +struct visitor_set_grayscale_to_alpha_c +{ + visitor_set_grayscale_to_alpha_c(color const& c) + : c_(c) {} + + template + void operator() (T & data) + { + std::clog << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified" << std::endl; + } + + private: + color const& c_; +}; + +template <> +void visitor_set_grayscale_to_alpha_c::operator() (image_rgba8 & data) +{ + using pixel_type = typename image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + // magic numbers for grayscale + pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); + + row_from[x] = (a << 24)| (c_.blue() << 16) | (c_.green() << 8) | (c_.red()) ; + } + } +} + } // end detail ns template<> @@ -694,7 +731,6 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_any & data) } } -// TEMPORARY can be removed once image_any is only way it is being passed. template<> MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data) { @@ -708,6 +744,31 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data) } } +template<> +MAPNIK_DECL void set_grayscale_to_alpha (image_any & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_grayscale_to_alpha_c(c), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template<> +MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_grayscale_to_alpha_c visit(c); + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + namespace detail { struct visitor_set_color_to_alpha @@ -1282,4 +1343,116 @@ MAPNIK_DECL image_view_any create_view(image_any const& data,unsigned x,unsigned return util::apply_visitor(detail::visitor_create_view(x,y,w,h), data); } +template +MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold, bool) +{ + using pixel_type = typename T::pixel_type; + if (im1.width() != im2.width() || im1.height() != im2.height()) + { + std::clog << "Warning the two images compared are not the same sizes." << std::endl; + return im1.width() * im1.height(); + } + unsigned difference = 0; + for (unsigned int y = 0; y < im1.height(); ++y) + { + const pixel_type * row_from = im1.getRow(y); + const pixel_type * row_from2 = im2.getRow(y); + for (unsigned int x = 0; x < im1.width(); ++x) + { + double d = std::abs(static_cast(row_from[x]) - static_cast(row_from2[x])); + if (d > threshold) + { + ++difference; + } + } + } + return difference; +} + +template MAPNIK_DECL unsigned compare(image_gray8 const&, image_gray8 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray16 const&, image_gray16 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray32f const&, image_gray32f const&, double, bool); + +template <> +MAPNIK_DECL unsigned compare(image_null const&, image_null const&, double, bool) +{ + return 0; +} + +template <> +MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 const& im2, double threshold, bool alpha) +{ + using pixel_type = image_rgba8::pixel_type; + if (im1.width() != im2.width() || im1.height() != im2.height()) + { + std::clog << "Warning: The two images compared are not the same sizes." << std::endl; + return im1.width() * im1.height(); + } + unsigned difference = 0; + for (unsigned int y = 0; y < im1.height(); ++y) + { + const pixel_type * row_from = im1.getRow(y); + const pixel_type * row_from2 = im2.getRow(y); + for (unsigned int x = 0; x < im1.width(); ++x) + { + unsigned rgba = row_from[x]; + unsigned rgba2 = row_from2[x]; + unsigned r = rgba & 0xff; + unsigned g = (rgba >> 8 ) & 0xff; + unsigned b = (rgba >> 16) & 0xff; + unsigned r2 = rgba2 & 0xff; + unsigned g2 = (rgba2 >> 8 ) & 0xff; + unsigned b2 = (rgba2 >> 16) & 0xff; + if (std::abs(static_cast(r - r2)) > static_cast(threshold) || + std::abs(static_cast(g - g2)) > static_cast(threshold) || + std::abs(static_cast(b - b2)) > static_cast(threshold)) { + ++difference; + continue; + } + if (alpha) { + unsigned a = (rgba >> 24) & 0xff; + unsigned a2 = (rgba2 >> 24) & 0xff; + if (std::abs(static_cast(a - a2)) > static_cast(threshold)) { + ++difference; + continue; + } + } + } + } + return difference; +} + +namespace detail +{ + +struct visitor_compare +{ + visitor_compare(image_any const& im2, double threshold, bool alpha) + : im2_(im2), threshold_(threshold), alpha_(alpha) {} + + template + unsigned operator() (T const & im1) + { + if (!im2_.is()) + { + std::clog << "Warning: Comparing different image types." << std::endl; + return im1.width() * im1.height(); + } + return mapnik::compare(im1, util::get(im2_), threshold_, alpha_); + } + + private: + image_any const& im2_; + double threshold_; + bool alpha_; +}; + +} // end detail ns + +template <> +MAPNIK_DECL unsigned compare(image_any const& im1, image_any const& im2, double threshold, bool alpha) +{ + util::apply_visitor(detail::visitor_compare(im2, threshold, alpha), im1); +} + } // end ns From bc28c12572d1a366804d5541bb1fc6679305129e Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 27 Jan 2015 15:29:43 -0600 Subject: [PATCH 69/91] Found more situations where getRowSize should be used over multiplying the width by the pixel size. --- benchmark/test_polygon_clipping.cpp | 2 +- include/mapnik/agg_render_marker.hpp | 4 ++-- include/mapnik/image_filter.hpp | 2 +- src/agg/agg_renderer.cpp | 6 +++--- src/agg/process_building_symbolizer.cpp | 2 +- src/agg/process_dot_symbolizer.cpp | 2 +- src/agg/process_group_symbolizer.cpp | 4 ++-- src/agg/process_line_pattern_symbolizer.cpp | 2 +- src/agg/process_line_symbolizer.cpp | 2 +- src/agg/process_markers_symbolizer.cpp | 2 +- src/agg/process_polygon_pattern_symbolizer.cpp | 2 +- src/agg/process_polygon_symbolizer.cpp | 2 +- src/image_compositing.cpp | 4 ++-- src/image_util.cpp | 15 ++++++++++++--- src/renderer_common/render_pattern.cpp | 8 ++++---- utils/svg2png/svg2png.cpp | 2 +- 16 files changed, 35 insertions(+), 26 deletions(-) diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index 8b72ea81d..d72f1afd9 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -41,7 +41,7 @@ void render(mapnik::geometry_type & geom, mapnik::box2d padded_extent = extent; padded_extent.pad(10); mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0); - agg::rendering_buffer buf(im.getBytes(),im.width(),im.height(), im.width() * 4); + agg::rendering_buffer buf(im.getBytes(),im.width(),im.height(), im.getRowSize()); agg::pixfmt_rgba32_plain pixf(buf); ren_base renb(pixf); renderer ren(renb); diff --git a/include/mapnik/agg_render_marker.hpp b/include/mapnik/agg_render_marker.hpp index 5f77303ed..188b7de1e 100644 --- a/include/mapnik/agg_render_marker.hpp +++ b/include/mapnik/agg_render_marker.hpp @@ -81,7 +81,7 @@ void render_raster_marker(RendererType renb, RasterizerType & ras, image_rgba8 c && (std::fabs(0.0 - tr.shx) < agg::affine_epsilon) && (std::fabs(1.0 - tr.sy) < agg::affine_epsilon)) { - agg::rendering_buffer src_buffer((unsigned char *)src.getBytes(),src.width(),src.height(),src.width() * 4); + agg::rendering_buffer src_buffer((unsigned char *)src.getBytes(),src.width(),src.height(),src.getRowSize()); pixfmt_pre pixf_mask(src_buffer); if (snap_to_pixels) { @@ -125,7 +125,7 @@ void render_raster_marker(RendererType renb, RasterizerType & ras, image_rgba8 c agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), src.width(), src.height(), - src.width()*4); + src.getRowSize()); pixfmt_pre pixf(marker_buf); img_accessor_type ia(pixf); agg::trans_affine final_tr(p, 0, 0, width, height); diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index 3c2a54d6d..215703efb 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -401,7 +401,7 @@ void apply_filter(Src & src, Filter const& filter) template void apply_filter(Src & src, agg_stack_blur const& op) { - agg::rendering_buffer buf(src.getBytes(),src.width(),src.height(), src.width() * 4); + agg::rendering_buffer buf(src.getBytes(),src.width(),src.height(), src.getRowSize()); agg::pixfmt_rgba32_pre pixf(buf); agg::stack_blur_rgba32(pixf,op.rx,op.ry); } diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 83aaed6bd..ea2f7e21b 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -331,7 +331,7 @@ void agg_renderer::render_marker(pixel_position const& pos, agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), - current_buffer_->width() * 4); + current_buffer_->getRowSize()); pixfmt_comp_type pixf(buf); pixf.comp_op(static_cast(comp_op)); renderer_base renb(pixf); @@ -416,7 +416,7 @@ void agg_renderer::render_marker(pixel_position const& pos, agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), src.width(), src.height(), - src.width()*4); + src.getRowSize()); agg::pixfmt_rgba32_pre marker_pixf(marker_buf); using img_accessor_type = agg::image_accessor_clone; using interpolator_type = agg::span_interpolator_linear; @@ -456,7 +456,7 @@ void agg_renderer::debug_draw_box(box2d const& box, agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), - current_buffer_->width() * 4); + current_buffer_->getRowSize()); debug_draw_box(buf, box, x, y, angle); } diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 5d6fba5c9..1b3eeee42 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -58,7 +58,7 @@ void agg_renderer::process(building_symbolizer const& sym, using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; - agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); agg::pixfmt_rgba32_pre pixf(buf); ren_base renb(pixf); diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index 7838a920b..226dae768 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -70,7 +70,7 @@ void agg_renderer::process(dot_symbolizer const& sym, double opacity = get(sym, keys::opacity, feature, common_.vars_, 1.0); color const& fill = get(sym, keys::fill, feature, common_.vars_, mapnik::color(128,128,128)); ras_ptr->reset(); - agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(),current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(),current_buffer_->getRowSize()); using blender_type = agg::comp_op_adaptor_rgba_pre; using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; using renderer_base = agg::renderer_base; diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index f1ae6a30b..d84ae23f8 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -81,7 +81,7 @@ struct thunk_renderer renderer_type, pixfmt_comp_type>; ras_ptr_->reset(); - buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->getRowSize()); pixfmt_comp_type pixf(render_buffer); pixf.comp_op(static_cast(thunk.comp_op_)); renderer_base renb(pixf); @@ -102,7 +102,7 @@ struct thunk_renderer using renderer_base = agg::renderer_base; ras_ptr_->reset(); - buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->width() * 4); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->getRowSize()); pixfmt_comp_type pixf(render_buffer); pixf.comp_op(static_cast(thunk.comp_op_)); renderer_base renb(pixf); diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 5e5821ab0..d1e4d5a15 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -103,7 +103,7 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, value_double simplify_tolerance = get(sym, feature, common_.vars_); value_double smooth = get(sym, feature, common_.vars_); - agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); pixfmt_type pixf(buf); pixf.comp_op(static_cast(get(sym, feature, common_.vars_))); renderer_base ren_base(pixf); diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 126c7475c..5392ca8f5 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -109,7 +109,7 @@ void agg_renderer::process(line_symbolizer const& sym, gamma_ = gamma; } - agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); using color_type = agg::rgba8; using order_type = agg::order_rgba; diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index b05787691..49b6bef89 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -192,7 +192,7 @@ void agg_renderer::process(markers_symbolizer const& sym, gamma_ = gamma; } - buf_type render_buffer(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); + buf_type render_buffer(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->getRowSize()); box2d clip_box = clipping_extent(common_); auto renderer_context = std::tie(render_buffer,*ras_ptr,pixmap_); diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 38a0eee8c..17f897147 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -92,7 +92,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, using path_type = transform_path_adapter; agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), - current_buffer_->height(), current_buffer_->width() * 4); + current_buffer_->height(), current_buffer_->getRowSize()); ras_ptr->reset(); value_double gamma = get(sym, feature, common_.vars_); gamma_method_enum gamma_method = get(sym, feature, common_.vars_); diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index 13b9f1e9f..af53dff06 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -61,7 +61,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, } box2d clip_box = clipping_extent(common_); - agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); render_polygon_symbolizer( sym, feature, prj_trans, common_, clip_box, *ras_ptr, diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 6667bce1c..878b0a611 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -139,7 +139,7 @@ struct rendering_buffer 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);} + int stride() const { return data_.getRowSize();} 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)); } @@ -161,7 +161,7 @@ MAPNIK_DECL void composite(image_rgba8 & dst, image_rgba8 const& src, composite_ 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 dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.getRowSize()); const_rendering_buffer src_buffer(src); pixfmt_type pixf(dst_buffer); pixf.comp_op(static_cast(mode)); diff --git a/src/image_util.cpp b/src/image_util.cpp index 33d62022c..efce27448 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -480,7 +480,7 @@ bool premultiply_visitor::operator() (image_rgba8 & data) { if (!data.get_premultiplied()) { - agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.width() * 4); + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); agg::pixfmt_rgba32 pixf(buffer); pixf.premultiply(); data.set_premultiplied(true); @@ -504,7 +504,7 @@ bool demultiply_visitor::operator() (image_rgba8 & data) { if (data.get_premultiplied()) { - agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.width() * 4); + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); agg::pixfmt_rgba32_pre pixf(buffer); pixf.demultiply(); data.set_premultiplied(false); @@ -1253,6 +1253,15 @@ template MAPNIK_DECL uint8_t get_pixel(image_any const&, std::size_t, std::size_ template MAPNIK_DECL int8_t get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL float get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL double get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL color get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_any const&, std::size_t, std::size_t); // Temporary remove these later! @@ -1452,7 +1461,7 @@ struct visitor_compare template <> MAPNIK_DECL unsigned compare(image_any const& im1, image_any const& im2, double threshold, bool alpha) { - util::apply_visitor(detail::visitor_compare(im2, threshold, alpha), im1); + return util::apply_visitor(detail::visitor_compare(im2, threshold, alpha), im1); } } // end ns diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index 8fc1ac5c2..39213cc0f 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -55,7 +55,7 @@ std::shared_ptr render_pattern(rasterizer & ras, mtx = tr * mtx; std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); @@ -98,7 +98,7 @@ std::shared_ptr render_pattern(rasterizer & ras, mtx = tr * mtx; std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width()); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); @@ -132,7 +132,7 @@ std::shared_ptr render_pattern(rasterizer & ras, mtx = tr * mtx; std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 2); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); @@ -166,7 +166,7 @@ std::shared_ptr render_pattern(rasterizer & ras, mtx = tr * mtx; std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4); + agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 24f11e623..f770cbc83 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -158,7 +158,7 @@ int main (int argc,char** argv) } // 10 pixel buffer to avoid edge clipping of 100% svg's mapnik::image_rgba8 im(w+0,h+0); - agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.width() * 4); + agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); From dc931555d2f218b0034220db84bdbb6b5f091986 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Tue, 27 Jan 2015 17:18:20 -0600 Subject: [PATCH 70/91] Added required include --- include/mapnik/image_view.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 2256cfbca..850b4726a 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -23,6 +23,8 @@ #ifndef MAPNIK_IMAGE_VIEW_HPP #define MAPNIK_IMAGE_VIEW_HPP +#include + namespace mapnik { template From 939e53e70be460860605387fa9b5b76ffc8be896 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 27 Jan 2015 15:33:58 -0800 Subject: [PATCH 71/91] python: fix compile when cairo is enabled but not pycairo --- bindings/python/mapnik_python.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 89c9debdb..a65120a43 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -136,13 +136,16 @@ void clear_cache() #endif } -#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) +#if defined(HAVE_CAIRO) #include #include +#include +#endif + +#if defined(HAVE_PYCAIRO) #include #include #include -#include static Pycairo_CAPI_t *Pycairo_CAPI; static void *extract_surface(PyObject* op) { From de99180a44ddf528d9478ffa5174e4bd2c3b67c9 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 28 Jan 2015 20:20:14 -0600 Subject: [PATCH 72/91] Added new image_cast method and added its bindings to python, added two new properities to images: offset and scaling. Added way to cast between image types with offset and scaling. Added new unit tests for color and casting. Made it so that pixel setting doesn't result in overflows or underflows. Made the return of get_pixel, dynamic based on what is passed to it. Added new methods for setting pixels that are doubles and ints. --- bindings/python/mapnik_image.cpp | 91 ++++++- include/mapnik/image.hpp | 51 +++- include/mapnik/image_any.hpp | 71 +++++- .../mapnik/image_cast.hpp | 51 ++-- include/mapnik/image_convert.hpp | 36 --- include/mapnik/image_util.hpp | 24 ++ include/mapnik/image_view.hpp | 10 + include/mapnik/image_view_any.hpp | 42 ++++ src/build.py | 2 +- src/image_cast.cpp | 228 ++++++++++++++++++ src/image_util.cpp | 159 +++++++++--- tests/python_tests/cast_test.py | 95 ++++++++ tests/python_tests/color_test.py | 115 +++++++++ tests/python_tests/image_test.py | 10 + tests/visual_tests/compare.py | 14 +- 15 files changed, 882 insertions(+), 117 deletions(-) rename src/image_convert.cpp => include/mapnik/image_cast.hpp (57%) delete mode 100644 include/mapnik/image_convert.hpp create mode 100644 src/image_cast.cpp create mode 100644 tests/python_tests/cast_test.py create mode 100644 tests/python_tests/color_test.py diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 4a4fcae6f..4f930f879 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -126,16 +127,56 @@ void background(mapnik::image_any & im, mapnik::color const& c) mapnik::fill(im, c); } -void compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha) +std::shared_ptr cast(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling) { - mapnik::compare(im1, im2, threshold, alpha); + return std::make_shared(std::move(mapnik::image_cast(im, type, offset, scaling))); } -uint32_t get_pixel(mapnik::image_any const& im, unsigned x, unsigned y) +unsigned compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha) +{ + return mapnik::compare(im1, im2, threshold, alpha); +} + +struct get_pixel_visitor +{ + get_pixel_visitor(unsigned x, unsigned y) + : x_(x), y_(y) {} + + PyObject* operator() (mapnik::image_null const&) + { + throw std::runtime_error("Can not return a null image from a pixel (shouldn't have reached here)"); + } + + PyObject* operator() (mapnik::image_rgba8 const& im) + { + return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); + } + + PyObject* operator() (mapnik::image_gray8 const& im) + { + return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); + } + + PyObject* operator() (mapnik::image_gray16 const& im) + { + return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); + } + + PyObject* operator() (mapnik::image_gray32f const& im) + { + return PyFloat_FromDouble(mapnik::get_pixel(im, x_, y_)); + } + + private: + unsigned x_; + unsigned y_; +}; + +PyObject* get_pixel(mapnik::image_any const& im, unsigned x, unsigned y) { if (x < static_cast(im.width()) && y < static_cast(im.height())) { - return mapnik::get_pixel(im, x, y); + return mapnik::util::apply_visitor(get_pixel_visitor(x, y), im); } PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); boost::python::throw_error_already_set(); @@ -153,7 +194,7 @@ mapnik::color get_pixel_color(mapnik::image_any const& im, unsigned x, unsigned return 0; } -void set_pixel(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c) +void set_pixel_color(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c) { if (x >= static_cast(im.width()) && y >= static_cast(im.height())) { @@ -164,6 +205,28 @@ void set_pixel(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color con mapnik::set_pixel(im, x, y, c); } +void set_pixel_double(mapnik::image_any & im, unsigned x, unsigned y, double val) +{ + if (x >= static_cast(im.width()) && y >= static_cast(im.height())) + { + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return; + } + mapnik::set_pixel(im, x, y, val); +} + +void set_pixel_int(mapnik::image_any & im, unsigned x, unsigned y, int val) +{ + if (x >= static_cast(im.width()) && y >= static_cast(im.height())) + { + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return; + } + mapnik::set_pixel(im, x, y, val); +} + std::shared_ptr open_from_file(std::string const& filename) { boost::optional type = type_from_filename(filename); @@ -348,10 +411,26 @@ void export_image() arg("threshold")=0.0, arg("alpha")=true )) + .def("cast",&cast, + ( arg("self"), + arg("type"), + arg("offset")=0.0, + arg("scaling")=1.0 + )) + .add_property("offset", + &image_any::get_offset, + &image_any::set_offset, + "Gets or sets the offset component.\n") + .add_property("scaling", + &image_any::get_scaling, + &image_any::set_scaling, + "Gets or sets the offset component.\n") .def("premultiplied",&premultiplied) .def("premultiply",&premultiply) .def("demultiply",&demultiply) - .def("set_pixel",&set_pixel) + .def("set_pixel",&set_pixel_color) + .def("set_pixel",&set_pixel_double) + .def("set_pixel",&set_pixel_int) .def("get_pixel",&get_pixel) .def("get_pixel_color",&get_pixel_color) .def("clear",&clear) diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index fe2b2e8c0..850f6e192 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace mapnik { @@ -121,11 +122,21 @@ class image public: using pixel_type = T; static constexpr std::size_t pixel_size = sizeof(pixel_type); - +private: + detail::image_dimensions dimensions_; + detail::buffer buffer_; + pixel_type *pData_; + double offset_; + double scaling_; + bool premultiplied_alpha_; + bool painted_; +public: image(int width, int height, bool initialize = true, bool premultiplied = false, bool painted = false) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), pData_(reinterpret_cast(buffer_.data())), + offset_(0.0), + scaling_(1.0), premultiplied_alpha_(premultiplied), painted_(painted) { @@ -136,6 +147,8 @@ public: : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), pData_(reinterpret_cast(buffer_.data())), + offset_(rhs.offset_), + scaling_(rhs.scaling_), premultiplied_alpha_(rhs.premultiplied_alpha_), painted_(rhs.painted_) {} @@ -144,6 +157,8 @@ public: : dimensions_(std::move(rhs.dimensions_)), buffer_(std::move(rhs.buffer_)), pData_(reinterpret_cast(buffer_.data())), + offset_(rhs.offset_), + scaling_(rhs.scaling_), premultiplied_alpha_(rhs.premultiplied_alpha_), painted_(rhs.painted_) { @@ -161,6 +176,8 @@ public: { std::swap(dimensions_, rhs.dimensions_); std::swap(buffer_, rhs.buffer_); + std::swap(offset_, rhs.offset_); + std::swap(scaling_, rhs.scaling_); std::swap(premultiplied_alpha_, rhs.premultiplied_alpha_); std::swap(painted_, rhs.painted_); } @@ -249,6 +266,31 @@ public: std::copy(buf, buf + (x1 - x0), pData_ + row * dimensions_.width() + x0); } + inline double get_offset() const + { + return offset_; + } + + inline void set_offset(double set) + { + offset_ = set; + } + + inline double get_scaling() const + { + return scaling_; + } + + inline void set_scaling(double set) + { + if (set != 0.0) + { + scaling_ = set; + return; + } + std::clog << "Can not set scaling to 0.0, offset not set." << std::endl; + } + inline bool get_premultiplied() const { return premultiplied_alpha_; @@ -268,13 +310,6 @@ public: { return painted_; } - -private: - detail::image_dimensions dimensions_; - detail::buffer buffer_; - pixel_type *pData_; - bool premultiplied_alpha_; - bool painted_; }; using image_rgba8 = image; diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index fc764f6ed..db7e6bd69 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -38,8 +38,12 @@ struct image_null std::size_t width() const { return 0; } std::size_t height() const { return 0; } bool painted() const { return false; } + double get_offset() const { return 0.0; } + void set_offset(double) {} + double get_scaling() const { return 1.0; } + void set_scaling(double) {} bool get_premultiplied() const { return false; } - void set_premultiplied(bool) const {} + void set_premultiplied(bool) {} void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image"); } pixel_type& operator() (std::size_t, std::size_t) { @@ -139,6 +143,51 @@ struct get_any_row_size_visitor return data.getRowSize(); } }; + +struct get_offset_visitor +{ + template + double operator() (T const& data) const + { + return data.get_offset(); + } +}; + +struct get_scaling_visitor +{ + template + double operator() (T const& data) const + { + return data.get_scaling(); + } +}; + +struct set_offset_visitor +{ + set_offset_visitor(double val) + : val_(val) {} + template + void operator() (T & data) + { + data.set_offset(val_); + } + private: + double val_; +}; + +struct set_scaling_visitor +{ + set_scaling_visitor(double val) + : val_(val) {} + template + void operator() (T & data) + { + data.set_scaling(val_); + } + private: + double val_; +}; + } // namespace detail struct image_any : image_base @@ -196,6 +245,26 @@ struct image_any : image_base { return util::apply_visitor(detail::get_any_row_size_visitor(),*this); } + + double get_offset() const + { + return util::apply_visitor(detail::get_offset_visitor(),*this); + } + + double get_scaling() const + { + return util::apply_visitor(detail::get_scaling_visitor(),*this); + } + + void set_offset(double val) + { + util::apply_visitor(detail::set_offset_visitor(val),*this); + } + + void set_scaling(double val) + { + util::apply_visitor(detail::set_scaling_visitor(val),*this); + } }; inline image_any create_image_any(int width, diff --git a/src/image_convert.cpp b/include/mapnik/image_cast.hpp similarity index 57% rename from src/image_convert.cpp rename to include/mapnik/image_cast.hpp index 40a9dbad9..45098a819 100644 --- a/src/image_convert.cpp +++ b/include/mapnik/image_cast.hpp @@ -20,43 +20,32 @@ * *****************************************************************************/ -// mapnik -#include -#include +#ifndef MAPNIK_IMAGE_CAST_HPP +#define MAPNIK_IMAGE_CAST_HPP + #include - +#include + namespace mapnik { -namespace detail -{ +template +MAPNIK_DECL T image_cast(image_any const&, double offset = 0.0, double scaling = 1.0); -template -struct visitor_convert -{ - using dst_type = typename T0::pixel_type; - template - T0 operator() (T1 const& src) - { - T0 dst(src.width(), src.height()); - for (unsigned y = 0; y < dst.height(); ++y) - { - for (unsigned x = 0; x < dst.width(); ++x) - { - dst(x,y) = static_cast(src(x,y)); - } - } - return T0(std::move(dst)); - } -}; +template +MAPNIK_DECL T image_cast(image_rgba8 const&, double offset = 0.0, double scaling = 1.0); -} // end detail ns +template +MAPNIK_DECL T image_cast(image_gray8 const&, double offset = 0.0, double scaling = 1.0); -template -MAPNIK_DECL T2 convert_image(T1 const& data) -{ - detail::visitor_convert visit; - return visit(data); -} +template +MAPNIK_DECL T image_cast(image_gray16 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_cast(image_gray32f const&, double offset = 0.0, double scaling = 1.0); + +MAPNIK_DECL image_any image_cast(image_any const&, image_dtype type, double offset = 0.0, double scaling = 1.0); } // end mapnik ns + +#endif // MAPNIK_IMAGE_CAST_HPP diff --git a/include/mapnik/image_convert.hpp b/include/mapnik/image_convert.hpp deleted file mode 100644 index e57bff08d..000000000 --- a/include/mapnik/image_convert.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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_CONVERT_HPP -#define MAPNIK_IMAGE_CONVERT_HPP - -#include - -namespace mapnik -{ - -template -MAPNIK_DECL T2 convert_image(T1 const& data); - -} // end mapnik ns - -#endif // MAPNIK_IMAGE_CONVERT_HPP diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index e42c8b1fe..09e522798 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -149,9 +149,33 @@ MAPNIK_DECL bool check_bounds (T const& data, std::size_t x, std::size_t y) template MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); +template +MAPNIK_DECL void set_pixel(image_rgba8 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray8 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray16 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray32f & data, std::size_t x, std::size_t y, T const& val); + template MAPNIK_DECL void set_pixel(T1 & data, std::size_t x, std::size_t y, T2 const& val); +template +MAPNIK_DECL T get_pixel(image_rgba8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray16 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray32f const& data, std::size_t x, std::size_t y); + template MAPNIK_DECL T2 get_pixel(T1 const& data, std::size_t x, std::size_t y); diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 850b4726a..96cda875d 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -121,6 +121,16 @@ public: return data_.get_premultiplied(); } + inline double get_offset() const + { + return data_.get_offset(); + } + + inline double get_scaling() const + { + return data_.get_scaling(); + } + private: unsigned x_; unsigned y_; diff --git a/include/mapnik/image_view_any.hpp b/include/mapnik/image_view_any.hpp index 0e4dbd1e9..425981612 100644 --- a/include/mapnik/image_view_any.hpp +++ b/include/mapnik/image_view_any.hpp @@ -70,6 +70,33 @@ struct get_view_row_size_visitor return data.getRowSize(); } }; + +struct get_view_premultiplied_visitor +{ + template + bool operator()(T const& data) const + { + return data.get_premultiplied(); + } +}; + +struct get_view_offset_visitor +{ + template + double operator()(T const& data) const + { + return data.get_offset(); + } +}; + +struct get_view_scaling_visitor +{ + template + double operator()(T const& data) const + { + return data.get_scaling(); + } +}; } // namespace detail struct image_view_any : image_view_base @@ -99,6 +126,21 @@ struct image_view_any : image_view_base { return util::apply_visitor(detail::get_view_row_size_visitor(),*this); } + + bool get_premultiplied() const + { + return util::apply_visitor(detail::get_view_premultiplied_visitor(),*this); + } + + double get_offset() const + { + return util::apply_visitor(detail::get_view_offset_visitor(),*this); + } + + double get_scaling() const + { + return util::apply_visitor(detail::get_view_scaling_visitor(),*this); + } }; } diff --git a/src/build.py b/src/build.py index 953ce6c2c..c6326906b 100644 --- a/src/build.py +++ b/src/build.py @@ -152,7 +152,7 @@ source = Split( miniz_png.cpp color.cpp conversions.cpp - image_convert.cpp + image_cast.cpp image_compositing.cpp image_scaling.cpp box2d.cpp diff --git a/src/image_cast.cpp b/src/image_cast.cpp new file mode 100644 index 000000000..56e820d50 --- /dev/null +++ b/src/image_cast.cpp @@ -0,0 +1,228 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + +using boost::numeric_cast; +using boost::numeric::positive_overflow; +using boost::numeric::negative_overflow; + +namespace mapnik +{ + +namespace detail +{ + +template +struct visitor_image_cast +{ + using dst_type = typename T0::pixel_type; + + T0 operator() (image_null const&) + { + throw std::runtime_error("Can not cast a null image"); + } + + T0 operator() (T0 const& src) + { + return T0(src); + } + + template + T0 operator() (T1 const& src) + { + T0 dst(src.width(), src.height(), false); + for (unsigned y = 0; y < dst.height(); ++y) + { + for (unsigned x = 0; x < dst.width(); ++x) + { + try + { + dst(x,y) = numeric_cast(src(x,y)); + } + catch(negative_overflow&) + { + dst(x,y) = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + dst(x,y) = std::numeric_limits::max(); + } + } + } + return T0(std::move(dst)); + } +}; + +template +struct visitor_image_cast_so +{ + using dst_type = typename T0::pixel_type; + + visitor_image_cast_so(double offset, double scaling) + : offset_(offset), scaling_(scaling) {} + + T0 operator() (image_null const&) + { + throw std::runtime_error("Can not cast a null image"); + } + + T0 operator() (T0 const& src) + { + return T0(src); + } + + template + T0 operator() (T1 const& src) + { + double src_offset = src.get_offset(); + double src_scaling = src.get_scaling(); + T0 dst(src.width(), src.height(), false); + dst.set_scaling(scaling_); + dst.set_offset(offset_); + for (unsigned y = 0; y < dst.height(); ++y) + { + for (unsigned x = 0; x < dst.width(); ++x) + { + double scaled_src_val = (numeric_cast(src(x,y)) * src_scaling) + src_offset; + double dst_val = (scaled_src_val - offset_) / scaling_; + try + { + dst(x,y) = numeric_cast(dst_val); + } + catch(negative_overflow&) + { + dst(x,y) = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + dst(x,y) = std::numeric_limits::max(); + } + } + } + return T0(std::move(dst)); + } + private: + double offset_; + double scaling_; +}; + +} // end detail ns + +template +MAPNIK_DECL T image_cast(image_any const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + return util::apply_visitor(detail::visitor_image_cast(), data); + } + else + { + return util::apply_visitor(detail::visitor_image_cast_so(offset, scaling), data); + } +} + +template +MAPNIK_DECL T image_cast(image_rgba8 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray8 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray16 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray32f const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +MAPNIK_DECL image_any image_cast(image_any const& data, image_dtype type, double offset, double scaling) +{ + switch (type) + { + case image_dtype_rgba8: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray8: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray16: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray32f: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_null: + throw std::runtime_error("Can not cast a null image"); + } + throw std::runtime_error("Unknown image type passed"); +} + +} // end mapnik ns diff --git a/src/image_util.cpp b/src/image_util.cpp index efce27448..ede5f7bf7 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -46,6 +46,13 @@ #include #include +// boost +#include + +using boost::numeric_cast; +using boost::numeric::positive_overflow; +using boost::numeric::negative_overflow; + namespace mapnik { @@ -1089,7 +1096,19 @@ struct visitor_set_pixel void operator() (T2 & data) { using pixel_type = typename T2::pixel_type; - pixel_type val = static_cast(val_); + pixel_type val; + try + { + val = numeric_cast(val_); + } + catch(negative_overflow&) + { + val = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + val = std::numeric_limits::max(); + } if (check_bounds(data, x_, y_)) { data(x_, y_) = val; @@ -1160,31 +1179,74 @@ template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int8_ template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, float const&); template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, double const&); - -// Temporary remove these later! -template <> -MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, color const& val) +template +MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, T const& val) { - detail::visitor_set_pixel visitor(x, y, val); + detail::visitor_set_pixel visitor(x, y, val); visitor(data); } -// Temporary remove these later! -template <> -MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, uint32_t const& val) +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray8 & data, std::size_t x, std::size_t y, T const& val) { - detail::visitor_set_pixel visitor(x, y, val); + detail::visitor_set_pixel visitor(x, y, val); visitor(data); } -// Temporary remove these later! -template <> -MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, int32_t const& val) +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray16 & data, std::size_t x, std::size_t y, T const& val) { - detail::visitor_set_pixel visitor(x, y, val); + detail::visitor_set_pixel visitor(x, y, val); visitor(data); } +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray32f & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, double const&); + namespace detail { template @@ -1263,31 +1325,74 @@ template MAPNIK_DECL int8_t get_pixel(image_view_any const&, std::size_t, std::s template MAPNIK_DECL float get_pixel(image_view_any const&, std::size_t, std::size_t); template MAPNIK_DECL double get_pixel(image_view_any const&, std::size_t, std::size_t); - -// Temporary remove these later! -template <> -MAPNIK_DECL color get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) +template +MAPNIK_DECL T get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) { - detail::visitor_get_pixel visitor(x, y); + detail::visitor_get_pixel visitor(x, y); return visitor(data); } -// Temporary remove these later! -template <> -MAPNIK_DECL uint32_t get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) +template MAPNIK_DECL color get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_rgba8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray8 const& data, std::size_t x, std::size_t y) { - detail::visitor_get_pixel visitor(x, y); + detail::visitor_get_pixel visitor(x, y); return visitor(data); } -// Temporary remove these later! -template <> -MAPNIK_DECL int32_t get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) +template MAPNIK_DECL color get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray16 const& data, std::size_t x, std::size_t y) { - detail::visitor_get_pixel visitor(x, y); + detail::visitor_get_pixel visitor(x, y); return visitor(data); } +template MAPNIK_DECL color get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray16 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray32f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray32f const&, std::size_t, std::size_t); + namespace detail { diff --git a/tests/python_tests/cast_test.py b/tests/python_tests/cast_test.py new file mode 100644 index 000000000..955a3fed2 --- /dev/null +++ b/tests/python_tests/cast_test.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os, mapnik +from timeit import Timer, time +from nose.tools import * +from utilities import execution_path, run_all, get_unique_colors + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_image_16_8_simple(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.set_pixel(0,0, 256) + im.set_pixel(0,1, 999) + im.set_pixel(1,0, 5) + im.set_pixel(1,1, 2) + im2 = im.cast(mapnik.ImageType.gray8) + eq_(im2.get_pixel(0,0), 255) + eq_(im2.get_pixel(0,1), 255) + eq_(im2.get_pixel(1,0), 5) + eq_(im2.get_pixel(1,1), 2) + # Cast back! + im = im2.cast(mapnik.ImageType.gray16) + eq_(im.get_pixel(0,0), 255) + eq_(im.get_pixel(0,1), 255) + eq_(im.get_pixel(1,0), 5) + eq_(im.get_pixel(1,1), 2) + +def test_image_32f_8_simple(): + im = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im.set_pixel(0,0, 120.1234) + im.set_pixel(0,1, -23.4) + im.set_pixel(1,0, 120.6) + im.set_pixel(1,1, 360.2) + im2 = im.cast(mapnik.ImageType.gray8) + eq_(im2.get_pixel(0,0), 120) + eq_(im2.get_pixel(0,1), 0) + eq_(im2.get_pixel(1,0), 120) # Notice this is truncated! + eq_(im2.get_pixel(1,1), 255) + +def test_image_offset_and_scale(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + eq_(im.offset, 0.0) + eq_(im.scaling, 1.0) + im.offset = 1.0 + im.scaling = 2.0 + eq_(im.offset, 1.0) + eq_(im.scaling, 2.0) + +def test_image_16_8_scale_and_offset(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.set_pixel(0,0, 256) + im.set_pixel(0,1, 258) + im.set_pixel(1,0, 99999) + im.set_pixel(1,1, 615) + offset = 255 + scaling = 3 + im2 = im.cast(mapnik.ImageType.gray8, offset, scaling) + eq_(im2.get_pixel(0,0), 0) + eq_(im2.get_pixel(0,1), 1) + eq_(im2.get_pixel(1,0), 255) + eq_(im2.get_pixel(1,1), 120) + # pixels will be a little off due to offsets in reverting! + im3 = im2.cast(mapnik.ImageType.gray16) + eq_(im3.get_pixel(0,0), 255) # Rounding error with ints + eq_(im3.get_pixel(0,1), 258) # same + eq_(im3.get_pixel(1,0), 1020) # The other one was way out of range for our scale/offset + eq_(im3.get_pixel(1,1), 615) # same + +def test_image_16_32f_scale_and_offset(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.set_pixel(0,0, 256) + im.set_pixel(0,1, 258) + im.set_pixel(1,0, 0) + im.set_pixel(1,1, 615) + offset = 255 + scaling = 3.2 + im2 = im.cast(mapnik.ImageType.gray32f, offset, scaling) + eq_(im2.get_pixel(0,0), 0.3125) + eq_(im2.get_pixel(0,1), 0.9375) + eq_(im2.get_pixel(1,0), -79.6875) + eq_(im2.get_pixel(1,1), 112.5) + im3 = im2.cast(mapnik.ImageType.gray16) + eq_(im3.get_pixel(0,0), 256) + eq_(im3.get_pixel(0,1), 258) + eq_(im3.get_pixel(1,0), 0) + eq_(im3.get_pixel(1,1), 615) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) diff --git a/tests/python_tests/color_test.py b/tests/python_tests/color_test.py new file mode 100644 index 000000000..900faf11b --- /dev/null +++ b/tests/python_tests/color_test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os, mapnik +from timeit import Timer, time +from nose.tools import * +from utilities import execution_path, run_all, get_unique_colors + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_color_init(): + c = mapnik.Color(12, 128, 255) + eq_(c.r, 12) + eq_(c.g, 128) + eq_(c.b, 255) + eq_(c.a, 255) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(16, 32, 64, 128) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(16, 32, 64, 128,True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(True, c.get_premultiplied()) + c = mapnik.Color('rgba(16,32,64,0.5)') + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(False, c.get_premultiplied()) + c = mapnik.Color('rgba(16,32,64,0.5)', True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(True, c.get_premultiplied()) + hex_str = '#10204080' + c = mapnik.Color(hex_str) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(hex_str, c.to_hex_string()) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(hex_str, True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(hex_str, c.to_hex_string()) + eq_(True, c.get_premultiplied()) + rgba_int = 2151686160 + c = mapnik.Color(rgba_int) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(rgba_int, c.packed()) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(rgba_int, True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(rgba_int, c.packed()) + eq_(True, c.get_premultiplied()) + +def test_color_properties(): + c = mapnik.Color(16, 32, 64, 128) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + c.r = 17 + eq_(c.r, 17) + c.g = 33 + eq_(c.g, 33) + c.b = 65 + eq_(c.b, 65) + c.a = 128 + eq_(c.a, 128) + +def test_color_premultiply(): + c = mapnik.Color(16, 33, 255, 128) + eq_(c.premultiply(), True) + eq_(c.r, 8) + eq_(c.g, 17) + eq_(c.b, 128) + eq_(c.a, 128) + # Repeating it again should do nothing + eq_(c.premultiply(), False) + eq_(c.r, 8) + eq_(c.g, 17) + eq_(c.b, 128) + eq_(c.a, 128) + c.demultiply() + c.demultiply() + # This will not return the same values as before but we expect that + eq_(c.r,15) + eq_(c.g,33) + eq_(c.b,255) + eq_(c.a,128) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index 7b233a233..a30a86719 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -127,6 +127,16 @@ def test_set_and_get_pixel(): eq_(c0_pre.b, c1.b) eq_(c0_pre.a, c1.a) +def test_pixel_overflow(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8) + im.set_pixel(0,0,256) + eq_(im.get_pixel(0,0),255) + +def test_pixel_underflow(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8) + im.set_pixel(0,0,-1) + eq_(im.get_pixel(0,0),0) + @raises(IndexError) def test_set_pixel_out_of_range_1(): im = mapnik.Image(4,4) diff --git a/tests/visual_tests/compare.py b/tests/visual_tests/compare.py index a08f52c0d..238625768 100644 --- a/tests/visual_tests/compare.py +++ b/tests/visual_tests/compare.py @@ -36,17 +36,17 @@ def compare_pixels(pixel1, pixel2, alpha=True, pixel_threshold=0): def compare(actual, expected, alpha=True): im1 = mapnik.Image.open(actual) im2 = mapnik.Image.open(expected) - diff = 0 pixels = im1.width() * im1.height() delta_pixels = (im2.width() * im2.height()) - pixels + #diff = 0 if delta_pixels != 0: return delta_pixels - # TODO: convert to C++ to speed this up - for x in range(0,im1.width(),2): - for y in range(0,im1.height(),2): - if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y),alpha=alpha): - diff += 1 - return diff + #for x in range(0,im1.width(),2): + # for y in range(0,im1.height(),2): + # if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y),alpha=alpha): + # diff += 1 + #return diff + return im1.compare(im2, 0, alpha) def compare_grids(actual, expected, threshold=0, alpha=True): global errors From 826e13f911648d2a337ecf2d4dd1e17fbc4d87c1 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 29 Jan 2015 13:27:42 -0700 Subject: [PATCH 73/91] Renamed background to fill, added numeric casting to fill utility, changed clog uses to MAPNIK_LOG, changed the implementation of fill some so that it only used a single template --- bindings/python/mapnik_image.cpp | 16 ++- include/mapnik/image_util.hpp | 16 ++- src/image_util.cpp | 104 +++++++++++++----- src/tiff_reader.cpp | 4 +- tests/python_tests/buffer_clear_test.py | 2 +- tests/python_tests/cast_test.py | 4 +- tests/python_tests/compare_test.py | 99 +++++++++++++++++ tests/python_tests/compositing_test.py | 4 +- tests/python_tests/grayscale_test.py | 2 +- .../python_tests/image_encoding_speed_test.py | 2 +- tests/python_tests/image_test.py | 21 +++- tests/python_tests/image_tiff_test.py | 10 +- tests/python_tests/png_encoding_test.py | 4 +- tests/python_tests/render_test.py | 12 +- tests/python_tests/webp_encoding_test.py | 4 +- 15 files changed, 243 insertions(+), 61 deletions(-) create mode 100644 tests/python_tests/compare_test.py diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 4f930f879..a3432f40f 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -122,11 +122,21 @@ bool is_solid(mapnik::image_any const& im) return mapnik::is_solid(im); } -void background(mapnik::image_any & im, mapnik::color const& c) +void fill_color(mapnik::image_any & im, mapnik::color const& c) { mapnik::fill(im, c); } +void fill_int(mapnik::image_any & im, int val) +{ + mapnik::fill(im, val); +} + +void fill_double(mapnik::image_any & im, double val) +{ + mapnik::fill(im, val); +} + std::shared_ptr cast(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling) { return std::make_shared(std::move(mapnik::image_cast(im, type, offset, scaling))); @@ -392,7 +402,9 @@ void export_image() .def("view",&get_view) .def("painted",&image_any::painted) .def("is_solid",&is_solid) - .def("background",&background, "Set the background color of the image.") + .def("fill",&fill_color) + .def("fill",&fill_int) + .def("fill",&fill_double) .def("set_grayscale_to_alpha",&set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") .def("set_grayscale_to_alpha",&set_grayscale_to_alpha_c, "Set the grayscale values to the alpha channel of the Image") .def("set_color_to_alpha",&set_color_to_alpha, "Set a given color to the alpha channel of the Image") diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 09e522798..3747999e7 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -134,8 +134,20 @@ MAPNIK_DECL void set_grayscale_to_alpha (T & image, color const& c); template MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); -template -MAPNIK_DECL void fill (T1 & data, T2 const& c); +template +MAPNIK_DECL void fill (image_any & data, T const&); + +template +MAPNIK_DECL void fill (image_rgba8 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray8 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray16 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray32f & data, T const&); template MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); diff --git a/src/image_util.cpp b/src/image_util.cpp index ede5f7bf7..a4fce8bde 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -34,6 +34,7 @@ #include #include #include +#include // agg #include "agg_rendering_buffer.h" @@ -661,7 +662,7 @@ struct visitor_set_grayscale_to_alpha template void operator() (T & data) { - std::clog << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified" << std::endl; + MAPNIK_LOG_WARN(image_util) << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified"; } }; @@ -695,7 +696,7 @@ struct visitor_set_grayscale_to_alpha_c template void operator() (T & data) { - std::clog << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified" << std::endl; + MAPNIK_LOG_WARN(image_util) << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified"; } private: @@ -855,7 +856,19 @@ struct visitor_fill void operator() (T2 & data) { using pixel_type = typename T2::pixel_type; - pixel_type val = static_cast(val_); + pixel_type val; + try + { + val = numeric_cast(val_); + } + catch(negative_overflow&) + { + val = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + val = std::numeric_limits::max(); + } data.set(val); } @@ -891,11 +904,10 @@ struct visitor_fill } // end detail ns -// For all the generic data types. -template -MAPNIK_DECL void fill (T1 & data, T2 const& val) +template +MAPNIK_DECL void fill (image_any & data, T const& val) { - util::apply_visitor(detail::visitor_fill(val), data); + util::apply_visitor(detail::visitor_fill(val), data); } template MAPNIK_DECL void fill(image_any &, color const&); @@ -908,31 +920,74 @@ template MAPNIK_DECL void fill(image_any &, int8_t const&); template MAPNIK_DECL void fill(image_any &, float const&); template MAPNIK_DECL void fill(image_any &, double const&); - -// Temporary remove these later! -template <> -MAPNIK_DECL void fill (image_rgba8 & data , color const& val) +template +MAPNIK_DECL void fill (image_rgba8 & data, T const& val) { - detail::visitor_fill visitor(val); - visitor(data); + detail::visitor_fill visitor(val); + return visitor(data); } -// Temporary remove these later! -template <> -MAPNIK_DECL void fill (image_rgba8 & data , uint32_t const& val) +template MAPNIK_DECL void fill(image_rgba8 &, color const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint32_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int32_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint16_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int16_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint8_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int8_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, float const&); +template MAPNIK_DECL void fill(image_rgba8 &, double const&); + +template +MAPNIK_DECL void fill (image_gray8 & data, T const& val) { - detail::visitor_fill visitor(val); - visitor(data); + detail::visitor_fill visitor(val); + return visitor(data); } -// Temporary remove these later! -template <> -MAPNIK_DECL void fill (image_rgba8 & data , int32_t const& val) +template MAPNIK_DECL void fill(image_gray8 &, color const&); +template MAPNIK_DECL void fill(image_gray8 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray8 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray8 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray8 &, float const&); +template MAPNIK_DECL void fill(image_gray8 &, double const&); + +template +MAPNIK_DECL void fill (image_gray16 & data, T const& val) { - detail::visitor_fill visitor(val); - visitor(data); + detail::visitor_fill visitor(val); + return visitor(data); } +template MAPNIK_DECL void fill(image_gray16 &, color const&); +template MAPNIK_DECL void fill(image_gray16 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray16 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray16 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray16 &, float const&); +template MAPNIK_DECL void fill(image_gray16 &, double const&); + +template +MAPNIK_DECL void fill (image_gray32f & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray32f &, color const&); +template MAPNIK_DECL void fill(image_gray32f &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int32_t const&); +template MAPNIK_DECL void fill(image_gray32f &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int16_t const&); +template MAPNIK_DECL void fill(image_gray32f &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int8_t const&); +template MAPNIK_DECL void fill(image_gray32f &, float const&); +template MAPNIK_DECL void fill(image_gray32f &, double const&); + namespace detail { struct visitor_set_rectangle @@ -1463,7 +1518,6 @@ MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold, bool) using pixel_type = typename T::pixel_type; if (im1.width() != im2.width() || im1.height() != im2.height()) { - std::clog << "Warning the two images compared are not the same sizes." << std::endl; return im1.width() * im1.height(); } unsigned difference = 0; @@ -1499,7 +1553,6 @@ MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 co using pixel_type = image_rgba8::pixel_type; if (im1.width() != im2.width() || im1.height() != im2.height()) { - std::clog << "Warning: The two images compared are not the same sizes." << std::endl; return im1.width() * im1.height(); } unsigned difference = 0; @@ -1549,7 +1602,6 @@ struct visitor_compare { if (!im2_.is()) { - std::clog << "Warning: Comparing different image types." << std::endl; return im1.width() * im1.height(); } return mapnik::compare(im1, util::get(im2_), threshold_, alpha_); diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 2e7c1a9a2..adfa8679f 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -609,7 +609,7 @@ void tiff_reader::read_tiled(unsigned x0,unsigned y0, ImageData & image) { if (!detail::tiff_reader_traits::read_tile(tif, x, y, buf.get(), tile_width_, tile_height_)) { - std::clog << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n"; + MAPNIK_LOG_DEBUG(tiff_reader) << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n"; break; } int tx0 = std::max(x0, static_cast(x)); @@ -649,7 +649,7 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_rgba8& image) if (!TIFFReadRGBAStrip(tif,y,strip.getData())) { - std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; + MAPNIK_LOG_DEBUG(tiff_reader) << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; break; } // This is in reverse becauase the TIFFReadRGBAStrip reads inverted diff --git a/tests/python_tests/buffer_clear_test.py b/tests/python_tests/buffer_clear_test.py index c48130731..6cffc1c4b 100644 --- a/tests/python_tests/buffer_clear_test.py +++ b/tests/python_tests/buffer_clear_test.py @@ -15,7 +15,7 @@ def test_clearing_image_data(): bytes = im.tostring() eq_(im.tostring(),bytes) # set background, then clear - im.background(mapnik.Color('green')) + im.fill(mapnik.Color('green')) eq_(im.tostring()!=bytes,True) # clear image, should now equal original im.clear() diff --git a/tests/python_tests/cast_test.py b/tests/python_tests/cast_test.py index 955a3fed2..b469859ab 100644 --- a/tests/python_tests/cast_test.py +++ b/tests/python_tests/cast_test.py @@ -1,11 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys import os, mapnik -from timeit import Timer, time from nose.tools import * -from utilities import execution_path, run_all, get_unique_colors +from utilities import execution_path, run_all def setup(): # All of the paths used are relative, if we run the tests diff --git a/tests/python_tests/compare_test.py b/tests/python_tests/compare_test.py new file mode 100644 index 000000000..1e9688869 --- /dev/null +++ b/tests/python_tests/compare_test.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os, mapnik +from nose.tools import * +from utilities import execution_path, run_all + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_compare_rgba8(): + im = mapnik.Image(2,2,mapnik.ImageType.rgba8) + im.fill(mapnik.Color(0,0,0,0)) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.rgba8) + im2.fill(mapnik.Color(0,0,0,0)) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + im2.fill(mapnik.Color(0,0,0,12)) + eq_(im.compare(im2), 4) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.rgba8) + im3.set_pixel(0,0, mapnik.Color(0,0,0,0)) + im3.set_pixel(0,1, mapnik.Color(1,1,1,1)) + im3.set_pixel(1,0, mapnik.Color(2,2,2,2)) + im3.set_pixel(1,1, mapnik.Color(3,3,3,3)) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1),2) + eq_(im.compare(im3,2),1) + eq_(im.compare(im3,3),0) + +def test_compare_dimensions(): + im = mapnik.Image(2,2) + im2 = mapnik.Image(3,3) + eq_(im.compare(im2), 4) + eq_(im2.compare(im), 9) + +def test_compare_gray8(): + im = mapnik.Image(2,2,mapnik.ImageType.gray8) + im.fill(0) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.gray8) + im2.fill(0) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.gray8) + im3.set_pixel(0,0,0) + im3.set_pixel(0,1,1) + im3.set_pixel(1,0,2) + im3.set_pixel(1,1,3) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1),2) + eq_(im.compare(im3,2),1) + eq_(im.compare(im3,3),0) + +def test_compare_gray16(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.fill(0) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.gray16) + im2.fill(0) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.gray16) + im3.set_pixel(0,0,0) + im3.set_pixel(0,1,1) + im3.set_pixel(1,0,2) + im3.set_pixel(1,1,3) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1),2) + eq_(im.compare(im3,2),1) + eq_(im.compare(im3,3),0) + +def test_compare_gray32f(): + im = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im.fill(0.5) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im2.fill(0.5) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im3.set_pixel(0,0,0.5) + im3.set_pixel(0,1,1.5) + im3.set_pixel(1,0,2.5) + im3.set_pixel(1,1,3.5) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1.0),2) + eq_(im.compare(im3,2.0),1) + eq_(im.compare(im3,3.0),0) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) diff --git a/tests/python_tests/compositing_test.py b/tests/python_tests/compositing_test.py index fc05525e6..b535311de 100644 --- a/tests/python_tests/compositing_test.py +++ b/tests/python_tests/compositing_test.py @@ -241,10 +241,10 @@ def test_background_image_with_alpha_and_background_color_against_composited_con mapnik.render(m,im) # create and composite the expected result im1 = mapnik.Image(10,10) - im1.background(mapnik.Color('rgba(255,255,255,.5)')) + im1.fill(mapnik.Color('rgba(255,255,255,.5)')) im1.premultiply() im2 = mapnik.Image(10,10) - im2.background(mapnik.Color('rgba(255,255,0,.5)')) + im2.fill(mapnik.Color('rgba(255,255,0,.5)')) im2.premultiply() im1.composite(im2) im1.demultiply() diff --git a/tests/python_tests/grayscale_test.py b/tests/python_tests/grayscale_test.py index cce8c6e31..35f541a87 100644 --- a/tests/python_tests/grayscale_test.py +++ b/tests/python_tests/grayscale_test.py @@ -4,7 +4,7 @@ from utilities import execution_path, run_all def test_grayscale_conversion(): im = mapnik.Image(2,2) - im.background(mapnik.Color('white')) + im.fill(mapnik.Color('white')) im.set_grayscale_to_alpha() pixel = im.get_pixel(0,0) eq_((pixel >> 24) & 0xff,255); diff --git a/tests/python_tests/image_encoding_speed_test.py b/tests/python_tests/image_encoding_speed_test.py index 6fa9f8f06..2b790e913 100644 --- a/tests/python_tests/image_encoding_speed_test.py +++ b/tests/python_tests/image_encoding_speed_test.py @@ -88,7 +88,7 @@ def do_encoding(): def solid(): return eval('image.tostring("%s")' % c) solid_im = mapnik.Image(512,512) - solid_im.background(mapnik.Color("#f2efe9")) + solid_im.fill(mapnik.Color("#f2efe9")) for c in combinations: t = Timer(solid) run(solid,solid_im,c,t) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index a30a86719..dee26e2c5 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -30,7 +30,7 @@ def test_image_premultiply(): def test_image_premultiply_values(): im = mapnik.Image(256,256) - im.background(mapnik.Color(16, 33, 255, 128)) + im.fill(mapnik.Color(16, 33, 255, 128)) im.premultiply() c = im.get_pixel_color(0,0) eq_(c.r, 8) @@ -48,7 +48,7 @@ def test_image_premultiply_values(): def test_background(): im = mapnik.Image(256,256) eq_(im.premultiplied(), False) - im.background(mapnik.Color(32,64,125,128)) + im.fill(mapnik.Color(32,64,125,128)) eq_(im.premultiplied(), False) c = im.get_pixel_color(0,0) eq_(c.get_premultiplied(), False) @@ -57,7 +57,7 @@ def test_background(): eq_(c.b,125) eq_(c.a,128) # Now again with a premultiplied alpha - im.background(mapnik.Color(32,64,125,128,True)) + im.fill(mapnik.Color(32,64,125,128,True)) eq_(im.premultiplied(), True) c = im.get_pixel_color(0,0) eq_(c.get_premultiplied(), True) @@ -127,6 +127,15 @@ def test_set_and_get_pixel(): eq_(c0_pre.b, c1.b) eq_(c0_pre.a, c1.a) +def test_pixel_floats(): + im = mapnik.Image(4,4,mapnik.ImageType.gray32f) + val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1] + for v in val_list: + im.set_pixel(0,0, v) + assert_almost_equal(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + assert_almost_equal(im.get_pixel(0,0), -v) + def test_pixel_overflow(): im = mapnik.Image(4,4,mapnik.ImageType.gray8) im.set_pixel(0,0,256) @@ -171,7 +180,7 @@ def test_get_pixel_color_out_of_range_2(): def test_set_color_to_alpha(): im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(12,12,12,255)')) + im.fill(mapnik.Color('rgba(12,12,12,255)')) eq_(get_unique_colors(im), ['rgba(12,12,12,255)']) im.set_color_to_alpha(mapnik.Color('rgba(12,12,12,0)')) eq_(get_unique_colors(im), ['rgba(0,0,0,0)']) @@ -184,7 +193,7 @@ def test_negative_image_dimensions(): def test_jpeg_round_trip(): filepath = '/tmp/mapnik-jpeg-io.jpeg' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.fill(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'jpeg') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -200,7 +209,7 @@ def test_jpeg_round_trip(): def test_png_round_trip(): filepath = '/tmp/mapnik-png-io.png' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(1,2,3,.5)')) + im.fill(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'png') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index a2c524f90..4dbcf3223 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -19,7 +19,7 @@ def setup(): def test_tiff_round_trip_scanline(): filepath = '/tmp/mapnik-tiff-io-scanline.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(12,255,128,.5)')) + im.fill(mapnik.Color('rgba(12,255,128,.5)')) org_str = hashstr(im.tostring()) im.save(filepath,'tiff:method=scanline') im2 = mapnik.Image.open(filepath) @@ -42,7 +42,7 @@ def test_tiff_round_trip_scanline(): def test_tiff_round_trip_stripped(): filepath = '/tmp/mapnik-tiff-io-stripped.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(12,255,128,.5)')) + im.fill(mapnik.Color('rgba(12,255,128,.5)')) org_str = hashstr(im.tostring()) im.save(filepath,'tiff:method=stripped') im2 = mapnik.Image.open(filepath) @@ -68,7 +68,7 @@ def test_tiff_round_trip_rows_stripped(): filepath = '/tmp/mapnik-tiff-io-rows_stripped.tiff' filepath2 = '/tmp/mapnik-tiff-io-rows_stripped2.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(12,255,128,.5)')) + im.fill(mapnik.Color('rgba(12,255,128,.5)')) c = im.get_pixel_color(0,0) eq_(c.r, 12) eq_(c.g, 255) @@ -105,7 +105,7 @@ def test_tiff_round_trip_buffered_tiled(): filepath2 = '/tmp/mapnik-tiff-io-buffered-tiled2.tiff' filepath3 = '/tmp/mapnik-tiff-io-buffered-tiled3.tiff' im = mapnik.Image(255,267) - im.background(mapnik.Color('rgba(33,255,128,.5)')) + im.fill(mapnik.Color('rgba(33,255,128,.5)')) c = im.get_pixel_color(0,0) eq_(c.r, 33) eq_(c.g, 255) @@ -142,7 +142,7 @@ def test_tiff_round_trip_buffered_tiled(): def test_tiff_round_trip_tiled(): filepath = '/tmp/mapnik-tiff-io-tiled.tiff' im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(1,255,128,.5)')) + im.fill(mapnik.Color('rgba(1,255,128,.5)')) im.save(filepath,'tiff:method=tiled') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) diff --git a/tests/python_tests/png_encoding_test.py b/tests/python_tests/png_encoding_test.py index 89bb02ad8..cbb5b4d4c 100644 --- a/tests/python_tests/png_encoding_test.py +++ b/tests/python_tests/png_encoding_test.py @@ -61,7 +61,7 @@ if mapnik.has_png(): '%s (actual) not == to %s (expected)' % (actual,expected)) # solid image - im.background(mapnik.Color('green')) + im.fill(mapnik.Color('green')) for opt in opts: expected = gen_filepath('blank',opt) actual = os.path.join(tmp_dir,os.path.basename(expected)) @@ -91,7 +91,7 @@ if mapnik.has_png(): def test_transparency_levels(): # create partial transparency image im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(255,255,255,.5)')) + im.fill(mapnik.Color('rgba(255,255,255,.5)')) c2 = mapnik.Color('rgba(255,255,0,.2)') c3 = mapnik.Color('rgb(0,255,255)') for y in range(0,im.height()/2): diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index 5fa4dd463..abdb0a518 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -25,7 +25,7 @@ def test_simplest_render(): def test_render_image_to_string(): im = mapnik.Image(256, 256) - im.background(mapnik.Color('black')) + im.fill(mapnik.Color('black')) eq_(im.painted(),False) eq_(im.is_solid(),True) s = im.tostring() @@ -33,7 +33,7 @@ def test_render_image_to_string(): def test_non_solid_image(): im = mapnik.Image(256, 256) - im.background(mapnik.Color('black')) + im.fill(mapnik.Color('black')) eq_(im.painted(),False) eq_(im.is_solid(),True) # set one pixel to a different color @@ -43,7 +43,7 @@ def test_non_solid_image(): def test_non_solid_image_view(): im = mapnik.Image(256, 256) - im.background(mapnik.Color('black')) + im.fill(mapnik.Color('black')) view = im.view(0,0,256,256) eq_(view.is_solid(),True) # set one pixel to a different color @@ -61,13 +61,13 @@ def test_setting_alpha(): im1 = mapnik.Image(w,h) # white, half transparent c1 = mapnik.Color('rgba(255,255,255,.5)') - im1.background(c1) + im1.fill(c1) eq_(im1.painted(),False) eq_(im1.is_solid(),True) # pure white im2 = mapnik.Image(w,h) c2 = mapnik.Color('rgba(255,255,255,1)') - im2.background(c2) + im2.fill(c2) im2.set_alpha(c1.a/255.0) eq_(im2.painted(),False) eq_(im2.is_solid(),True) @@ -75,7 +75,7 @@ def test_setting_alpha(): def test_render_image_to_file(): im = mapnik.Image(256, 256) - im.background(mapnik.Color('black')) + im.fill(mapnik.Color('black')) if mapnik.has_jpeg(): im.save('test.jpg') im.save('test.png', 'png') diff --git a/tests/python_tests/webp_encoding_test.py b/tests/python_tests/webp_encoding_test.py index 8f2ebf630..642f37210 100644 --- a/tests/python_tests/webp_encoding_test.py +++ b/tests/python_tests/webp_encoding_test.py @@ -84,7 +84,7 @@ if mapnik.has_webp(): for opt in opts: im = mapnik.Image(256,256) - im.background(mapnik.Color('green')) + im.fill(mapnik.Color('green')) expected = gen_filepath('solid',opt) actual = os.path.join(tmp_dir,os.path.basename(expected)) if generate or not os.path.exists(expected): @@ -125,7 +125,7 @@ if mapnik.has_webp(): try: # create partial transparency image im = mapnik.Image(256,256) - im.background(mapnik.Color('rgba(255,255,255,.5)')) + im.fill(mapnik.Color('rgba(255,255,255,.5)')) c2 = mapnik.Color('rgba(255,255,0,.2)') c3 = mapnik.Color('rgb(0,255,255)') for y in range(0,im.height()/2): From 5a4f9321d0d5f8367dd78a8517bc06cd83a97333 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 29 Jan 2015 16:10:56 -0700 Subject: [PATCH 74/91] A few updates to attempt to fix pixel getting and setting --- bindings/python/mapnik_image.cpp | 2 +- include/mapnik/image_util.hpp | 13 ++++++++----- src/image_util.cpp | 19 +++++++++++++------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index a3432f40f..425abf12d 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -197,7 +197,7 @@ mapnik::color get_pixel_color(mapnik::image_any const& im, unsigned x, unsigned { if (x < static_cast(im.width()) && y < static_cast(im.height())) { - return mapnik::get_pixel(im, x, y); + return mapnik::get_pixel(im, x, y); } PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); boost::python::throw_error_already_set(); diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 3747999e7..40f1378dc 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -161,6 +161,9 @@ MAPNIK_DECL bool check_bounds (T const& data, std::size_t x, std::size_t y) template MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); +template +MAPNIK_DECL void set_pixel(image_any & data, std::size_t x, std::size_t y, T const& val); + template MAPNIK_DECL void set_pixel(image_rgba8 & data, std::size_t x, std::size_t y, T const& val); @@ -173,8 +176,11 @@ MAPNIK_DECL void set_pixel(image_gray16 & data, std::size_t x, std::size_t y, T template MAPNIK_DECL void set_pixel(image_gray32f & data, std::size_t x, std::size_t y, T const& val); -template -MAPNIK_DECL void set_pixel(T1 & data, std::size_t x, std::size_t y, T2 const& val); +template +MAPNIK_DECL T get_pixel(image_any const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_any const& data, std::size_t x, std::size_t y); template MAPNIK_DECL T get_pixel(image_rgba8 const& data, std::size_t x, std::size_t y); @@ -188,9 +194,6 @@ MAPNIK_DECL T get_pixel(image_gray16 const& data, std::size_t x, std::size_t y); template MAPNIK_DECL T get_pixel(image_gray32f const& data, std::size_t x, std::size_t y); -template -MAPNIK_DECL T2 get_pixel(T1 const& data, std::size_t x, std::size_t y); - MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss); MAPNIK_DECL image_view_any create_view (image_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); diff --git a/src/image_util.cpp b/src/image_util.cpp index a4fce8bde..f0cd535dd 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -1218,10 +1218,10 @@ struct visitor_set_pixel } // end detail ns // For all the generic data types. -template -MAPNIK_DECL void set_pixel (T1 & data, std::size_t x, std::size_t y, T2 const& val) +template +MAPNIK_DECL void set_pixel (image_any & data, std::size_t x, std::size_t y, T const& val) { - util::apply_visitor(detail::visitor_set_pixel(x, y, val), data); + util::apply_visitor(detail::visitor_set_pixel(x, y, val), data); } template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, color const&); @@ -1355,10 +1355,10 @@ struct visitor_get_pixel } // end detail ns // For all the generic data types. -template -MAPNIK_DECL T2 get_pixel (T1 const& data, std::size_t x, std::size_t y) +template +MAPNIK_DECL T get_pixel (image_any const& data, std::size_t x, std::size_t y) { - return util::apply_visitor(detail::visitor_get_pixel(x, y), data); + return util::apply_visitor(detail::visitor_get_pixel(x, y), data); } template MAPNIK_DECL color get_pixel(image_any const&, std::size_t, std::size_t); @@ -1370,6 +1370,13 @@ template MAPNIK_DECL uint8_t get_pixel(image_any const&, std::size_t, std::size_ template MAPNIK_DECL int8_t get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL float get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL double get_pixel(image_any const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_any const& data, std::size_t x, std::size_t y) +{ + return util::apply_visitor(detail::visitor_get_pixel(x, y), data); +} + template MAPNIK_DECL color get_pixel(image_view_any const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_view_any const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_view_any const&, std::size_t, std::size_t); From 0e017be98d8a05cff77c1e6f09acda0a4af2c4b6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 3 Feb 2015 00:38:55 -0800 Subject: [PATCH 75/91] merge with master + fixups --- tests/python_tests/datasource_test.py | 2 +- tests/python_tests/image_test.py | 2 +- tests/python_tests/image_tiff_test.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/python_tests/datasource_test.py b/tests/python_tests/datasource_test.py index 62a6fab52..4ada3dc3c 100644 --- a/tests/python_tests/datasource_test.py +++ b/tests/python_tests/datasource_test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from nose.tools import eq_ +from nose.tools import eq_, raises from utilities import execution_path, run_all import os, mapnik from itertools import groupby diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index 800da573c..79ac92e33 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- import os, mapnik -from nose.tools import eq_,raises +from nose.tools import eq_,raises, assert_almost_equal from utilities import execution_path, run_all, get_unique_colors def setup(): diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index 403370330..d8e4f6c1c 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -3,7 +3,7 @@ import os, mapnik import hashlib -from nose.tools import eq_ +from nose.tools import eq_, assert_not_equal from utilities import execution_path, run_all def hashstr(var): From 2b8bd59d820ff79f4027a86a2094e5151e2a5fea Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 4 Feb 2015 15:41:58 -0600 Subject: [PATCH 76/91] A large set of updates: * Added new gray data types adding those to the variants and updating all the code necessary for them * Added basic SSE to the image compare method, (only for RGBA) must be enabled with the -DSSE_MATH flag this is not yet put into the build process in any location. * Fixed the resulting image for some TIFF visual tests, most likely they were incorrect due to fixes in TIFF reader * Added some MAPNIK_DECL where necessary to grid rendering. * Added support for more data types in GDAL plugin with grayscale images. * Added views for all the new gray data types * Updated python bindings for new gray data types. Ref #2681 --- bindings/python/mapnik_image.cpp | 28 +- include/mapnik/grid/grid.hpp | 11 +- include/mapnik/grid/grid_view.hpp | 2 +- include/mapnik/image.hpp | 35 +- include/mapnik/image_any.hpp | 9 +- include/mapnik/image_cast.hpp | 21 + include/mapnik/image_scaling_traits.hpp | 77 + include/mapnik/image_util.hpp | 209 ++- include/mapnik/image_view.hpp | 8 + include/mapnik/image_view_any.hpp | 9 +- include/mapnik/pixel_types.hpp | 41 + .../process_group_symbolizer.hpp | 14 + include/mapnik/sse.hpp | 40 + include/mapnik/tiff_io.hpp | 97 ++ include/mapnik/value_types.hpp | 3 + include/mapnik/webp_io.hpp | 2 +- plugins/input/gdal/gdal_featureset.cpp | 96 +- src/feature_style_processor.cpp | 8 +- src/grid/grid.cpp | 4 +- src/grid/grid_renderer.cpp | 2 +- src/image_cast.cpp | 119 ++ src/image_scaling.cpp | 20 + src/image_util.cpp | 1338 +++++++++++++---- src/image_util_jpeg.cpp | 28 +- src/image_util_png.cpp | 56 +- src/image_util_tiff.cpp | 30 +- src/image_util_webp.cpp | 14 + src/raster_colorizer.cpp | 21 + .../process_group_symbolizer.cpp | 81 +- src/tiff_reader.cpp | 125 +- src/warp.cpp | 4 +- tests/python_tests/compare_test.py | 10 +- tests/python_tests/image_test.py | 3 + ...edge-raster2-600-400-1.0-agg-reference.png | Bin 8208 -> 8211 bytes ...ge-raster2-600-400-1.0-cairo-reference.png | Bin 8208 -> 8211 bytes ...edge-raster2-600-400-2.0-agg-reference.png | Bin 8208 -> 8211 bytes ...ge-raster2-600-400-2.0-cairo-reference.png | Bin 8208 -> 8211 bytes ...edge-raster2-969-793-1.0-agg-reference.png | Bin 8907 -> 8913 bytes ...ge-raster2-969-793-1.0-cairo-reference.png | Bin 8907 -> 8913 bytes ...edge-raster2-969-793-2.0-agg-reference.png | Bin 8907 -> 8913 bytes ...ge-raster2-969-793-2.0-cairo-reference.png | Bin 8907 -> 8913 bytes 41 files changed, 2087 insertions(+), 478 deletions(-) create mode 100644 include/mapnik/pixel_types.hpp create mode 100644 include/mapnik/sse.hpp diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 425abf12d..3dfbc0f27 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -157,25 +157,22 @@ struct get_pixel_visitor throw std::runtime_error("Can not return a null image from a pixel (shouldn't have reached here)"); } - PyObject* operator() (mapnik::image_rgba8 const& im) + template + PyObject* operator() (T const& im) { - return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); - } - - PyObject* operator() (mapnik::image_gray8 const& im) - { - return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); - } - - PyObject* operator() (mapnik::image_gray16 const& im) - { - return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); + using pixel_type = typename T::pixel_type; + return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); } PyObject* operator() (mapnik::image_gray32f const& im) { return PyFloat_FromDouble(mapnik::get_pixel(im, x_, y_)); } + + PyObject* operator() (mapnik::image_gray64f const& im) + { + return PyFloat_FromDouble(mapnik::get_pixel(im, x_, y_)); + } private: unsigned x_; @@ -388,8 +385,15 @@ void export_image() enum_("ImageType") .value("rgba8", mapnik::image_dtype_rgba8) .value("gray8", mapnik::image_dtype_gray8) + .value("gray8s", mapnik::image_dtype_gray8s) .value("gray16", mapnik::image_dtype_gray16) + .value("gray16s", mapnik::image_dtype_gray16s) + .value("gray32", mapnik::image_dtype_gray32) + .value("gray32s", mapnik::image_dtype_gray32s) .value("gray32f", mapnik::image_dtype_gray32f) + .value("gray64", mapnik::image_dtype_gray64) + .value("gray64s", mapnik::image_dtype_gray64s) + .value("gray64f", mapnik::image_dtype_gray64f) ; class_, boost::noncopyable >("Image","This class represents a image.",init()) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 2aa423854..053f5ef85 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -49,8 +49,8 @@ template class MAPNIK_DECL hit_grid { public: - using value_type = T; - using data_type = mapnik::image; + using value_type = typename T::type; + using data_type = mapnik::image; using lookup_type = std::string; // mapping between pixel id and key using feature_key_type = std::map; @@ -147,12 +147,12 @@ public: return data_; } - inline T const * raw_data() const + inline value_type const * raw_data() const { return data_.getData(); } - inline T* raw_data() + inline value_type* raw_data() { return data_.getData(); } @@ -222,10 +222,9 @@ public: } } } - }; -using grid = hit_grid; +using grid = hit_grid; } #endif //MAPNIK_GRID_HPP diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index 2db982e5c..43c50da88 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -196,7 +196,7 @@ private: feature_type const& features_; }; -using grid_view = hit_grid_view >; +using grid_view = hit_grid_view >; } diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index 850f6e192..e9796e3db 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -25,6 +25,8 @@ // mapnik #include +#include + // stl #include #include @@ -120,7 +122,8 @@ template class image { public: - using pixel_type = T; + using pixel = T; + using pixel_type = typename T::type; static constexpr std::size_t pixel_size = sizeof(pixel_type); private: detail::image_dimensions dimensions_; @@ -143,7 +146,7 @@ public: if (pData_ && initialize) std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), 0); } - image(image const& rhs) + image(image const& rhs) : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), pData_(reinterpret_cast(buffer_.data())), @@ -153,7 +156,7 @@ public: painted_(rhs.painted_) {} - image(image && rhs) noexcept + image(image && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), buffer_(std::move(rhs.buffer_)), pData_(reinterpret_cast(buffer_.data())), @@ -166,13 +169,13 @@ public: rhs.pData_ = nullptr; } - image& operator=(image rhs) + image& operator=(image rhs) { swap(rhs); return *this; } - void swap(image & rhs) + void swap(image & rhs) { std::swap(dimensions_, rhs.dimensions_); std::swap(buffer_, rhs.buffer_); @@ -312,17 +315,31 @@ public: } }; -using image_rgba8 = image; -using image_gray8 = image ; -using image_gray16 = image; -using image_gray32f = image; +using image_rgba8 = image; +using image_gray8 = image; +using image_gray8s = image; +using image_gray16 = image; +using image_gray16s = image; +using image_gray32 = image; +using image_gray32s = image; +using image_gray32f = image; +using image_gray64 = image; +using image_gray64s = image; +using image_gray64f = image; enum image_dtype : std::uint8_t { image_dtype_rgba8 = 0, image_dtype_gray8, + image_dtype_gray8s, image_dtype_gray16, + image_dtype_gray16s, + image_dtype_gray32, + image_dtype_gray32s, image_dtype_gray32f, + image_dtype_gray64, + image_dtype_gray64s, + image_dtype_gray64f, image_dtype_null }; diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index db7e6bd69..2745886ce 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -58,8 +58,15 @@ struct image_null using image_base = util::variant; + image_gray16s, + image_gray32, + image_gray32s, + image_gray32f, + image_gray64, + image_gray64s, + image_gray64f>; // Forward declaring struct image_any; diff --git a/include/mapnik/image_cast.hpp b/include/mapnik/image_cast.hpp index 45098a819..320c41788 100644 --- a/include/mapnik/image_cast.hpp +++ b/include/mapnik/image_cast.hpp @@ -38,12 +38,33 @@ MAPNIK_DECL T image_cast(image_rgba8 const&, double offset = 0.0, double scaling template MAPNIK_DECL T image_cast(image_gray8 const&, double offset = 0.0, double scaling = 1.0); +template +MAPNIK_DECL T image_cast(image_gray8s const&, double offset = 0.0, double scaling = 1.0); + template MAPNIK_DECL T image_cast(image_gray16 const&, double offset = 0.0, double scaling = 1.0); +template +MAPNIK_DECL T image_cast(image_gray16s const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_cast(image_gray32 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_cast(image_gray32s const&, double offset = 0.0, double scaling = 1.0); + template MAPNIK_DECL T image_cast(image_gray32f const&, double offset = 0.0, double scaling = 1.0); +template +MAPNIK_DECL T image_cast(image_gray64 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_cast(image_gray64s const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_cast(image_gray64f const&, double offset = 0.0, double scaling = 1.0); + MAPNIK_DECL image_any image_cast(image_any const&, image_dtype type, double offset = 0.0, double scaling = 1.0); } // end mapnik ns diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp index c891b37df..9b783062c 100644 --- a/include/mapnik/image_scaling_traits.hpp +++ b/include/mapnik/image_scaling_traits.hpp @@ -60,6 +60,17 @@ struct agg_scaling_traits using span_image_resample_affine = agg::span_image_resample_gray_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 { @@ -71,6 +82,39 @@ struct agg_scaling_traits 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 <> +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 <> struct agg_scaling_traits { @@ -82,6 +126,39 @@ struct agg_scaling_traits 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 <> +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 <> +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 set_scaling_method(Filter & filter, scaling_method_e scaling_method, double filter_factor) { diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 40f1378dc..b2b723e8b 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -110,30 +110,54 @@ MAPNIK_DECL void save_to_stream std::string const& type ); +// PREMULTIPLY ALPHA +MAPNIK_DECL bool premultiply_alpha(image_any & image); + template MAPNIK_DECL bool premultiply_alpha(T & image); +// DEMULTIPLY ALPHA +MAPNIK_DECL bool demultiply_alpha(image_any & image); + template MAPNIK_DECL bool demultiply_alpha(T & image); +// SET PREMULTIPLIED ALPHA +MAPNIK_DECL void set_premultiplied_alpha(image_any & image, bool status); + template MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status); +// IS SOLID +MAPNIK_DECL bool is_solid (image_any const& image); +MAPNIK_DECL bool is_solid (image_view_any const& image); + template MAPNIK_DECL bool is_solid (T const& image); +// SET ALPHA +MAPNIK_DECL void set_alpha (image_any & image, float opacity); + template MAPNIK_DECL void set_alpha (T & image, float opacity); +// SET GRAYSCALE TO ALPHA +MAPNIK_DECL void set_grayscale_to_alpha (image_any & image); +MAPNIK_DECL void set_grayscale_to_alpha (image_any & image, color const& c); + template MAPNIK_DECL void set_grayscale_to_alpha (T & image); template MAPNIK_DECL void set_grayscale_to_alpha (T & image, color const& c); +// SET COLOR TO ALPHA +MAPNIK_DECL void set_color_to_alpha (image_any & image, color const& c); + template MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); +// FILL template MAPNIK_DECL void fill (image_any & data, T const&); @@ -143,24 +167,53 @@ MAPNIK_DECL void fill (image_rgba8 & data, T const&); template MAPNIK_DECL void fill (image_gray8 & data, T const&); +template +MAPNIK_DECL void fill (image_gray8s & data, T const&); + template MAPNIK_DECL void fill (image_gray16 & data, T const&); +template +MAPNIK_DECL void fill (image_gray16s & data, T const&); + +template +MAPNIK_DECL void fill (image_gray32 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray32s & data, T const&); + template MAPNIK_DECL void fill (image_gray32f & data, T const&); +template +MAPNIK_DECL void fill (image_gray64 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray64s & data, T const&); + +template +MAPNIK_DECL void fill (image_gray64f & data, T const&); + +// SET RECTANGLE +MAPNIK_DECL void set_rectangle (image_any & dst, image_any const& src, int x = 0, int y = 0); + template MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); +// CHECK BOUNDS template MAPNIK_DECL bool check_bounds (T const& data, std::size_t x, std::size_t y) { return (x < static_cast(data.width()) && y < static_cast(data.height())); } +// COMPOSITE_PIXEL +MAPNIK_DECL void composite_pixel(image_any & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); + template MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); +// SET PIXEL template MAPNIK_DECL void set_pixel(image_any & data, std::size_t x, std::size_t y, T const& val); @@ -170,12 +223,34 @@ MAPNIK_DECL void set_pixel(image_rgba8 & data, std::size_t x, std::size_t y, T c template MAPNIK_DECL void set_pixel(image_gray8 & data, std::size_t x, std::size_t y, T const& val); +template +MAPNIK_DECL void set_pixel(image_gray8s & data, std::size_t x, std::size_t y, T const& val); + template MAPNIK_DECL void set_pixel(image_gray16 & data, std::size_t x, std::size_t y, T const& val); +template +MAPNIK_DECL void set_pixel(image_gray16s & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray32 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray32s & data, std::size_t x, std::size_t y, T const& val); + template MAPNIK_DECL void set_pixel(image_gray32f & data, std::size_t x, std::size_t y, T const& val); +template +MAPNIK_DECL void set_pixel(image_gray64 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray64s & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray64f & data, std::size_t x, std::size_t y, T const& val); + +// GET PIXEL template MAPNIK_DECL T get_pixel(image_any const& data, std::size_t x, std::size_t y); @@ -188,16 +263,73 @@ MAPNIK_DECL T get_pixel(image_rgba8 const& data, std::size_t x, std::size_t y); template MAPNIK_DECL T get_pixel(image_gray8 const& data, std::size_t x, std::size_t y); +template +MAPNIK_DECL T get_pixel(image_gray8s const& data, std::size_t x, std::size_t y); + template MAPNIK_DECL T get_pixel(image_gray16 const& data, std::size_t x, std::size_t y); +template +MAPNIK_DECL T get_pixel(image_gray16s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray32 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray32s const& data, std::size_t x, std::size_t y); + template MAPNIK_DECL T get_pixel(image_gray32f const& data, std::size_t x, std::size_t y); +template +MAPNIK_DECL T get_pixel(image_gray64 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray64s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray64f const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_rgba8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray8s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray16 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray16s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray32 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray32s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray32f const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray64 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray64s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray64f const& data, std::size_t x, std::size_t y); + +// VIEW TO STRING MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss); +// CREATE VIEW MAPNIK_DECL image_view_any create_view (image_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); +// COMPARE template MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold = 0, bool alpha = true); @@ -277,83 +409,6 @@ void add_border(T & image) } } -/* -extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, - std::string const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_any const&, - std::string const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, - std::string const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file(image_any const&, - std::string const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_any const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_rgba8 const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file(image_any const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file(image_view_any const&, - std::string const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_view_any const&, - std::string const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file(image_view_any const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_view_any const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL std::string save_to_string (image_view_rgba8 const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string (image_view_rgba8 const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL std::string save_to_string(image_any const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string(image_any const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL std::string save_to_string (image_view_any const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string (image_view_any const&, - std::string const&, - rgba_palette const&); -*/ #ifdef _MSC_VER template MAPNIK_DECL void save_to_stream( diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 96cda875d..640235ac5 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -31,6 +31,7 @@ template class image_view { public: + using pixel = typename T::pixel; using pixel_type = typename T::pixel_type; static constexpr std::size_t pixel_size = sizeof(pixel_type); @@ -141,8 +142,15 @@ private: using image_view_rgba8 = image_view; using image_view_gray8 = image_view; +using image_view_gray8s = image_view; using image_view_gray16 = image_view; +using image_view_gray16s = image_view; +using image_view_gray32 = image_view; +using image_view_gray32s = image_view; using image_view_gray32f = image_view; +using image_view_gray64 = image_view; +using image_view_gray64s = image_view; +using image_view_gray64f = image_view; } // end ns diff --git a/include/mapnik/image_view_any.hpp b/include/mapnik/image_view_any.hpp index 425981612..9f47f0ae4 100644 --- a/include/mapnik/image_view_any.hpp +++ b/include/mapnik/image_view_any.hpp @@ -30,8 +30,15 @@ namespace mapnik { using image_view_base = util::variant; + image_view_gray16s, + image_view_gray32, + image_view_gray32s, + image_view_gray32f, + image_view_gray64, + image_view_gray64s, + image_view_gray64f>; namespace detail { diff --git a/include/mapnik/pixel_types.hpp b/include/mapnik/pixel_types.hpp new file mode 100644 index 000000000..5990a3b20 --- /dev/null +++ b/include/mapnik/pixel_types.hpp @@ -0,0 +1,41 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_PIXEL_TYPES_HPP +#define MAPNIK_PIXEL_TYPES_HPP + +// std +#include + +struct rgba8_t { using type = std::uint32_t; }; +struct gray8_t { using type = std::uint8_t; }; +struct gray8s_t { using type = std::int8_t; }; +struct gray16_t { using type = std::uint16_t; }; +struct gray16s_t { using type = std::int16_t; }; +struct gray32_t { using type = std::uint32_t; }; +struct gray32s_t { using type = std::int32_t; }; +struct gray32f_t { using type = float; }; +struct gray64_t { using type = std::uint64_t; }; +struct gray64s_t { using type = std::int64_t; }; +struct gray64f_t { using type = double; }; + +#endif // MAPNIK_PIXEL_TYPES_HPP diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index f0b7e2f75..44eb09450 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -152,8 +152,15 @@ struct raster_marker_render_thunk : util::noncopyable template struct raster_marker_render_thunk; template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; +template struct raster_marker_render_thunk; using helper_ptr = std::unique_ptr; @@ -186,8 +193,15 @@ struct text_render_thunk : util::noncopyable using render_thunk = util::variant, raster_marker_render_thunk, + raster_marker_render_thunk, raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, + raster_marker_render_thunk, text_render_thunk>; using render_thunk_ptr = std::unique_ptr; using render_thunk_list = std::list; diff --git a/include/mapnik/sse.hpp b/include/mapnik/sse.hpp new file mode 100644 index 000000000..ddf877812 --- /dev/null +++ b/include/mapnik/sse.hpp @@ -0,0 +1,40 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_SSE_HPP +#define MAPNIK_SSE_HPP + +#include +#include + +#define ROUND_DOWN(x, s) ((x) & ~((s)-1)) + +typedef union +{ + __m128i v; + int32_t i32[4]; + uint32_t u32[4]; + uint16_t u16[8]; + uint8_t u8[16]; +} m128_int; + +#endif // MAPNIK_SSE_HPP diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index f729ca31a..ab56a3282 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -217,6 +217,75 @@ struct tag_setter } } + inline void operator() (image_gray64 const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 64); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray64s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 64); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray64f const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 64); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT); + } + } + inline void operator() (image_gray32 const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray32s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } inline void operator() (image_gray32f const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); @@ -244,6 +313,20 @@ struct tag_setter } } + inline void operator() (image_gray16s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } inline void operator() (image_gray8 const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); @@ -258,6 +341,20 @@ struct tag_setter } } + inline void operator() (image_gray8s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } inline void operator() (image_null const&) const { // Assume this would be null type diff --git a/include/mapnik/value_types.hpp b/include/mapnik/value_types.hpp index ffe021869..fd5feaee5 100644 --- a/include/mapnik/value_types.hpp +++ b/include/mapnik/value_types.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include // icu #include // for U_NAMESPACE_QUALIFIER @@ -43,8 +44,10 @@ namespace mapnik { #ifdef BIGINT //using value_integer = boost::long_long_type; using value_integer = long long; +using value_integer_pixel = gray64s_t; #else using value_integer = int; +using value_integer_pixel = gray32s_t; #endif using value_double = double; diff --git a/include/mapnik/webp_io.hpp b/include/mapnik/webp_io.hpp index a65792f55..6236d260c 100644 --- a/include/mapnik/webp_io.hpp +++ b/include/mapnik/webp_io.hpp @@ -77,7 +77,7 @@ inline int import_image(T2 const& im_in, WebPPicture & pic, bool alpha) { - image const& data = im_in.data(); + image const& data = im_in.data(); int stride = sizeof(typename T2::pixel_type) * im_in.width(); if (data.width() == im_in.width() && data.height() == im_in.height()) diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 55f8e0f65..8ec66f27e 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -203,29 +203,95 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; if (band_ > 0) // we are querying a single band { - mapnik::image_gray16 image(im_width, im_height); - image.set(std::numeric_limits::max()); + GDALRasterBand * band = dataset_.GetRasterBand(band_); if (band_ > nbands_) { std::ostringstream s; s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands"; throw datasource_exception(s.str()); } - - GDALRasterBand * band = dataset_.GetRasterBand(band_); - raster_nodata = band->GetNoDataValue(&raster_has_nodata); - raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, - image.getData(), image.width(), image.height(), - GDT_Int16, 0, 0); - if (raster_io_error == CE_Failure) + GDALDataType band_type = band->GetRasterDataType(); + switch (band_type) { - throw datasource_exception(CPLGetLastErrorMsg()); + case GDT_Byte: + { + mapnik::image_gray8 image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_Byte, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } + case GDT_Float64: + case GDT_Float32: + { + mapnik::image_gray32f image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_Float32, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } + case GDT_UInt16: + { + mapnik::image_gray16 image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_UInt16, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } + default: + case GDT_Int16: + { + mapnik::image_gray16s image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_Int16, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } } - mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); - // set nodata value to be used in raster colorizer - if (nodata_value_) raster->set_nodata(*nodata_value_); - else raster->set_nodata(raster_nodata); - feature->set_raster(raster); } else // working with all bands { diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 3d845e4bc..94bfa6bbb 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -44,17 +44,17 @@ namespace mapnik { #if defined(HAVE_CAIRO) -template class feature_style_processor >; +template class MAPNIK_DECL feature_style_processor >; #endif #if defined(SVG_RENDERER) -template class feature_style_processor > >; +template class MAPNIK_DECL feature_style_processor > >; #endif #if defined(GRID_RENDERER) -template class feature_style_processor >; +template class MAPNIK_DECL feature_style_processor >; #endif -template class feature_style_processor >; +template class MAPNIK_DECL feature_style_processor >; } diff --git a/src/grid/grid.cpp b/src/grid/grid.cpp index 434e1bca9..0afefed28 100644 --- a/src/grid/grid.cpp +++ b/src/grid/grid.cpp @@ -34,7 +34,7 @@ namespace mapnik { template -const typename hit_grid::value_type hit_grid::base_mask = std::numeric_limits::min(); +const typename hit_grid::value_type hit_grid::base_mask = std::numeric_limits::min(); template hit_grid::hit_grid(int width, int height, std::string const& key, unsigned int resolution) @@ -146,7 +146,7 @@ void hit_grid::add_feature(mapnik::feature_impl const& feature) } -template class hit_grid; +template class MAPNIK_DECL hit_grid; } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index ccf258632..427435667 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -194,7 +194,7 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ pixmap_.add_feature(feature); } -template class grid_renderer; +template class MAPNIK_DECL grid_renderer; } diff --git a/src/image_cast.cpp b/src/image_cast.cpp index 56e820d50..a26323d00 100644 --- a/src/image_cast.cpp +++ b/src/image_cast.cpp @@ -177,6 +177,21 @@ MAPNIK_DECL T image_cast(image_gray8 const& data, double offset, double scaling) } } +template +MAPNIK_DECL T image_cast(image_gray8s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + template MAPNIK_DECL T image_cast(image_gray16 const& data, double offset, double scaling) { @@ -192,6 +207,51 @@ MAPNIK_DECL T image_cast(image_gray16 const& data, double offset, double scaling } } +template +MAPNIK_DECL T image_cast(image_gray16s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray32 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray32s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + template MAPNIK_DECL T image_cast(image_gray32f const& data, double offset, double scaling) { @@ -207,6 +267,51 @@ MAPNIK_DECL T image_cast(image_gray32f const& data, double offset, double scalin } } +template +MAPNIK_DECL T image_cast(image_gray64 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray64s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_cast(image_gray64f const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_cast visit; + return visit(data); + } + else + { + detail::visitor_image_cast_so visit(offset, scaling); + return visit(data); + } +} + MAPNIK_DECL image_any image_cast(image_any const& data, image_dtype type, double offset, double scaling) { switch (type) @@ -215,10 +320,24 @@ MAPNIK_DECL image_any image_cast(image_any const& data, image_dtype type, double return image_any(std::move(image_cast(data, offset, scaling))); case image_dtype_gray8: return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray8s: + return image_any(std::move(image_cast(data, offset, scaling))); case image_dtype_gray16: return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray16s: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray32: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray32s: + return image_any(std::move(image_cast(data, offset, scaling))); case image_dtype_gray32f: return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray64: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray64s: + return image_any(std::move(image_cast(data, offset, scaling))); + case image_dtype_gray64f: + return image_any(std::move(image_cast(data, offset, scaling))); case image_dtype_null: throw std::runtime_error("Can not cast a null image"); } diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index 76bf931d3..42a96eb1c 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -171,10 +171,30 @@ template MAPNIK_DECL void scale_image_agg(image_rgba8 &, image_rgba8 const&, sca template MAPNIK_DECL void scale_image_agg(image_gray8 &, image_gray8 const&, scaling_method_e, double, double , double, double , double); +template MAPNIK_DECL void scale_image_agg(image_gray8s &, image_gray8s const&, scaling_method_e, + double, double , double, double , double); + template MAPNIK_DECL void scale_image_agg(image_gray16 &, image_gray16 const&, scaling_method_e, double, double , double, double , double); +template MAPNIK_DECL void scale_image_agg(image_gray16s &, image_gray16s const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray32 &, image_gray32 const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray32s &, image_gray32s const&, scaling_method_e, + double, double , double, double , double); + template MAPNIK_DECL void scale_image_agg(image_gray32f &, image_gray32f const&, scaling_method_e, double, double , double, double , double); +template MAPNIK_DECL void scale_image_agg(image_gray64 &, image_gray64 const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray64s &, image_gray64s const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray64f &, image_gray64f const&, scaling_method_e, + double, double , double, double , double); } diff --git a/src/image_util.cpp b/src/image_util.cpp index f0cd535dd..362323555 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -35,6 +35,10 @@ #include #include #include +#ifdef SSE_MATH +#include + +#endif // agg #include "agg_rendering_buffer.h" @@ -50,6 +54,7 @@ // boost #include + using boost::numeric_cast; using boost::numeric::positive_overflow; using boost::numeric::negative_overflow; @@ -405,6 +410,11 @@ namespace detail { struct is_solid_visitor { + bool operator() (image_null const&) + { + return true; + } + template bool operator() (T const & data) { @@ -429,98 +439,83 @@ struct is_solid_visitor } }; -template bool is_solid_visitor::operator() (image_rgba8 const& data); -template bool is_solid_visitor::operator() (image_gray8 const& data); -template bool is_solid_visitor::operator() (image_gray16 const& data); -template bool is_solid_visitor::operator() (image_gray32f const& data); -template bool is_solid_visitor::operator() (image_view_rgba8 const& data); -template bool is_solid_visitor::operator() (image_view_gray8 const& data); -template bool is_solid_visitor::operator() (image_view_gray16 const& data); -template bool is_solid_visitor::operator() (image_view_gray32f const& data); - -template<> -bool is_solid_visitor::operator() (image_null const&) -{ - return true; -} - } // end detail ns -template -MAPNIK_DECL bool is_solid(T const& image) +MAPNIK_DECL bool is_solid(image_any const& image) { return util::apply_visitor(detail::is_solid_visitor(), image); } -template MAPNIK_DECL bool is_solid (image_any const&); -template MAPNIK_DECL bool is_solid (image_view_any const&); +MAPNIK_DECL bool is_solid(image_view_any const& image) +{ + return util::apply_visitor(detail::is_solid_visitor(), image); +} -// Temporary until image_rgba8 is removed from passing -template <> -MAPNIK_DECL bool is_solid(image_rgba8 const& image) +template +MAPNIK_DECL bool is_solid(T const& image) { detail::is_solid_visitor visitor; return visitor(image); } -// Temporary until image_view_rgba8 is removed from passing -template <> -MAPNIK_DECL bool is_solid(image_view_rgba8 const& image) -{ - detail::is_solid_visitor visitor; - return visitor(image); -} +template MAPNIK_DECL bool is_solid(image_rgba8 const&); +template MAPNIK_DECL bool is_solid(image_gray8 const&); +template MAPNIK_DECL bool is_solid(image_gray8s const&); +template MAPNIK_DECL bool is_solid(image_gray16 const&); +template MAPNIK_DECL bool is_solid(image_gray16s const&); +template MAPNIK_DECL bool is_solid(image_gray32 const&); +template MAPNIK_DECL bool is_solid(image_gray32s const&); +template MAPNIK_DECL bool is_solid(image_gray32f const&); +template MAPNIK_DECL bool is_solid(image_gray64 const&); +template MAPNIK_DECL bool is_solid(image_gray64s const&); +template MAPNIK_DECL bool is_solid(image_gray64f const&); namespace detail { struct premultiply_visitor { + bool operator() (image_rgba8 & data) + { + if (!data.get_premultiplied()) + { + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); + agg::pixfmt_rgba32 pixf(buffer); + pixf.premultiply(); + data.set_premultiplied(true); + return true; + } + return false; + } + template bool operator() (T &) { return false; } - }; -template <> -bool premultiply_visitor::operator() (image_rgba8 & data) -{ - if (!data.get_premultiplied()) - { - agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); - data.set_premultiplied(true); - return true; - } - return false; -} - struct demultiply_visitor { + bool operator() (image_rgba8 & data) + { + if (data.get_premultiplied()) + { + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); + agg::pixfmt_rgba32_pre pixf(buffer); + pixf.demultiply(); + data.set_premultiplied(false); + return true; + } + return false; + } + template bool operator() (T &) { return false; } - }; -template <> -bool demultiply_visitor::operator() (image_rgba8 & data) -{ - if (data.get_premultiplied()) - { - agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); - agg::pixfmt_rgba32_pre pixf(buffer); - pixf.demultiply(); - data.set_premultiplied(false); - return true; - } - return false; -} - struct set_premultiplied_visitor { set_premultiplied_visitor(bool status) @@ -537,54 +532,78 @@ struct set_premultiplied_visitor } // end detail ns -template -MAPNIK_DECL bool premultiply_alpha(T & image) +MAPNIK_DECL bool premultiply_alpha(image_any & image) { return util::apply_visitor(detail::premultiply_visitor(), image); } -template MAPNIK_DECL bool premultiply_alpha (image_any &); - -// Temporary, can be removed once image_view_any and image_any are the only ones passed -template <> -MAPNIK_DECL bool premultiply_alpha(image_rgba8 & image) +template +MAPNIK_DECL bool premultiply_alpha(T & image) { detail::premultiply_visitor visit; return visit(image); } -template -MAPNIK_DECL bool demultiply_alpha(T & image) +template MAPNIK_DECL bool premultiply_alpha(image_rgba8 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray8 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray8s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray16 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray16s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray32 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray32s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray32f &); +template MAPNIK_DECL bool premultiply_alpha(image_gray64 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray64s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray64f &); + +MAPNIK_DECL bool demultiply_alpha(image_any & image) { return util::apply_visitor(detail::demultiply_visitor(), image); } -template MAPNIK_DECL bool demultiply_alpha (image_any &); - -// Temporary, can be removed once image_view_any and image_any are the only ones passed -template <> -MAPNIK_DECL bool demultiply_alpha(image_rgba8 & image) +template +MAPNIK_DECL bool demultiply_alpha(T & image) { detail::demultiply_visitor visit; return visit(image); } -template -MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status) +template MAPNIK_DECL bool demultiply_alpha(image_rgba8 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray8 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray8s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray16 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray16s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray32 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray32s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray32f &); +template MAPNIK_DECL bool demultiply_alpha(image_gray64 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray64s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray64f &); + +MAPNIK_DECL void set_premultiplied_alpha(image_any & image, bool status) { util::apply_visitor(detail::set_premultiplied_visitor(status), image); } -template void set_premultiplied_alpha (image_any &, bool); - -// Temporary, can be removed once image_view_any and image_any are the only ones passed -template <> -MAPNIK_DECL void set_premultiplied_alpha(image_rgba8 & image, bool status) +template +MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status) { detail::set_premultiplied_visitor visit(status); visit(image); } +template MAPNIK_DECL void set_premultiplied_alpha(image_rgba8 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray8 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray8s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray16 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray16s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray32 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray32s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray32f &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray64 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray64s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray64f &, bool); + namespace detail { struct visitor_set_alpha @@ -592,6 +611,29 @@ struct visitor_set_alpha visitor_set_alpha(float opacity) : opacity_(opacity) {} + void operator() (image_rgba8 & data) + { + using pixel_type = typename image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) + { + pixel_type* row_to = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_to[x]; + pixel_type a0 = (rgba >> 24) & 0xff; + pixel_type a1 = pixel_type( ((rgba >> 24) & 0xff) * opacity_ ); + //unsigned a1 = opacity; + if (a0 == a1) continue; + + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; + } + } + } + template void operator() (T & data) { @@ -603,34 +645,9 @@ struct visitor_set_alpha }; -template <> -void visitor_set_alpha::operator() (image_rgba8 & data) -{ - using pixel_type = typename image_rgba8::pixel_type; - for (unsigned int y = 0; y < data.height(); ++y) - { - pixel_type* row_to = data.getRow(y); - for (unsigned int x = 0; x < data.width(); ++x) - { - pixel_type rgba = row_to[x]; - pixel_type a0 = (rgba >> 24) & 0xff; - pixel_type a1 = pixel_type( ((rgba >> 24) & 0xff) * opacity_ ); - //unsigned a1 = opacity; - if (a0 == a1) continue; - - pixel_type r = rgba & 0xff; - pixel_type g = (rgba >> 8 ) & 0xff; - pixel_type b = (rgba >> 16) & 0xff; - - row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; - } - } -} - } // end detail ns -template<> -MAPNIK_DECL void set_alpha (image_any & data, float opacity) +MAPNIK_DECL void set_alpha(image_any & data, float opacity) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -641,9 +658,8 @@ MAPNIK_DECL void set_alpha (image_any & data, float opacity) } } -// TEMPORARY can be removed once image_any is only way it is being passed. -template<> -MAPNIK_DECL void set_alpha (image_rgba8 & data, float opacity) +template +MAPNIK_DECL void set_alpha(T & data, float opacity) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -655,10 +671,43 @@ MAPNIK_DECL void set_alpha (image_rgba8 & data, float opacity) } } +template MAPNIK_DECL void set_alpha(image_rgba8 &, float); +template MAPNIK_DECL void set_alpha(image_gray8 &, float); +template MAPNIK_DECL void set_alpha(image_gray8s &, float); +template MAPNIK_DECL void set_alpha(image_gray16 &, float); +template MAPNIK_DECL void set_alpha(image_gray16s &, float); +template MAPNIK_DECL void set_alpha(image_gray32 &, float); +template MAPNIK_DECL void set_alpha(image_gray32s &, float); +template MAPNIK_DECL void set_alpha(image_gray32f &, float); +template MAPNIK_DECL void set_alpha(image_gray64 &, float); +template MAPNIK_DECL void set_alpha(image_gray64s &, float); +template MAPNIK_DECL void set_alpha(image_gray64f &, float); + namespace detail { struct visitor_set_grayscale_to_alpha { + void operator() (image_rgba8 & data) + { + using pixel_type = typename image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + // magic numbers for grayscale + pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); + + row_from[x] = (a << 24)| (255 << 16) | (255 << 8) | (255) ; + } + } + } + template void operator() (T & data) { @@ -666,33 +715,32 @@ struct visitor_set_grayscale_to_alpha } }; -template <> -void visitor_set_grayscale_to_alpha::operator() (image_rgba8 & data) -{ - using pixel_type = typename image_rgba8::pixel_type; - for (unsigned int y = 0; y < data.height(); ++y) - { - pixel_type* row_from = data.getRow(y); - for (unsigned int x = 0; x < data.width(); ++x) - { - pixel_type rgba = row_from[x]; - pixel_type r = rgba & 0xff; - pixel_type g = (rgba >> 8 ) & 0xff; - pixel_type b = (rgba >> 16) & 0xff; - - // magic numbers for grayscale - pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); - - row_from[x] = (a << 24)| (255 << 16) | (255 << 8) | (255) ; - } - } -} - struct visitor_set_grayscale_to_alpha_c { visitor_set_grayscale_to_alpha_c(color const& c) : c_(c) {} + void operator() (image_rgba8 & data) + { + using pixel_type = typename image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + // magic numbers for grayscale + pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); + + row_from[x] = (a << 24)| (c_.blue() << 16) | (c_.green() << 8) | (c_.red()) ; + } + } + } + template void operator() (T & data) { @@ -703,32 +751,9 @@ struct visitor_set_grayscale_to_alpha_c color const& c_; }; -template <> -void visitor_set_grayscale_to_alpha_c::operator() (image_rgba8 & data) -{ - using pixel_type = typename image_rgba8::pixel_type; - for (unsigned int y = 0; y < data.height(); ++y) - { - pixel_type* row_from = data.getRow(y); - for (unsigned int x = 0; x < data.width(); ++x) - { - pixel_type rgba = row_from[x]; - pixel_type r = rgba & 0xff; - pixel_type g = (rgba >> 8 ) & 0xff; - pixel_type b = (rgba >> 16) & 0xff; - - // magic numbers for grayscale - pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); - - row_from[x] = (a << 24)| (c_.blue() << 16) | (c_.green() << 8) | (c_.red()) ; - } - } -} - } // end detail ns -template<> -MAPNIK_DECL void set_grayscale_to_alpha (image_any & data) +MAPNIK_DECL void set_grayscale_to_alpha(image_any & data) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -739,8 +764,8 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_any & data) } } -template<> -MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data) +template +MAPNIK_DECL void set_grayscale_to_alpha(T & data) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -752,8 +777,19 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data) } } -template<> -MAPNIK_DECL void set_grayscale_to_alpha (image_any & data, color const& c) +template MAPNIK_DECL void set_grayscale_to_alpha(image_rgba8 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32f &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64f &); + +MAPNIK_DECL void set_grayscale_to_alpha(image_any & data, color const& c) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -764,8 +800,8 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_any & data, color cons } } -template<> -MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data, color const& c) +template +MAPNIK_DECL void set_grayscale_to_alpha(T & data, color const& c) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -777,6 +813,18 @@ MAPNIK_DECL void set_grayscale_to_alpha (image_rgba8 & data, color } } +template MAPNIK_DECL void set_grayscale_to_alpha(image_rgba8 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32f &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64f &, color const&); + namespace detail { struct visitor_set_color_to_alpha @@ -784,6 +832,26 @@ struct visitor_set_color_to_alpha visitor_set_color_to_alpha(color const& c) : c_(c) {} + void operator() (image_rgba8 & data) + { + using pixel_type = typename image_rgba8::pixel_type; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + if (r == c_.red() && g == c_.green() && b == c_.blue()) + { + row_from[x] = 0; + } + } + } + } + template void operator() (T & data) { @@ -795,31 +863,10 @@ struct visitor_set_color_to_alpha }; -template <> -void visitor_set_color_to_alpha::operator() (image_rgba8 & data) -{ - using pixel_type = typename image_rgba8::pixel_type; - for (unsigned y = 0; y < data.height(); ++y) - { - pixel_type* row_from = data.getRow(y); - for (unsigned x = 0; x < data.width(); ++x) - { - pixel_type rgba = row_from[x]; - pixel_type r = rgba & 0xff; - pixel_type g = (rgba >> 8 ) & 0xff; - pixel_type b = (rgba >> 16) & 0xff; - if (r == c_.red() && g == c_.green() && b == c_.blue()) - { - row_from[x] = 0; - } - } - } -} } // end detail ns -template<> -MAPNIK_DECL void set_color_to_alpha (image_any & data, color const& c) +MAPNIK_DECL void set_color_to_alpha (image_any & data, color const& c) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -830,9 +877,8 @@ MAPNIK_DECL void set_color_to_alpha (image_any & data, color const& c } } -// TEMPORARY can be removed once image_any is only way it is being passed. -template<> -MAPNIK_DECL void set_color_to_alpha (image_rgba8 & data, color const& c) +template +MAPNIK_DECL void set_color_to_alpha(T & data, color const& c) { // Prior to calling the data must not be premultiplied bool remultiply = mapnik::demultiply_alpha(data); @@ -844,6 +890,18 @@ MAPNIK_DECL void set_color_to_alpha (image_rgba8 & data, color cons } } +template MAPNIK_DECL void set_color_to_alpha(image_rgba8 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray8 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray8s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray16 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray16s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray32 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray32s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray32f &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray64 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray64s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray64f &, color const&); + namespace detail { template @@ -911,6 +969,8 @@ MAPNIK_DECL void fill (image_any & data, T const& val) } template MAPNIK_DECL void fill(image_any &, color const&); +template MAPNIK_DECL void fill(image_any &, uint64_t const&); +template MAPNIK_DECL void fill(image_any &, int64_t const&); template MAPNIK_DECL void fill(image_any &, uint32_t const&); template MAPNIK_DECL void fill(image_any &, int32_t const&); template MAPNIK_DECL void fill(image_any &, uint16_t const&); @@ -928,6 +988,8 @@ MAPNIK_DECL void fill (image_rgba8 & data, T const& val) } template MAPNIK_DECL void fill(image_rgba8 &, color const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint64_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int64_t const&); template MAPNIK_DECL void fill(image_rgba8 &, uint32_t const&); template MAPNIK_DECL void fill(image_rgba8 &, int32_t const&); template MAPNIK_DECL void fill(image_rgba8 &, uint16_t const&); @@ -945,6 +1007,8 @@ MAPNIK_DECL void fill (image_gray8 & data, T const& val) } template MAPNIK_DECL void fill(image_gray8 &, color const&); +template MAPNIK_DECL void fill(image_gray8 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int64_t const&); template MAPNIK_DECL void fill(image_gray8 &, uint32_t const&); template MAPNIK_DECL void fill(image_gray8 &, int32_t const&); template MAPNIK_DECL void fill(image_gray8 &, uint16_t const&); @@ -954,6 +1018,25 @@ template MAPNIK_DECL void fill(image_gray8 &, int8_t const&); template MAPNIK_DECL void fill(image_gray8 &, float const&); template MAPNIK_DECL void fill(image_gray8 &, double const&); +template +MAPNIK_DECL void fill (image_gray8s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray8s &, color const&); +template MAPNIK_DECL void fill(image_gray8s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray8s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray8s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray8s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray8s &, float const&); +template MAPNIK_DECL void fill(image_gray8s &, double const&); + template MAPNIK_DECL void fill (image_gray16 & data, T const& val) { @@ -962,6 +1045,8 @@ MAPNIK_DECL void fill (image_gray16 & data, T const& val) } template MAPNIK_DECL void fill(image_gray16 &, color const&); +template MAPNIK_DECL void fill(image_gray16 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int64_t const&); template MAPNIK_DECL void fill(image_gray16 &, uint32_t const&); template MAPNIK_DECL void fill(image_gray16 &, int32_t const&); template MAPNIK_DECL void fill(image_gray16 &, uint16_t const&); @@ -971,6 +1056,63 @@ template MAPNIK_DECL void fill(image_gray16 &, int8_t const&); template MAPNIK_DECL void fill(image_gray16 &, float const&); template MAPNIK_DECL void fill(image_gray16 &, double const&); +template +MAPNIK_DECL void fill (image_gray16s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray16s &, color const&); +template MAPNIK_DECL void fill(image_gray16s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray16s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray16s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray16s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray16s &, float const&); +template MAPNIK_DECL void fill(image_gray16s &, double const&); + +template +MAPNIK_DECL void fill (image_gray32 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray32 &, color const&); +template MAPNIK_DECL void fill(image_gray32 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int64_t const&); +template MAPNIK_DECL void fill(image_gray32 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray32 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray32 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray32 &, float const&); +template MAPNIK_DECL void fill(image_gray32 &, double const&); + +template +MAPNIK_DECL void fill (image_gray32s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray32s &, color const&); +template MAPNIK_DECL void fill(image_gray32s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray32s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray32s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray32s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray32s &, float const&); +template MAPNIK_DECL void fill(image_gray32s &, double const&); + template MAPNIK_DECL void fill (image_gray32f & data, T const& val) { @@ -979,6 +1121,8 @@ MAPNIK_DECL void fill (image_gray32f & data, T const& val) } template MAPNIK_DECL void fill(image_gray32f &, color const&); +template MAPNIK_DECL void fill(image_gray32f &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int64_t const&); template MAPNIK_DECL void fill(image_gray32f &, uint32_t const&); template MAPNIK_DECL void fill(image_gray32f &, int32_t const&); template MAPNIK_DECL void fill(image_gray32f &, uint16_t const&); @@ -988,6 +1132,63 @@ template MAPNIK_DECL void fill(image_gray32f &, int8_t const&); template MAPNIK_DECL void fill(image_gray32f &, float const&); template MAPNIK_DECL void fill(image_gray32f &, double const&); +template +MAPNIK_DECL void fill (image_gray64 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray64 &, color const&); +template MAPNIK_DECL void fill(image_gray64 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int64_t const&); +template MAPNIK_DECL void fill(image_gray64 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray64 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray64 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray64 &, float const&); +template MAPNIK_DECL void fill(image_gray64 &, double const&); + +template +MAPNIK_DECL void fill (image_gray64s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray64s &, color const&); +template MAPNIK_DECL void fill(image_gray64s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray64s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray64s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray64s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray64s &, float const&); +template MAPNIK_DECL void fill(image_gray64s &, double const&); + +template +MAPNIK_DECL void fill (image_gray64f & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray64f &, color const&); +template MAPNIK_DECL void fill(image_gray64f &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int64_t const&); +template MAPNIK_DECL void fill(image_gray64f &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int32_t const&); +template MAPNIK_DECL void fill(image_gray64f &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int16_t const&); +template MAPNIK_DECL void fill(image_gray64f &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int8_t const&); +template MAPNIK_DECL void fill(image_gray64f &, float const&); +template MAPNIK_DECL void fill(image_gray64f &, double const&); + namespace detail { struct visitor_set_rectangle @@ -995,6 +1196,37 @@ struct visitor_set_rectangle visitor_set_rectangle(image_any const & src, int x0, int y0) : src_(src), x0_(x0), y0_(y0) {} + void operator()(image_rgba8 & dst) + { + using pixel_type = typename image_rgba8::pixel_type; + image_rgba8 src = util::get(src_); + box2d ext0(0,0,dst.width(),dst.height()); + box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); + + if (ext0.intersects(ext1)) + { + box2d box = ext0.intersect(ext1); + for (std::size_t y = box.miny(); y < box.maxy(); ++y) + { + pixel_type* row_to = dst.getRow(y); + pixel_type const * row_from = src.getRow(y-y0_); + + for (std::size_t x = box.minx(); x < box.maxx(); ++x) + { + if (row_from[x-x0_] & 0xff000000) // Don't change if alpha == 0 + { + row_to[x] = row_from[x-x0_]; + } + } + } + } + } + + void operator() (image_null &) + { + throw std::runtime_error("Set rectangle not support for null images"); + } + template void operator() (T & dst) { @@ -1024,41 +1256,13 @@ struct visitor_set_rectangle int y0_; }; -template <> -void visitor_set_rectangle::operator() (image_rgba8 & dst) -{ - using pixel_type = typename image_rgba8::pixel_type; - image_rgba8 src = util::get(src_); - box2d ext0(0,0,dst.width(),dst.height()); - box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (std::size_t y = box.miny(); y < box.maxy(); ++y) - { - pixel_type* row_to = dst.getRow(y); - pixel_type const * row_from = src.getRow(y-y0_); - - for (std::size_t x = box.minx(); x < box.maxx(); ++x) - { - if (row_from[x-x0_] & 0xff000000) // Don't change if alpha == 0 - { - row_to[x] = row_from[x-x0_]; - } - } - } - } -} - -template<> -void visitor_set_rectangle::operator() (image_null &) -{ - throw std::runtime_error("Set rectangle not support for null images"); -} - } // end detail ns +MAPNIK_DECL void set_rectangle(image_any & dst, image_any const& src, int x, int y) +{ + util::apply_visitor(detail::visitor_set_rectangle(src, x, y), dst); +} + template MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x, int y) { @@ -1066,11 +1270,17 @@ MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x, int y) visit(dst); } -template <> -MAPNIK_DECL void set_rectangle (image_any & dst, image_any const& src, int x, int y) -{ - util::apply_visitor(detail::visitor_set_rectangle(src, x, y), dst); -} +template MAPNIK_DECL void set_rectangle(image_rgba8 &, image_rgba8 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray8 &, image_gray8 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray8s &, image_gray8s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray16 &, image_gray16 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray16s &, image_gray16s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray32 &, image_gray32 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray32s &, image_gray32s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray32f &, image_gray32f const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray64 &, image_gray64 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray64s &, image_gray64s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray64f &, image_gray64f const&, int, int); namespace detail { @@ -1087,6 +1297,25 @@ struct visitor_composite_pixel c_(c), cover_(cover) {} + void operator() (image_rgba8 & data) + { + using color_type = agg::rgba8; + using value_type = color_type::value_type; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba; + + if (mapnik::check_bounds(data, x_, y_)) + { + unsigned rgba = data(x_,y_); + unsigned ca = (unsigned)(((c_ >> 24) & 0xff) * opacity_); + unsigned cb = (c_ >> 16 ) & 0xff; + unsigned cg = (c_ >> 8) & 0xff; + unsigned cr = (c_ & 0xff); + blender_type::blend_pix(op_, (value_type*)&rgba, cr, cg, cb, ca, cover_); + data(x_,y_) = rgba; + } + } + template void operator() (T & data) { @@ -1103,42 +1332,32 @@ struct visitor_composite_pixel }; -template<> -void visitor_composite_pixel::operator() (image_rgba8 & data) -{ - using color_type = agg::rgba8; - using value_type = color_type::value_type; - using order_type = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba; - - if (mapnik::check_bounds(data, x_, y_)) - { - unsigned rgba = data(x_,y_); - unsigned ca = (unsigned)(((c_ >> 24) & 0xff) * opacity_); - unsigned cb = (c_ >> 16 ) & 0xff; - unsigned cg = (c_ >> 8) & 0xff; - unsigned cr = (c_ & 0xff); - blender_type::blend_pix(op_, (value_type*)&rgba, cr, cg, cb, ca, cover_); - data(x_,y_) = rgba; - } -} - } // end detail ns -template -MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +MAPNIK_DECL void composite_pixel(image_any & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) { util::apply_visitor(detail::visitor_composite_pixel(op, x, y, c, cover, opacity), data); } -// Temporary delete later -template <> -MAPNIK_DECL void composite_pixel(image_rgba8 & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +template +MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) { detail::visitor_composite_pixel visitor(op, x, y, c, cover, opacity); visitor(data); } +template MAPNIK_DECL void composite_pixel(image_rgba8 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray8 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray8s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray16 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray16s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray32 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray32s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray32f &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray64 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray64s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray64f &, unsigned, int, int, unsigned, unsigned, double); + namespace detail { template @@ -1217,7 +1436,6 @@ struct visitor_set_pixel } // end detail ns -// For all the generic data types. template MAPNIK_DECL void set_pixel (image_any & data, std::size_t x, std::size_t y, T const& val) { @@ -1225,6 +1443,8 @@ MAPNIK_DECL void set_pixel (image_any & data, std::size_t x, std::size_t y, T co } template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int64_t const&); template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint32_t const&); template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int32_t const&); template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint16_t const&); @@ -1242,6 +1462,8 @@ MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, T } template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int64_t const&); template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint32_t const&); template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int32_t const&); template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint16_t const&); @@ -1259,6 +1481,8 @@ MAPNIK_DECL void set_pixel (image_gray8 & data, std::size_t x, std::size_t y, T } template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int64_t const&); template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint32_t const&); template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int32_t const&); template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint16_t const&); @@ -1268,6 +1492,25 @@ template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, float const&); template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, double const&); +template +MAPNIK_DECL void set_pixel (image_gray8s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, double const&); + template MAPNIK_DECL void set_pixel (image_gray16 & data, std::size_t x, std::size_t y, T const& val) { @@ -1276,6 +1519,8 @@ MAPNIK_DECL void set_pixel (image_gray16 & data, std::size_t x, std::size_t y, T } template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int64_t const&); template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint32_t const&); template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int32_t const&); template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint16_t const&); @@ -1285,6 +1530,63 @@ template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, in template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, float const&); template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, double const&); +template +MAPNIK_DECL void set_pixel (image_gray16s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray32 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray32s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, double const&); + template MAPNIK_DECL void set_pixel (image_gray32f & data, std::size_t x, std::size_t y, T const& val) { @@ -1293,6 +1595,8 @@ MAPNIK_DECL void set_pixel (image_gray32f & data, std::size_t x, std::size_t y, } template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int64_t const&); template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint32_t const&); template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int32_t const&); template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint16_t const&); @@ -1302,6 +1606,63 @@ template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, i template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, float const&); template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, double const&); +template +MAPNIK_DECL void set_pixel (image_gray64 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray64s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray64f & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, double const&); + namespace detail { template @@ -1354,7 +1715,6 @@ struct visitor_get_pixel } // end detail ns -// For all the generic data types. template MAPNIK_DECL T get_pixel (image_any const& data, std::size_t x, std::size_t y) { @@ -1362,6 +1722,8 @@ MAPNIK_DECL T get_pixel (image_any const& data, std::size_t x, std::size_t y) } template MAPNIK_DECL color get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_any const&, std::size_t, std::size_t); template MAPNIK_DECL uint16_t get_pixel(image_any const&, std::size_t, std::size_t); @@ -1378,6 +1740,8 @@ MAPNIK_DECL T get_pixel (image_view_any const& data, std::size_t x, std::size_t } template MAPNIK_DECL color get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_any const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_view_any const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_view_any const&, std::size_t, std::size_t); template MAPNIK_DECL uint16_t get_pixel(image_view_any const&, std::size_t, std::size_t); @@ -1395,6 +1759,8 @@ MAPNIK_DECL T get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) } template MAPNIK_DECL color get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); template MAPNIK_DECL uint16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); @@ -1412,6 +1778,8 @@ MAPNIK_DECL T get_pixel (image_gray8 const& data, std::size_t x, std::size_t y) } template MAPNIK_DECL color get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray8 const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_gray8 const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_gray8 const&, std::size_t, std::size_t); template MAPNIK_DECL uint16_t get_pixel(image_gray8 const&, std::size_t, std::size_t); @@ -1421,6 +1789,25 @@ template MAPNIK_DECL int8_t get_pixel(image_gray8 const&, std::size_t, std::size template MAPNIK_DECL float get_pixel(image_gray8 const&, std::size_t, std::size_t); template MAPNIK_DECL double get_pixel(image_gray8 const&, std::size_t, std::size_t); +template +MAPNIK_DECL T get_pixel (image_gray8s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray8s const&, std::size_t, std::size_t); + template MAPNIK_DECL T get_pixel (image_gray16 const& data, std::size_t x, std::size_t y) { @@ -1429,6 +1816,8 @@ MAPNIK_DECL T get_pixel (image_gray16 const& data, std::size_t x, std::size_t y) } template MAPNIK_DECL color get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray16 const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_gray16 const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_gray16 const&, std::size_t, std::size_t); template MAPNIK_DECL uint16_t get_pixel(image_gray16 const&, std::size_t, std::size_t); @@ -1438,6 +1827,63 @@ template MAPNIK_DECL int8_t get_pixel(image_gray16 const&, std::size_t, std::siz template MAPNIK_DECL float get_pixel(image_gray16 const&, std::size_t, std::size_t); template MAPNIK_DECL double get_pixel(image_gray16 const&, std::size_t, std::size_t); +template +MAPNIK_DECL T get_pixel (image_gray16s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray16s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray32 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray32 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray32s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray32s const&, std::size_t, std::size_t); + template MAPNIK_DECL T get_pixel (image_gray32f const& data, std::size_t x, std::size_t y) { @@ -1446,6 +1892,8 @@ MAPNIK_DECL T get_pixel (image_gray32f const& data, std::size_t x, std::size_t y } template MAPNIK_DECL color get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray32f const&, std::size_t, std::size_t); template MAPNIK_DECL uint32_t get_pixel(image_gray32f const&, std::size_t, std::size_t); template MAPNIK_DECL int32_t get_pixel(image_gray32f const&, std::size_t, std::size_t); template MAPNIK_DECL uint16_t get_pixel(image_gray32f const&, std::size_t, std::size_t); @@ -1455,6 +1903,272 @@ template MAPNIK_DECL int8_t get_pixel(image_gray32f const&, std::size_t, std::si template MAPNIK_DECL float get_pixel(image_gray32f const&, std::size_t, std::size_t); template MAPNIK_DECL double get_pixel(image_gray32f const&, std::size_t, std::size_t); +template +MAPNIK_DECL T get_pixel (image_gray64 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray64 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray64s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray64s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray64f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray64f const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_rgba8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray8s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray8s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray16 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray16 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray16s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray16s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray32 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray32 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray32s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray32s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray32f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray32f const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray64 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray64 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray64s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray64s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray64f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray64f const&, std::size_t, std::size_t); + namespace detail { @@ -1493,6 +2207,11 @@ struct visitor_create_view visitor_create_view(unsigned x,unsigned y, unsigned w, unsigned h) : x_(x), y_(y), w_(w), h_(h) {} + image_view_any operator() (image_null const&) + { + throw std::runtime_error("Can not make a view from a null image"); + } + template image_view_any operator() (T const& data) { @@ -1506,12 +2225,6 @@ struct visitor_create_view unsigned h_; }; -template <> -image_view_any visitor_create_view::operator() (image_null const&) -{ - throw std::runtime_error("Can not make a view from a null image"); -} - } // end detail ns MAPNIK_DECL image_view_any create_view(image_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) @@ -1545,8 +2258,15 @@ MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold, bool) } template MAPNIK_DECL unsigned compare(image_gray8 const&, image_gray8 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray8s const&, image_gray8s const&, double, bool); template MAPNIK_DECL unsigned compare(image_gray16 const&, image_gray16 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray16s const&, image_gray16s const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray32 const&, image_gray32 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray32s const&, image_gray32s const&, double, bool); template MAPNIK_DECL unsigned compare(image_gray32f const&, image_gray32f const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray64 const&, image_gray64 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray64s const&, image_gray64s const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray64f const&, image_gray64f const&, double, bool); template <> MAPNIK_DECL unsigned compare(image_null const&, image_null const&, double, bool) @@ -1563,10 +2283,109 @@ MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 co return im1.width() * im1.height(); } unsigned difference = 0; +#ifdef SSE_MATH + __m128i true_set = _mm_set1_epi8(0xff); + __m128i one = _mm_set1_epi32(1); + __m128i sum = _mm_setzero_si128(); + uint32_t alphamask = 0xffffffff; + if (!alpha) + { + alphamask = 0xffffff; + } + __m128i mask = _mm_set1_epi32(alphamask); + if (threshold == 0.0) + { + for (unsigned int y = 0; y < im1.height(); ++y) + { + const std::uint32_t * row_from = im1.getRow(y); + const std::uint32_t * row_from2 = im2.getRow(y); + int x = 0; + for (; x < ROUND_DOWN(im1.width(),4); x +=4 ) + { + __m128i rgba = _mm_loadu_si128((__m128i*)(row_from + x)); + __m128i rgba2 = _mm_loadu_si128((__m128i*)(row_from2 + x)); + rgba = _mm_and_si128(rgba, mask); + rgba2 = _mm_and_si128(rgba2, mask); + __m128i eq = _mm_cmpeq_epi8(rgba,rgba2); + __m128i comp2 = _mm_cmpeq_epi32(eq, true_set); + sum = _mm_add_epi32(sum, _mm_andnot_si128(comp2, one)); + } + for (; x < im1.width(); ++x) + { + if ((row_from[x] & alphamask) != (row_from2[x] & alphamask)) + { + ++difference; + } + } + } + m128_int diff_sum; + diff_sum.v = sum; + difference += diff_sum.u32[0]; + difference += diff_sum.u32[1]; + difference += diff_sum.u32[2]; + difference += diff_sum.u32[3]; + } + else + { + uint8_t thres = static_cast(threshold); + __m128i m_thres = _mm_set1_epi8(thres); + for (unsigned int y = 0; y < im1.height(); ++y) + { + const std::uint32_t * row_from = im1.getRow(y); + const std::uint32_t * row_from2 = im2.getRow(y); + int x = 0; + for (; x < ROUND_DOWN(im1.width(),4); x +=4 ) + { + __m128i rgba = _mm_loadu_si128((__m128i*)(row_from + x)); + __m128i rgba2 = _mm_loadu_si128((__m128i*)(row_from2 + x)); + rgba = _mm_and_si128(rgba, mask); + rgba2 = _mm_and_si128(rgba2, mask); + __m128i gt_comp = _mm_cmpgt_epi8(rgba, rgba2); + __m128i abs_1 = _mm_and_si128(gt_comp, _mm_sub_epi8(rgba, rgba2)); + __m128i abs_2 = _mm_andnot_si128(gt_comp, _mm_sub_epi8(rgba2, rgba)); + __m128i abs = _mm_or_si128(abs_1, abs_2); + __m128i compare = _mm_or_si128(_mm_cmplt_epi8(abs, m_thres), _mm_cmpeq_epi8(abs, m_thres)); + __m128i comp2 = _mm_cmpeq_epi32(compare, true_set); + sum = _mm_add_epi32(sum, _mm_andnot_si128(comp2, one)); + } + for (; x < im1.width(); ++x) + { + unsigned rgba = row_from[x]; + unsigned rgba2 = row_from2[x]; + unsigned r = rgba & 0xff; + unsigned g = (rgba >> 8 ) & 0xff; + unsigned b = (rgba >> 16) & 0xff; + unsigned r2 = rgba2 & 0xff; + unsigned g2 = (rgba2 >> 8 ) & 0xff; + unsigned b2 = (rgba2 >> 16) & 0xff; + if (std::abs(static_cast(r - r2)) > static_cast(threshold) || + std::abs(static_cast(g - g2)) > static_cast(threshold) || + std::abs(static_cast(b - b2)) > static_cast(threshold)) { + ++difference; + continue; + } + if (alpha) { + unsigned a = (rgba >> 24) & 0xff; + unsigned a2 = (rgba2 >> 24) & 0xff; + if (std::abs(static_cast(a - a2)) > static_cast(threshold)) { + ++difference; + continue; + } + } + } + } + m128_int diff_sum; + diff_sum.v = sum; + difference += diff_sum.u32[0]; + difference += diff_sum.u32[1]; + difference += diff_sum.u32[2]; + difference += diff_sum.u32[3]; + } +#else for (unsigned int y = 0; y < im1.height(); ++y) { - const pixel_type * row_from = im1.getRow(y); - const pixel_type * row_from2 = im2.getRow(y); + const std::uint32_t * row_from = im1.getRow(y); + const std::uint32_t * row_from2 = im2.getRow(y); for (unsigned int x = 0; x < im1.width(); ++x) { unsigned rgba = row_from[x]; @@ -1593,6 +2412,7 @@ MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 co } } } +#endif return difference; } diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp index c689dd856..b6da08f76 100644 --- a/src/image_util_jpeg.cpp +++ b/src/image_util_jpeg.cpp @@ -88,11 +88,27 @@ void jpeg_saver::operator() (T const& image) const throw ImageWriterException("Mapnik does not support jpeg grayscale images"); } -template void jpeg_saver::operator() (image_gray8 const& image) const; -template void jpeg_saver::operator() (image_gray16 const& image) const; -template void jpeg_saver::operator() (image_gray32f const& image) const; -template void jpeg_saver::operator() (image_view_gray8 const& image) const; -template void jpeg_saver::operator() (image_view_gray16 const& image) const; -template void jpeg_saver::operator() (image_view_gray32f const& image) const; +template void jpeg_saver::operator() (image_rgba8 const& image) const; +template void jpeg_saver::operator() (image_gray8 const& image) const; +template void jpeg_saver::operator() (image_gray8s const& image) const; +template void jpeg_saver::operator() (image_gray16 const& image) const; +template void jpeg_saver::operator() (image_gray16s const& image) const; +template void jpeg_saver::operator() (image_gray32 const& image) const; +template void jpeg_saver::operator() (image_gray32s const& image) const; +template void jpeg_saver::operator() (image_gray32f const& image) const; +template void jpeg_saver::operator() (image_gray64 const& image) const; +template void jpeg_saver::operator() (image_gray64s const& image) const; +template void jpeg_saver::operator() (image_gray64f const& image) const; +template void jpeg_saver::operator() (image_view_rgba8 const& image) const; +template void jpeg_saver::operator() (image_view_gray8 const& image) const; +template void jpeg_saver::operator() (image_view_gray8s const& image) const; +template void jpeg_saver::operator() (image_view_gray16 const& image) const; +template void jpeg_saver::operator() (image_view_gray16s const& image) const; +template void jpeg_saver::operator() (image_view_gray32 const& image) const; +template void jpeg_saver::operator() (image_view_gray32s const& image) const; +template void jpeg_saver::operator() (image_view_gray32f const& image) const; +template void jpeg_saver::operator() (image_view_gray64 const& image) const; +template void jpeg_saver::operator() (image_view_gray64s const& image) const; +template void jpeg_saver::operator() (image_view_gray64f const& image) const; } // end ns diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp index 691e7607f..68b2b66df 100644 --- a/src/image_util_png.cpp +++ b/src/image_util_png.cpp @@ -308,17 +308,49 @@ void png_saver_pal::operator() (T const& image) const #endif } -template void png_saver::operator() (image_gray8 const& image) const; -template void png_saver::operator() (image_gray16 const& image) const; -template void png_saver::operator() (image_gray32f const& image) const; -template void png_saver::operator() (image_view_gray8 const& image) const; -template void png_saver::operator() (image_view_gray16 const& image) const; -template void png_saver::operator() (image_view_gray32f const& image) const; -template void png_saver_pal::operator() (image_gray8 const& image) const; -template void png_saver_pal::operator() (image_gray16 const& image) const; -template void png_saver_pal::operator() (image_gray32f const& image) const; -template void png_saver_pal::operator() (image_view_gray8 const& image) const; -template void png_saver_pal::operator() (image_view_gray16 const& image) const; -template void png_saver_pal::operator() (image_view_gray32f const& image) const; +template void png_saver::operator() (image_rgba8 const& image) const; +template void png_saver::operator() (image_gray8 const& image) const; +template void png_saver::operator() (image_gray8s const& image) const; +template void png_saver::operator() (image_gray16 const& image) const; +template void png_saver::operator() (image_gray16s const& image) const; +template void png_saver::operator() (image_gray32 const& image) const; +template void png_saver::operator() (image_gray32s const& image) const; +template void png_saver::operator() (image_gray32f const& image) const; +template void png_saver::operator() (image_gray64 const& image) const; +template void png_saver::operator() (image_gray64s const& image) const; +template void png_saver::operator() (image_gray64f const& image) const; +template void png_saver::operator() (image_view_rgba8 const& image) const; +template void png_saver::operator() (image_view_gray8 const& image) const; +template void png_saver::operator() (image_view_gray8s const& image) const; +template void png_saver::operator() (image_view_gray16 const& image) const; +template void png_saver::operator() (image_view_gray16s const& image) const; +template void png_saver::operator() (image_view_gray32 const& image) const; +template void png_saver::operator() (image_view_gray32s const& image) const; +template void png_saver::operator() (image_view_gray32f const& image) const; +template void png_saver::operator() (image_view_gray64 const& image) const; +template void png_saver::operator() (image_view_gray64s const& image) const; +template void png_saver::operator() (image_view_gray64f const& image) const; +template void png_saver_pal::operator() (image_rgba8 const& image) const; +template void png_saver_pal::operator() (image_gray8 const& image) const; +template void png_saver_pal::operator() (image_gray8s const& image) const; +template void png_saver_pal::operator() (image_gray16 const& image) const; +template void png_saver_pal::operator() (image_gray16s const& image) const; +template void png_saver_pal::operator() (image_gray32 const& image) const; +template void png_saver_pal::operator() (image_gray32s const& image) const; +template void png_saver_pal::operator() (image_gray32f const& image) const; +template void png_saver_pal::operator() (image_gray64 const& image) const; +template void png_saver_pal::operator() (image_gray64s const& image) const; +template void png_saver_pal::operator() (image_gray64f const& image) const; +template void png_saver_pal::operator() (image_view_rgba8 const& image) const; +template void png_saver_pal::operator() (image_view_gray8 const& image) const; +template void png_saver_pal::operator() (image_view_gray8s const& image) const; +template void png_saver_pal::operator() (image_view_gray16 const& image) const; +template void png_saver_pal::operator() (image_view_gray16s const& image) const; +template void png_saver_pal::operator() (image_view_gray32 const& image) const; +template void png_saver_pal::operator() (image_view_gray32s const& image) const; +template void png_saver_pal::operator() (image_view_gray32f const& image) const; +template void png_saver_pal::operator() (image_view_gray64 const& image) const; +template void png_saver_pal::operator() (image_view_gray64s const& image) const; +template void png_saver_pal::operator() (image_view_gray64f const& image) const; } // end ns diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp index ffd4ecf64..22f1924f1 100644 --- a/src/image_util_tiff.cpp +++ b/src/image_util_tiff.cpp @@ -181,13 +181,27 @@ void tiff_saver::operator() (T const& image) const #endif } -template void tiff_saver::operator() (image_rgba8 const& image) const; -template void tiff_saver::operator() (image_gray8 const& image) const; -template void tiff_saver::operator() (image_gray16 const& image) const; -template void tiff_saver::operator() (image_gray32f const& image) const; -template void tiff_saver::operator() (image_view_rgba8 const& image) const; -template void tiff_saver::operator() (image_view_gray8 const& image) const; -template void tiff_saver::operator() (image_view_gray16 const& image) const; -template void tiff_saver::operator() (image_view_gray32f const& image) const; +template void tiff_saver::operator() (image_rgba8 const& image) const; +template void tiff_saver::operator() (image_gray8 const& image) const; +template void tiff_saver::operator() (image_gray8s const& image) const; +template void tiff_saver::operator() (image_gray16 const& image) const; +template void tiff_saver::operator() (image_gray16s const& image) const; +template void tiff_saver::operator() (image_gray32 const& image) const; +template void tiff_saver::operator() (image_gray32s const& image) const; +template void tiff_saver::operator() (image_gray32f const& image) const; +template void tiff_saver::operator() (image_gray64 const& image) const; +template void tiff_saver::operator() (image_gray64s const& image) const; +template void tiff_saver::operator() (image_gray64f const& image) const; +template void tiff_saver::operator() (image_view_rgba8 const& image) const; +template void tiff_saver::operator() (image_view_gray8 const& image) const; +template void tiff_saver::operator() (image_view_gray8s const& image) const; +template void tiff_saver::operator() (image_view_gray16 const& image) const; +template void tiff_saver::operator() (image_view_gray16s const& image) const; +template void tiff_saver::operator() (image_view_gray32 const& image) const; +template void tiff_saver::operator() (image_view_gray32s const& image) const; +template void tiff_saver::operator() (image_view_gray32f const& image) const; +template void tiff_saver::operator() (image_view_gray64 const& image) const; +template void tiff_saver::operator() (image_view_gray64s const& image) const; +template void tiff_saver::operator() (image_view_gray64f const& image) const; } // end ns diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp index aa9bb2d93..836039e40 100644 --- a/src/image_util_webp.cpp +++ b/src/image_util_webp.cpp @@ -379,11 +379,25 @@ void webp_saver::operator() (T const& image) const template void webp_saver::operator() (image_rgba8 const& image) const; template void webp_saver::operator() (image_gray8 const& image) const; +template void webp_saver::operator() (image_gray8s const& image) const; template void webp_saver::operator() (image_gray16 const& image) const; +template void webp_saver::operator() (image_gray16s const& image) const; +template void webp_saver::operator() (image_gray32 const& image) const; +template void webp_saver::operator() (image_gray32s const& image) const; template void webp_saver::operator() (image_gray32f const& image) const; +template void webp_saver::operator() (image_gray64 const& image) const; +template void webp_saver::operator() (image_gray64s const& image) const; +template void webp_saver::operator() (image_gray64f const& image) const; template void webp_saver::operator() (image_view_rgba8 const& image) const; template void webp_saver::operator() (image_view_gray8 const& image) const; +template void webp_saver::operator() (image_view_gray8s const& image) const; template void webp_saver::operator() (image_view_gray16 const& image) const; +template void webp_saver::operator() (image_view_gray16s const& image) const; +template void webp_saver::operator() (image_view_gray32 const& image) const; +template void webp_saver::operator() (image_view_gray32s const& image) const; template void webp_saver::operator() (image_view_gray32f const& image) const; +template void webp_saver::operator() (image_view_gray64 const& image) const; +template void webp_saver::operator() (image_view_gray64s const& image) const; +template void webp_saver::operator() (image_view_gray64f const& image) const; } // end ns diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index 27682f3c3..bd150d540 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -289,11 +289,32 @@ unsigned raster_colorizer::get_color(float value) const template void raster_colorizer::colorize(image_rgba8 & out, image_gray8 const& in, boost::optionalconst& nodata, feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray8s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; template void raster_colorizer::colorize(image_rgba8 & out, image_gray16 const& in, boost::optionalconst& nodata, feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray16s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray32 const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray32s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; template void raster_colorizer::colorize(image_rgba8 & out, image_gray32f const& in, boost::optionalconst& nodata, feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray64 const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray64s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray64f const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; } diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index ac00db020..df49fc28c 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -59,6 +59,16 @@ raster_marker_render_thunk::raster_marker_render_thunk(image_gray8 snap_to_pixels_(snap_to_pixels) {} +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray8s & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + template <> raster_marker_render_thunk::raster_marker_render_thunk(image_gray16 & src, agg::trans_affine const& marker_trans, @@ -69,6 +79,36 @@ raster_marker_render_thunk::raster_marker_render_thunk(image_gray1 snap_to_pixels_(snap_to_pixels) {} +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray16s & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray32 & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray32s & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + template <> raster_marker_render_thunk::raster_marker_render_thunk(image_gray32f & src, agg::trans_affine const& marker_trans, @@ -79,6 +119,36 @@ raster_marker_render_thunk::raster_marker_render_thunk(image_gray snap_to_pixels_(snap_to_pixels) {} +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray64 & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray64s & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + +template <> +raster_marker_render_thunk::raster_marker_render_thunk(image_gray64f & src, + agg::trans_affine const& marker_trans, + double opacity, + composite_mode_e comp_op, + bool snap_to_pixels) + : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), + snap_to_pixels_(snap_to_pixels) +{} + text_render_thunk::text_render_thunk(helper_ptr && helper, double opacity, composite_mode_e comp_op, halo_rasterizer_enum halo_rasterizer) @@ -137,6 +207,11 @@ struct visitor_push_thunk opacity_(opacity), comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) {} + + void operator() (image_null &) + { + throw std::runtime_error("Push thunk does not support null images"); + } template void operator() (T & data) @@ -153,12 +228,6 @@ struct visitor_push_thunk bool snap_to_pixels_; }; -template <> -void visitor_push_thunk::operator() (image_null &) -{ - throw std::runtime_error("Push thunk does not support null images"); -} - template struct raster_marker_thunk_dispatch : public raster_markers_dispatch { diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index adfa8679f..b9fe5a074 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -132,6 +132,7 @@ private: std::size_t height_; boost::optional > bbox_; unsigned bps_; + unsigned sample_format_; unsigned photometric_; unsigned bands_; unsigned planar_config_; @@ -156,6 +157,7 @@ public: image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; // methods specific to tiff reader unsigned bits_per_sample() const { return bps_; } + unsigned sample_format() const { return sample_format_; } unsigned photometric() const { return photometric_; } bool is_tiled() const { return is_tiled_; } unsigned tile_width() const { return tile_width_; } @@ -209,6 +211,7 @@ tiff_reader::tiff_reader(std::string const& file_name) width_(0), height_(0), bps_(0), + sample_format_(SAMPLEFORMAT_UINT), photometric_(0), bands_(1), planar_config_(PLANARCONFIG_CONTIG), @@ -232,6 +235,7 @@ tiff_reader::tiff_reader(char const* data, std::size_t size) width_(0), height_(0), bps_(0), + sample_format_(SAMPLEFORMAT_UINT), photometric_(0), bands_(1), planar_config_(PLANARCONFIG_CONTIG), @@ -257,10 +261,12 @@ void tiff_reader::init() if (!tif) throw image_reader_exception("Can't open tiff file"); TIFFGetField(tif,TIFFTAG_BITSPERSAMPLE,&bps_); + TIFFGetField(tif,TIFFTAG_SAMPLEFORMAT,&sample_format_); TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photometric_); TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &bands_); MAPNIK_LOG_DEBUG(tiff_reader) << "bits per sample: " << bps_; + MAPNIK_LOG_DEBUG(tiff_reader) << "sample format: " << sample_format_; MAPNIK_LOG_DEBUG(tiff_reader) << "photometric: " << photometric_; MAPNIK_LOG_DEBUG(tiff_reader) << "bands: " << bands_; @@ -491,67 +497,86 @@ image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigne { case 8: { - return read_any_gray(x0, y0, width, height); - } - case 16: - { - return read_any_gray(x0, y0, width, height); - } - case 32: - { - return read_any_gray(x0, y0, width, height); - } - } - } -// read PHOTOMETRIC_RGB expand using RGBA interface -/* - case PHOTOMETRIC_RGB: - { - switch (bps_) - { - case 8: - { - TIFF* tif = open(stream_); - if (tif) + switch (sample_format_) { - image_rgba8 data(width, height, true, premultiplied_alpha_); - std::size_t element_size = sizeof(detail::rgb8); - std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size; - const std::unique_ptr scanline(new detail::rgb8[size_to_allocate]); - std::ptrdiff_t start_y = y0 - y0 % rows_per_strip_; - std::ptrdiff_t end_y = std::min(y0 + height, static_cast(height_)); - std::ptrdiff_t start_x = x0; - std::ptrdiff_t end_x = std::min(x0 + width, static_cast(width_)); - for (std::size_t y = start_y; y < end_y; ++y) - { - if (-1 != TIFFReadScanline(tif, scanline.get(), y)) - { - if (y >= y0) - { - image_rgba8::pixel_type * row = data.getRow(y - y0); - std::transform(scanline.get() + start_x, scanline.get() + end_x, row, detail::rgb8_to_rgba8()); - } - } - } - return image_any(std::move(data)); + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } } - return image_any(); } case 16: { - image_rgba8 data(width,height,true,premultiplied_alpha_); - read(x0, y0, data); - return image_any(std::move(data)); + switch (sample_format_) + { + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } + } } case 32: { - image_rgba8 data(width,height,true,premultiplied_alpha_); - read(x0, y0, data); - return image_any(std::move(data)); + switch (sample_format_) + { + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_IEEEFP: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } + } + } + case 64: + { + switch (sample_format_) + { + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_IEEEFP: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } + } } } } -*/ default: { //PHOTOMETRIC_PALETTE = 3; diff --git a/src/warp.cpp b/src/warp.cpp index 85730303f..be216bfa6 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -70,8 +70,8 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& std::size_t mesh_nx = std::ceil(source.width()/double(mesh_size) + 1); std::size_t mesh_ny = std::ceil(source.height()/double(mesh_size) + 1); - image xs(mesh_nx, mesh_ny); - image ys(mesh_nx, mesh_ny); + image_gray64f xs(mesh_nx, mesh_ny, false); + image_gray64f ys(mesh_nx, mesh_ny, false); // Precalculate reprojected mesh for(std::size_t j = 0; j < mesh_ny; ++j) diff --git a/tests/python_tests/compare_test.py b/tests/python_tests/compare_test.py index 1e9688869..8b3049ac2 100644 --- a/tests/python_tests/compare_test.py +++ b/tests/python_tests/compare_test.py @@ -11,22 +11,22 @@ def setup(): os.chdir(execution_path('.')) def test_compare_rgba8(): - im = mapnik.Image(2,2,mapnik.ImageType.rgba8) + im = mapnik.Image(5,5,mapnik.ImageType.rgba8) im.fill(mapnik.Color(0,0,0,0)) eq_(im.compare(im), 0) - im2 = mapnik.Image(2,2,mapnik.ImageType.rgba8) + im2 = mapnik.Image(5,5,mapnik.ImageType.rgba8) im2.fill(mapnik.Color(0,0,0,0)) eq_(im.compare(im2), 0) eq_(im2.compare(im), 0) im2.fill(mapnik.Color(0,0,0,12)) - eq_(im.compare(im2), 4) + eq_(im.compare(im2), 25) eq_(im.compare(im2, 0, False), 0) - im3 = mapnik.Image(2,2,mapnik.ImageType.rgba8) + im3 = mapnik.Image(5,5,mapnik.ImageType.rgba8) im3.set_pixel(0,0, mapnik.Color(0,0,0,0)) im3.set_pixel(0,1, mapnik.Color(1,1,1,1)) im3.set_pixel(1,0, mapnik.Color(2,2,2,2)) im3.set_pixel(1,1, mapnik.Color(3,3,3,3)) - eq_(im.compare(im3),3) + eq_(im.compare(im3), 3) eq_(im.compare(im3,1),2) eq_(im.compare(im3,2),1) eq_(im.compare(im3,3),0) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index 79ac92e33..d7ee92e61 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -143,6 +143,9 @@ def test_pixel_underflow(): im = mapnik.Image(4,4,mapnik.ImageType.gray8) im.set_pixel(0,0,-1) eq_(im.get_pixel(0,0),0) + im = mapnik.Image(4,4,mapnik.ImageType.gray16) + im.set_pixel(0,0,-1) + eq_(im.get_pixel(0,0),0) @raises(IndexError) def test_set_pixel_out_of_range_1(): diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png index 699b71c072d621d425b408484a084220f293e984..54cc50b796fdf73ec72b855e98aa5048aa4e2d97 100644 GIT binary patch delta 8164 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 w3oBb1AG4D|R37*CkP3600P7 zuhF~s_V?X?&Yd%J&$;)`IcMg1CPgJtCD9j%($P>g4anWgi%DMw(W(S$=@WcL4Bi3T zc!3p%X??~iEgQSf6Lx$yQ2vFWLgcTUt`C69Mx^VP#=DcBJiZ1>w|F~??TuwEqU48- zKMO+HR;MuG;~9spv>U7jM4M?br8$=37l;(9QEzO2j8F!gCLpJbZ@UWHk6nA~Ah08j{+xqHrPY zrX@Va>T;@yYjuVUl?f!_V7P-u@D*L6#BbW64Gs9e?aJv$D9?DMhdm`+^#|q2_R#cu zXrhin*s1SL2h`|=eoQF0vKUh;Al!?;bA1trrVAi-Er9AgImtB2b2($(d0=eT73{S$VXyPj^K8 zR);Vi%I#ziFKOgWl7)xlR()jbN9n)yyE?Jo%^&&5Sbsq5SAHSO&QKXo{~&$ipZITv z$}?!fUay-es)aAW=Cargg1T|{;Pmh;4SxKRaVRP19Ds&IeJxuUHp3i6I(;>C4#V8` zJ*kJF-|GQ?qom%QIyMQJy?Iq7o^|?E2ArNz_)qDUR^G859`+xBHfjuQjh6g3Z2aOs z{xg~&(j3OhQ7&I=Vq12Msn(&@BKveT^eL~udt{(}gD5Mn747czHAxc~EBNf~v1q10 zo)K}4B(QUWPL$=W9`VBvh*3uwQ z2=y)PvHC84*dYos6FFk@=0KZ~U@BsSA}xe_d0in!C^i)0s;_psw*qI1vfSRug_DL$ ztD?8Rky=kO{!qGQ$sxcXSxnf4#0M?u7{COY#L2I`dTFhqn`f`49Vhp3YFaGhRvbb{&ZVb2 zN{nG!x(!GaA~T=<_6q*un3rt?uQ(S;{J$Ji*y1@puk-GJ&umx)vc< zbfNSNJ6uM~Z+f!|p+5tvQU^g?gV~fwX&s%C$yB@3^O-`ZNr0}YFOQYoqts@cz<`Ea zLdM-!i2)-N`E!Q1RC=mt0a+urN3{$LJ8Xs$j8S_SH1f=`dbQ8TZl#?%A$-Nt{Z6>@DxSi8UEc!%XBsFG_^T=6MnxjdOWI z1l*u-hXZ3th8qX6h+CExBuHt3SO7iSiu&?AfG?02gnbXDxK~Q>MHLp8g(!q7{u}d` znV~v{QmUfmy27_QDm>dPaqh$Km=u)BQcn+upJtXyrz~wwQs9i0tbgFge~gmGxrGL; zR%go}L0o&zu7n%(No_n-i9S4LVt+=2!8JAkE}|I2=qi$;#)x2e2Xwl8g4$EPw|J*s zmK^E1XNZo=oc73P#IPB2_HZ=SG9os*!BbjLo82ZwPNcM5=3vHi8y+&ov^^g=Xl91;!$bba zJ$E$?^t(T7S>xe}z)+gqnyORV9}7T^p>m+w2(3!*of-RuYVEakZH^};W?SM_=xs+s z1fk7iHIG>RD7sJW#)G@PA~@rbD%tH=W67U#^0Yl3P3#Afk(PALG3{J9Rg#4|lk?t6 z{&D%RBxb(>U2FCF*|gjBISltAJlNcW_Fb!Rt2wbKdEh&drBM4G;sJ7UWs?IxzOAE@q1^$L{-UBAJpX}2dg zIR_Om<~A7)Tika`|2SzMv)jd}88?lrGlQ@yFdK!n<+`k9LKfCijKFyiZm$^KoD5!% z?7jweh3h19IO>d0bo_zk9YOh3aH0bd>^%*%mTbT6^f;kS6i;x!LaA8jGc?9;9fTz_ zAAD4d`mE)qzMs$C(BiLF(BY4^1d@H^cSgzXxik_@^Kbw2Z)uro<+=-fQr9qIHD z>ghviX3{qQ7gwKldC5S8lwOoR7=S}goWr#tx?V?3w-GxZdxTIa29$_E+!{`T<(4 z5d$g<5H^!AP{MeNSbFEI7Ek^>^29$39_N{R)9zDE@BQHU&i+83ANb`r!6kpShXc{YJn#mp6dAY}`p+ATlh@Z%%KWj1nk-cO})W_$l^6W=%=dn~Q z`kUs-&!7(=>{B~p#raHRgPgow1^LQa>{!PP&2DJa(&rC@?m?~1fW__A`9Cfrl%Cp& z{)ol}m6m+*)go8?E61*Cc7tl)+W{>wC&~^ydo?c z)aBA4(I@gbvuaZ`qT76}rh+hr64?xJV6q9MRJun^EQ`(F8et|23*@Iw^HjES?L16) zKMvQS{##fyN0}KKp(gP;$2beL4`XArH+*s*l-Lgyo5x?Ver8tI#JV4lJ1k-PdL zXdzTyy2;yZb z$6<2RB1QK=k?=W8<@(AR&^TFr4NzNUU9Y5xO{SV2j_C?*Is1Dy7=mQM_!UK|$otZl z`TJG(szQ6(*;lt7ZO)1*c0|MH2)%W6gDRFACON&g{9x{M146zl5vPMJ&-wCd5f&bM zTc*vxey_ueI8893X$s1cYbs8K-T2AzKs9IL0?CHM z>QX)$Gl>*QvAQ~H@QxN`*S=5f^|0^m8f40|mb%gQTM$;3$9iPkugq=MM(;1TD#VZc zzMIo}4!AGA$#*(gXEps2>ryOW)?o8qqNET2P6aD4au$O^T<5LB9cpQ1n~(fqjk=M| zdCHkpkSxU~Kb44)z8Op5k5flF>&qG0rrQb@pz~a$ih%k-wFMpWxZU+XwN|ToSfT8e zxb<`E)AOxerV?xYCieu&scPPf;m7REh0ycy!1`rU=7f>=E%DXMM!sCc#=3#k&iTOI z>7@{5(>T(ao4P^MqQoOHzFIA0aI&g-H1Ccly{75fo)Y`K5j=y0D|SI3<={$aZpE;J z4`Wn?>@DK3xGZ5P@`WCzvC#GpwyqYt_n-*)+pV)-Tmx( z&H!N%vj64lT7JN1KuTEf#0GsTn*Rwp2G5eE{F0Z@-1m*7?dBD}4_iS1@6(l$T};ft z0D*N*dMA*`HPMn>t3{^u#Y)y$)i*JC^0jz4T#+==$mOJyvm(4N;P;u4Kf9GLGpXFzLDAy?%uu?d&J?3`|OK;Z6TCAL0BzNR~s*cX@z00dP{I?v* z?-QL_k;9fr`(|8%Ir)3%5{OzTP>7Ne(ThyBQZj z?~&U>r2l31e4uL>j8CLtUdRW&_I#OK|B<1oO3(dw#t@PG-(gV~cL}yh+`o=)PLyDE zqVbXD)DIi#LTJLb|0=4BM7Pvn_xtB_ntQy(Z0}S+7srR7Ovb64y=B!82|$da5tEOAj1sgTl<$4g zlm4HMJ&o4e58};T3xqY$Ha-0&+pt5amh;*kn4wY4%u~53iV}plSxK+x6eqN6{cGvA zz;id0We69_7?tt{qUM4%35QTG7nqCTRSD0p&lDbvIlHe$uaB{_wAHud{7z6 zcaSi*U>fbV<}*=^ZzNYYXDN+R-OjyuXFD)O%dnHu*ZR1jA%pTb;iE6&ja2djcE?sw z8U@`9F#rp;hotx)5XVCc`pVjE$LD7Weq(-|nbdFFeULcR~x*Cdmt z(!5|{patVhA^`I)S*U7bs7~1XjgW^MWNW={vFvYef-?=l`qo4!vf14y)&NYKSN3$S zf_N>^BLc3d-NyAN{~u~l<`G+w$o08e%;cSl0zV5Fnm+P0^W|3rTVd=DO-8$es5UzP zL7;E@P0+r0&mEBu5Gn0KY%)*SAb9`#y)>}}`iDi(F@VUPt&}P^rk97RM-eWuMO6I{gPXy$YN~X>#56iApkZ1{H1-NFD#Zr`ASxq0_lsN>0@2d$xbB; zA0fcVJ#=>9jPVz^%J?;={g)dbmxM8*=lk$o$);mI5y&4Y;1W_WvCi7)z_}R*#vqRs zheTwCT(u{xBfU(CL0BAOi+^xN@@(X4^Kh3!5h+c|P>Jau#I0L7-+59C`&i(AJ>72? z`2L8s3SWBXxkG~pF)pCWCT7WIkcZRT7onS3p==D5__MDM>XOT*mZ#1slnIe(-`hO~ zDq&(}Rdd>F?aI-A@G!`LbyM@h!kmj>ROvn^4HO48A0#%$;UPY&N0)Fqiypi>!XZr` z!U~s|1^j1nCoL!8!f&d8#+OE@!JhJRF}8>P?jk8~ZY#y9;S{c-t<01!N{+p%dDHQX zO9buhWrv%`9M0hu+*qJmq3LvRx!KrB&D`bMG;E!mpEhJ?OF-f+?MCvey-r#(gPkoq@4K*_0pL>?MbRO zkYjMhQtVoygkqnUvVW4~er#?m@-HjO<~RH+96z$e_M$8URLazb@Ub}6QYT#v^aH0$ zi>A};SN?7$$enm2=GAuCnAwgbM%xDH!hH>{qdyPG8il2?IEy%y!2@?(UuOS$RyW7O zF&bam4`4R9+yVMsGt~4!Z_a^UtB{WyNQS~Ihjsv^xoe7I_%<+4)luo={{3Pi@{_Ei zh`lY`H?64a-R~Q@leKlHy+`qxk+%IEeH9e~BksqQrjX&su{4imsp`|wV04RU>tYQd z=nENZo?3kVk_eJ`R~IE`5cO!MvNG9xF-}3x29Zgb03?XoIl)z5Ta!!cOL>#vDN72{ zSU|nrChgFXSBNXv=>AoMI8As{jrMiTw@ZspdjBG1iWgV6+Gn=sN zqY3OE_R*|N5FI!_vAjFG?5#Tth`k2!(T$Q@) zOz&2O#|^Eg*!*#`nP9M`^UHy=ZoJ7lG=x412 zqWIl(P_UMI7^ky7M|Nyu>F=>X0{Y57rESim#Q6i3U4DHO;7);ZyhgpR4=C_(Bd`>@mMS$-P+fZJ|Ko*_jyiPYIrdFKb-1Gsi*LU>RPf&)JlCfw{ed zRyqB(wF*A_h&`o)c5~jIDwg6s$(r1FIqC9o<__*J z^I*GQ7X*fhqZ^Mf;S<_b`fF8K5>yxvaN5r(s$o%9OXf3)np+XKIouz0>9@j&tI8E{ z(^K-e4^2;yH21iOxl4Sot)TcruAe`3XceSrx)rn+bSyBIXry6!KVf8eqpXj@a&k1l zpF-6X)#v_+LJZPz^|sLq%T!|!!n|;U>egv1E*2E1b39guTR52{hSu>u|2hFcYv;6H}O!rZD-@Q9>_pkoA{&BL>F1cij3&BaPvvp zs-O*Zo`j*EnVUrD>t)JbhSjpgFjOHHtx|QlGkg+kn({m56_7z zrw>2dd`n8mJtl-VmND-BH2-R&ol;kxxi+g0PN*^rHj{VzBcH-e3yxYf>O~U%;_oVX z{diySrP%cNH@4JrML*%(ANQgeYX&-l)&CL0Vg7Z!r&t*zTo=Nw3WM3E3;mLmhi&OyF!CucTa)bv3*Q9 zs@bT(SzoS!m)UMM1ZPnhHN90SUD>SMKZ^n_dZ8|H)aaWC3#o+jz~GdD?TNiBpT7yb z=PEdo6k}i?bNHtWvc$u*D4jP`2qg!nSPI2MH48%UV&|QJ2zcX#y{Vq51pYYjUIxS^ z5f@3{1<&_c*40Qx4E5kfewb|O^=Dg`2X>&u&agvO;1@8<)j`8PGe(M$Bh{Zxi#Ki? z8?VF}W(17ya%KDHTh8HVH%8j25Bf_qCl7EzSjbHe&BEY{6cXU7O&Y~fr8>ep=~3Sm zj8Lxu;j@31I3|$1@8M8@rV~C0%SWP8@`_249*2Sdx+W4Cjtt`fsSbwac~m_v2{5s{ zQQ~IUk%38?CM+QI!{Kw?XXc-i%vI6*v}RFIu(tpRtEkZX^6arH+OiZ(f}==rX#mN? zwO>zJ4JB5@@8LpeskU&O>i@cf0GeU$DFFiFG>lPW)194}Sw1M!+fXJD1Httr( z>Yn#k_(IEE7~H^{FEVd_w%ch3N4oZ%+J&v5)8E4l5{0zQoNmpMm{kFEb=W4O&1YzT zejmZH6)`J)>y90PE35o{y^TN{nUJleeppnLn{#;hu)`C0nDipPa9<7IhSfY(?^4lnl2U)^Dp57O{4t7`7HqlF#C;3dQ1^pk;a#sL z#T$5#08}g$c|N_yg-!c}T;{D~bY+(AfsNDS6#YIAt_+ICKK6MNSWLuKJ*#omGUJ*)4vC$EvfBwLMKoz2X>HnR2 zL=BtVxOX+2P0#t7Uzn|trj?FzB06pR`1PlXaTxe#mL|VTBOA`kA4@0vXq;b`w{hg1 z$GD7h^j0v=BtbQSelf&GXoJ$p=+j>=5I=r1f6z=ByF5XTQfJa_G%;K@)eVNLzsY;T z!eJ0UJ|@oRaLo^eA`N>vQVOXo%{4zl`@B(|`76t&&N(mb-Yc~uZlfV*8Dy$0Y)Adz z2>QjK={P7)pT9;ZMY#fBzi4J-F)NsaJwSbwymh{?$qwL12bIO27Poh8EO??^i=BI{Ww^c7qgcH zt`v2sYh%X2={q=H2cj6&2ebFv49#>vl@hd*YsL;#mEQeGzsZE~0{sJE1Q_j$wyYA+ z^~f2HvyCh*VtFuT2B2`^9di!iqk_&Hd_ohTjB&#eOpkCAGpW?#^)MWK4>Ww ziYi))U%tQRuY1qE&$;)!&wbr<&ikgRW~iq5AriEos+j~99u`sMT6G*B@>7+wqc(6nVxQ+6p`0oUxsKs%ro8a((o6y8sJhp5`DKbadeeKBEk6 zLBMt+WV^{QC;JbVQ()tFXp+wneGGqT+%?5!?OZUJYh!}=d^GdXQ8@K`dqucuD}_8w zICTLX_;svB7_B88l|cQ*HT7tGay+0g^C+CmVNz}gDEKb7?-C@(%dGW#e_=TaW^fAZ zxs;USVP>R%VHd`+@ql@eaiP3qy_D<1omwHqNo&^gj^%+TYcUh7AxZRU$xGd(Rc7GR5jAl#D!9PhAk9VZVKl6516Wb(xMExXLJbsB4 znZ>S>tVd|*zXo5nEXTrX?3%+a9`e}B@j(~(Ffdn5_K5A z#A4gxf)j4yMbCdlNM?~skxwdjmxw1UxxmYfHMgt>FIq&>ZvEv1p`Nk# zQ`lY)1uL>MfE({74AJ2a-StrNPE7eN-@3T%FWmJ}nQt4Lo@3WmN@05Wv}mP^f|V+m z9wyk`%c%k`E8BlM?&Vkq&wBdh@4DUVs!%CQriqM@3z#}0vc1}N5{d=Ju(ZE$iNszH zv9y??BPL!S#mWSq!P`Wk_6`-2d1oqeU}#!t_{KG@qEibza+c&7>H=+z2HuPs8qLa{ z-wOd0Fx83N>~{joq>wdHUpp`?P1a}~$j>hnRKqUT4L9t z8jV2w8KNv*p0i=fA4?+cmA_M=b$q2BxSnDvJE;3_oG>}lyEN42kqVwd zdsel(CR)G(HkB{83NeV0wqbVPm(f!ry$8cLhoRFgTDQHsYoq2QgYrxbzCf+=l;fA) zXM_nl&wpXdj``R4qJ`X_59$z%8Yhh{yIMVXhFZhW2*w3G8N#We=cj<`O+U8AOJNAT zvaeR7k|(_qASnMhnGOdUN``e6Wf>HMZl<-0f}nSB5MKw_!AnyEl#r?TT|I5|o&J1+ zlUJktllid(=Np&8DDBzQ0h;FED7av$50CacIqLqATq>}h1Q~Wb;!zZ>sHmfSs_mxQ zPGu=fS+3|aUyO(#<&FyuVt_&rvlkiFq*1&M#?-}9siF1XU_~W#3znoH zD##tuM9YYenYwy=C{8unj)V35R4A}=;2XxI9f9w5CZ-8RpK?Mv-?!?DL2ny~- z!ILRoDruR^ogkP3X{ax%R8xYH%^i8b#hYA`_m-Y&KKf@ zOJGY;4gHf?_CL8oN~EmbtPbJ$m7zLHVHt}i7J8IWM9E#GtVZe64(%*49K9h<~ z_i!-c*=V;f)@P2-N?{DFMm<+_y zPBKIV;!LGsL?L}!(eNS)G8`S45%St_O}XnWJeg7(Rq2d2s&_Q1sZEC*nIXg(-I9nU zpL^}eYg2sQ%3Y05xc+W#h@$%`JpGc&(vXy^=a+R1(~#%dLK#e$+IVMvjEb~uV8y1I zUr@2W@hxF#Q@LWnvejbgm$Gy(bEuv&x?wV8r7NPe9yS;nKa_Cn=_>>yWj8--*#$u) z$a)Q2p0E4_ekz0ADXu@>Vn=9hcffvrXqCwP&m5sZ__x6Tt;X={VNG?JQX`fB!`Fm~ zv6GD(IRUSETr~HR--+CFgpgNcuEbe_a1kYz-iz!N4s^R++>k$0{&&>q2k3oRLX<%` z)ugUnYV%S*t&r)FP7q_)!tj7kC9i$r;YOSWnyeh=i+k&LM4!2j2$%Yjp<7xxzcyW1 zPT12lT^-!7vXz*EsVp@$@H@twy1gx=lMKstoE2f-Ro=^+&}~dlE0rMTdp;-oGL1Z35%X?i?G;EPI6*KCB@}B zHVBR(!lur2Zy+X%ho||#En~b?ST@6q>iw=9tf(f@2K-u;(JjXLUjnD{rXTfy^Q3*w zTI>?@T3!W=KUADMskxc0=57ZfbasD(Qk|r(fNo0_`@Kq?(d{V!5aciltQ}_`|5rnL zITRAoqNCI9e?o#)c=^WoiO-wi^N_GuN<-zJ>Ywi8)e#g8%h?tnT!Olb!^v(}>H6SU zw4UCt8~AL?quXCK6dBFT-jHob`?SL8nFs|V{^=~{mU&_>I)SUB@awiU1Jq233o*Fp z&JJjiu-3{vJPNPaN}G`v`O!U$<4IWax3Rhy5r7JskM! zKq$HLAgvGfV@PVq(3e4-87cccPATsLbyU7z2rQx~1ajG;iq;I&4=+*pOesh=;&)+h z)RiUvg;5=?$+7Hf%&X=7$2=VugYSlvf^gpvpvDHNjgk0h9(XTo%K{~1=kYay8R^Ft z!S^D_h)x>s^ui@ckWzGHH}wuU&I z+TZQF*o}Z&(^ojV3Jo|*uCmLLUcBac*yY$32JGYoAIi;-Q$UUVJKiP3J*Zf|arm^V z-|4W`NLybdPp5!RUs3(~^ceul-S5s010}y=+N@g0#7Rv$Jr&wHRhpd; z@lHx49`*;0Rq|E19bZ;IzBxO3y!bY4KUnkh;N#oD1){2tKc0!t)gqXqjyBY>g1q9o~3c=x|{^yH;sB^6W8D<>)*to1-qWKgMEq!~plk$1$gL2qKM0)xvmvw&IrMkqm#H9Ep)#nG?9PH4qS{fHR=TP`d9B8#PLd8Jv#n#%9->RWdDdF7Hm=uN;0336tVf9vkd&;YLQ zmcT>CaRyYY>dEVW_s)>f6|hwAOkEof8ucmP<9fst9hv)77maP6Mdi(7ogJ3k?k;IZb`=qVo zohSlO;5<67l?8`;2N-uuwTIOAyz7=kR0*l)`J70GPUYkREV6~1qZ*;n&vL`IsjHV#U{bmkLVjhvf5L2)VQ*MI&dcqU zjEP0tHftonueCYqzWlLAa%(Qu%B!kag(5=!Lsmd@gl(AtdZFFU2=HP|3JYM1r?oAs zBO`e)fUY#NS5c%>|9qdYcNP{4S&1L%4;Yds7?=K*ly>qjV*gUyW@%ML#4qD2$c?0 za%;5)32TtOl83O>TD8P{VC(r9gb^>|u29Lv@}eSy2F!6zdRACe;ahKD8E_ggki^{_DE>Z~OK5jw|0A(Q8*BUy9A( zdRDVbCRtKLl<@4w3s=T>F}Fe8h?Z)al2}l8L%65Ixn37Ux5jdv{##Rt=O9|^8g;k; zkme@B1{d<)$#c;{?tREaRVd`5&sM>ojZ56T5`Tl%rf z`y28dkb!XD7Ogq%I13|=B&clT9{te${E97hL4t2LYuas&b=l2)+&C#5L3W6*4`#&I zzsFZT9Z{Vqc9b$RXP)M@5-?UvX-!Z!FE6RcXPkS_^ue_@j(3YBU)CjzFBl6d^7p-$MzAEiJ zHQm>Y9cOv(UU=di39>ar&fG`dOP*%1N-|3q2oD^R zS?(s8b1Yt{w=gKakOSfD-{bq&f4ndYcs$4Iv9cj-fx01|7wI?YZ}yz&|I#VGNaAM^ z@aL$hPh48a(WsK$ecW}MP5ad#OaE8TD3}pX_f_Gh zpgTCCJHZowCAG|Ffa;rbce6RWGI&5uXNc+}8Z5>)odOD1jr!cH8L*epi=a)*ujg@( zSAMG&H4=)U3+*7pTzwGW+X>4vQ~=Qrojs})v!6ta_(V++P&G zMysJciOlOvq~649*-?r6-LimiG988tSLoQndoga*ZCvEo{2^p0K;|>8jaA;|6sEag z`JozGNK4jZEpi;FK9=MBY{QrI4z^Q>WuwAF)$vXUcIN})FdANguM##MbjzZH#QWd-?#3Zn_3TWEo^AV~kCaXcK>GG(5S< zD9!3;Xs8#~_{(A*F`+O?Y(5d#&|rOL8Uddo#_rb`c}09drE*O-%vQjBRnZFWwYuBC zmTFE_MiFfGC_;fJ9vLUM6~5vqvWR~(xXKQKK0oZV8Qm`LE)v(iu5!L~H9#@%RrOEk z6sskAZGb~*K+r1cGWJIOkjK`CDxyc%YTINWD4%5GC6b&#VHnAtZF*z!$&pzR?>Mh znD0stEDcU+0_G`?1^h;8uYbeKdJ%S7y_o71zhIRUgg~qQ*+O-M^x*Yh(n-EuZfi+j@rM!oNmn|8YEcF1EWW(L|w{I z>|}goMZSw}!rbky?o{N$`E1kHqXBz?GGZ&P+(F2Lun) z#k@SaHbY>Ip%PTs{27&@`794aM#(~5KPB}p2uFX;!@Nvn9lLLcR?X+0Op|y?4(|uS z5wl?9PbPBo?Pa?yLFm#*`wPdwH$=e2?N|kQrfFw9JaT#@?NkdulWhrvBOLIWhF`>-dZY9Ef>QcSEe0p zI3yj@a!G_zpVN+ji=T>}DBGdQtx11i5!$WM@Y~OLIVk6s& z+&O|>1V(o|pNhyae{kQZ0N3Gw^-p$bK`nbbh~4NNHnM|S^@6B^PGSlBzdr1X_K zxBRg4jg4^8>f#>52F>ColcX!;t+3YaX%<|KGaWh%s6(_8yYX1}oMfdM;-n-CYoFCQA! z{#fhDDl4Me@|D;!Ek^d(-xX72l!3(XeKQ1VD>R7c$;|L$RM&kKa{X0hwPWKEF9dn#6kshz|j*OdPE zocT9{2+^8w?lhGDw2 zK**K{3LGnoWFr6YJmUF+;}_pHo2KZKyPyTq1DJfq16r_kD&jKsAH(~BpGM!yYO~q} zyonL}MJcCtn6SOP&}i6sC48sYwo^~$;~nM&gE+aA&-i*8|6!JR!0_egbq;{0fN(F( z>bF!?Mvhfmh2O3cwmi7}i9Raw#poVTdt)7x2$~eTT)5_aTIUz3KmFhpQ{W#>eMNXcnrgV_VUEot1NXB+oGId;wRRv-vRdQRw;&FN@u3m`WE*UF71Ax`%Z=Plh{DpiOVoUjiv= zUt#`H_aX>VFtWdJco}$<%6p-T&i{zjGfq5_-ZtIR7Q?tHw5Xw_p-!zPZ0K6vD+Cd1 z&kPxMpCayk_G=O1Ir2l|ii?#}*qt(Wd-2C6dHs%Cp#~^A^LiQ2Gr=^;KmwQOr#Y&q zWKCn6ntZTJ;BoE<9qCkqR5JIL2os-2xdhNmfnU^nax>zAT6p!U*W|%;1oH3Rnvob8 zHh-XU=#JdHISEoW!SQ;YHjf;ElugF|XFH*a7K(i1aKCX+jEE4%i9QrgLY$)Ddi0Px z>6%|F5!S8a_HDBm)e>>Sq^SY1#%T#pNxe%r7wzj`Qm{t((R)DYo;O zUEoBx5C}T*28#h=^C^)_@b`rZ!VDlMj_;B1R?P4CN~uwT*bkA48Qmh#nUw@;mPng| zOQ47x=||4l16)3HAW*ZpElvu0wR?6p7DRr71je#dp!!54>k&O5#f*?!XsQNvmIF0@ z11Gu(80HHxU4CN@k(nYi1?tH=Y|&opKM8g{rX5ImaJbpxN8l9ZgPR6^!JZSOqgnjx z=6$A!ZGr)AJV9?+M6%JsXp9n6ZTS69gQW_C1& zje>}I-Ynf$!YkQ^*HmhN*o~JE1$Lx9n7n4JQRhuQ|1dUT-9ZlYKd>J69I8!+VPxaq zI1uxIboNZ7wA5b|SuFmwY#U!pI!XCG5zEwmt zis$n+cxN){Qs~3mUIGZ~|5@Cea0$2h2+e4Tl4i45kz8xaU60>k`$HFLYobo3&zcmz zv!=uhePA(ZGlZ1)0~w2Mi47jBkG`^|c(xwH9c#P=Bs@3BooWyBn`AsH)XN8@dd!=w ztpb%EwvZ^&C+a0+(Vw)66)NYlZ6XY^v}LUrC7hqYD}4_VPWi%ke`L2)mx;ebuHrOYTigN;Yvog==Yv`?_`QbvV6%C7dEK~?k`R!5fju!#P7G4+%~PASiQ>UwvT4&Uh_Am?N;tuh2WEUP>9_}lydYqxP>D?R!Ju(I$JvK)+qhDg!#3q<8Lfw;(Kvnc~JN_I6&&Lg$63U-?}e_ zY9MR54JOhFUsxB*swWnr>fv{5dWBBPjbBk5=&2GOg|~@i3q4ihd>FLo!6YY^-8&g? z!yt)17HtD(SLL+-ctD(L%4Rd{gq42!k11cV@Z4quibXVYC=T{yB_k_eaQZe-&c^UJ zP})w&VSjBmz~odZs*50R4gl^(C@Y@7(0HxhfnDojda+LNJ&1o%~s z1yKRFpR{P8jf_t;>G}S<<_U3%hN~6DiiXWauwd*~_n$PYq1oQ;zZ%rYbd=qt_oBaf z)CPj8&09+!iH?&{JWIA7x@E9r1b-B63LpK{!tx8TQVv^}m3ZE?K7Y0R9wuJHpb_c3 zyfGAu)oCv&8gamdEPsFn6{brC$C1RL+K*`fp3htZ)*`ov2%olw{?i7CUDW>pzvi12 delta 8161 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png index 699b71c072d621d425b408484a084220f293e984..54cc50b796fdf73ec72b855e98aa5048aa4e2d97 100644 GIT binary patch delta 8164 zcmW+)cRZZW^B0^hh*P4MsHe+`=)DC|&xL4*5bc9RFURSpM(;HUPC0_;5>AU=PLC43 z1WEMZci-Rh*Y3_fvpesZ*UWo1St(U1*&80Kt)^_^mv@v;o|z*<9s0+fJ9!|7;{Luu zij>N5(zK^aZ1s8Pih29i>u%muZ3)#JJ?agr37&N(Ce|OfPqn6#eHD9TB5aP(Z=F?C zex9`#5?%SAZT>o3GZ7-sID?v?=WFBE6KYC!w%03z_nWyGGWszV{9XqqmVh(Tphh@! zCluU4)N{HoIiCm}CZI|dXvm+`tlm-##w5f5^3sk&i0ntC`p9@bWOZNjOL5X`{oS9QM?ek!kab>* zNpa8vAHB2*W?2=bp8-yn6b{VA!2w{9N6)ofmz9vJU>q!%ZB+!aCPWy&teEs4!*@g7 z_>d>7BJ^v>6UnOpv`!weVoDvui()AI&|DnPN;~_5?2QA=24e^O2~Oug>j~{u2%3K^ zvT*PsPF*bMUaiXtg^(Dr59Y8I&5)t)cySpP)DBG$(LVd-s8oy7h=7+f{=bxdJ_nY3 z<{#7vrDQ~MV|Pw(Vc?$As{I}G12j`Y=7D08aEt><&Y7pHvd|jgGYZ87;h0%QWID4# zf*x+5?*Y1QoR5N5+B5`TNOIUoaY3dpODM|u1$8q*h;V47=W!0-Jo0_0h&YOwWw35^ z!t&K~qNg_CV(G-<#3S+@g~GA3POuVVjdjc3i$(#oQnmDBrekrMdmkwthj`lE z?@cKT4F39O_&(?IisMnDl zoWYAzq*-f6eK7dK|K)6zYMtDu`mH3If_ruU4dXVac@_nE+3r$2g=CblmG_V>-Pevp zVGzmvD3`{fO*S2!%fT{hlv$$$Gd)OfQ^2;2eWiv(-$nhg-Dby=S{}mV?YiM|4D#Dd zo|wpIadAl93(FH78bbrfJlc$d6f$TD&rFD$eHvw`5`vJDsePbb++;Jn7)K6Eq&_R( zSrW`;0GUdcybd&okg%e6-G8d5O!yFb&=8DHF>l)R?5ILaiuq@o8Z1LzXUoUTeoPJK zahzIa%82+^_p*`LhYMmKfEp%@D!y4f)I=@yQ1L|jD)wQO&{Lyis`Y#8!$nZIUh&53 zL9x>=5q=2wFp&-m8bX9|7G&rZf~+Ms3Gzb-uqyBDp@+7n1}I)rVM;x1G{M&#oRb&B zeG<4aIOiJ|K}qeHQ~?^VKnNI5kr#*d2PulL16kxCJrN?zaOg7xwVW?9 zR9-57jw?cdhjhyct73qHKVZ%`s!S&F2gZcry>=|LOd?yTkF2dhc zrJfpi5HWfac_d6eu-Dn71qvFwaKbz&S|b zr(c76ALCG2f1C)FR6^gWtUu^^j+^6A9LS73z+4j~Mc=&%gRKw~x<4Mn$F#i^#wCGu zS!MLE2jCx4d8A0N-h>V={EAVnMbOk46LURM2)vLI305ysYi0ii@KMPo$4%1B)2-=_ zGz#!A@SHU*@qv0E&;`McJR;0Mz$|I``w!!k(Y2oQP{-%|Sa6h$cQ>X8I!7op*2w}q zV4~i)&ZkvIvV@`=MABW{GDM#> zU`~RZC7{>6Pwzc-7T||aMd(+|*gt$lh6LLzVs)cR%|M|r%7`EyVrgC`EFMPYG*$3P zw5bFXFR*((9F|W)grxxiRXhxr!i7eo0djJKwS$O((TEm&1>^T^iJ zMdFS&l`7yVUM!HX1=HAOlB)q-dQ!m>r3fv_T0>(=5r@w1JP;DRHm7CduOdR!W#IH; z;TPGLVkkjD&B;15Tw}8p`s-7ZNZOBAa2edcwFYQq+TW6u6~%IOU5TkvB;3oSfnm`m+xcG}rhE=PR`lplS2{2LqkT83ELjzMKWh*>rVtz3)E{42~i-l>epr!<-)*tLkKby3<~?(mNEcr}z5~ zHqrR({&yuwY6HEe%BD)on9QFu0TSSW+C&`E)t-JlA(-|zP!Z$jB& zayN9ZPrT3Y9jz)o61*KPm;H$Xk>ec*4b2Z!xo%WKYxwDh6w1tz^3V);U)UM7rwcCw zRnZzO^Y4r~wLC9hrC=itI#i1IvDCF|&_0r#n zM&jVjOQ+!d@9^lUfI^?fuS>h86n}c)w_6Y#(oP%1AT|Zovgdq<{&fxD3S*k&6ci07 zPtv{cAF=)^`bo26))E}QqWkM%Cpfi#7+T32KPRbh<0D&tFH6BkU~;~+1V0+x-|4>C z358icDs^<`{pKjP$P6aD@ZgYacW4eKYvTkRNlgutK#YA_KP151$QgdJcr~dKv|6ht zugnmqkU++6$bWyC13+^&MZQw!9K2BA$M$Q9|C{|?|2>>(fj;3wM8txlMT5BDEg-Bh z;haPR&5QTS!Uw%u7p?j|8BSZO^Yood;OB6<`KL5fR9#L~5Y{&pGX^LD)Z0T$7G3}M z?p2vlL?bckoLO~IMP~tdC&3tGayNWi|G6mZX21|7phRGDC|3q{1`~_a5cMv9?LWic zdWQ(tOMlY9kJN!9tSimsmC+F5_cFdgY+noebW9yOa@sX_qmOgO;AakvMMgRgUlE`8 zJ-?na*oj`3khrkGC2u7MW*fEk%E{iz!nMK$ZVDPVmG)oZtCPMu>>S4WTjL*SszMSz zMhworXp}dA!g?HQb{qZ)A;FY0O`;pg=}ci;GclBS1j zr8wR)lS%OIh<^Kz0^T{l8^j=_Z~*wKsLv(`%{5_ZyYmG#u|yMl7zD%9sgR;ix>BGVW4;L4zi}46v5k9+B~dB4-?Nx0gm9% zYUfIR!_?!w)$58`sxQ9b68DsCq%V?0OQ08_DJhF=mO0JWsv@@{Bf?YAGWVc*<;T6T zA8DJ#m{Ia<@cd)N*X1=$8f2WcPi_u+u>T^|7skWm7^wKMmPMU0WMJcH_cV$4RefT$ zYW{X{s<5l#Lnos&_39^jUl$)6#x#E772(+0%dE61YBc?iA)$NdS1#R~f$J3`Si0l| zPKiq40NUZAduecQoDw1Y9q~ghoNVlqh%?M|2f%0yC%;}|Ni|1hmig>`S#>z4d!1cc zI5jXUNVDy8XVVPvKAqRSp~k7vXUHpdzqin>ndr&r{ntPIOM3T;xy1JfX^?kp8BV{L znUhb1EKQu=nlZgk9(Olf9I!t)|8lazgcz4=^n8HyX18nxg`DioQ+ztu6{IxXF{Ca_ z%S6I6wvLnQ8f+|T=FcXTEM`UE;X&`|a_lPIN4@XUi}p zEyS6@*~$M}n%~_i2MiwQd^6`{EcRM20{qhaZCdda*Ag;Pt5#0l`*_f4pEkFC5QGDA z9S5hh(qS-9U*p!%mcW|M4;^Cga$ePJuT!z0(abD>c?Pc|q7D+SnH9WAfeDB|3GC{> z(WA|n5Qlj^1B;0-miRxiPl^{9E4SG}|B$hPitC#5dKY(H23yNR-!puklG-gC5(>9& zP>+S(YO_=?U)mwrHD;=$l@wkF!2^FFOCgzj*7N|qpbkekXeJ_&0kF=|)STX$ny~9j zQ*1A{qOWG_V&_{R3IGaDpwF?>c9p(4$mRPyR==YlZX``0n$3_k@o z%FXk$5^2ZUO%G)js%iPL@04^L=y@5G#`=4h?x${zExO!0V({#OBtW%rg;rETQ-wM{ zqraV;8{g}t3Xv(lrt={c;DLavOc@))%hEt95X(8?SzdnWyBY(F7&}viL$8%EfUCbt zmHW>=Y}M?}S0YRRnbv*(w3lnpkGJRf$kS&bzi%t9T5gB8oVnf$-a7NXBUuZmVKlp@ z0}~pe_$EGII0HXK-1~RH8!M;^qxd^&L)`7p_1aZ*D=k(Y{j4u^??r3fqK>8k66|=G zfIRMl-zjUFg%K9AGX60#$6HD(7Do=b9~@1M%HU?#ns`Wbc&)TuuarN#g*UUbk0I9~ z5kL0lj3o@+!195xAU31}$7!_Utk^2jsD)R|F< zU6I3hLsqpA`OcbXN+rj@VqY=np>c)se%{|}gMm3*6OjM0UGj5tCi$P1Sno(Ta7u~v zsE@WF9d`qH$j{6E*SWqVbcxX8C!3wtlPin(O9Mj}W|8+`JlS&b^x3A$V1tz_L2qu= zEpj8NvCA(?X?6T?T?9-%=KH}_TWz%wGef+$eoH1`HJCj_Es(l?B=h{;h@Tb?SKu#5JU{91U0H3?A@*3Hwn*jIK2o(Oy1^yaw+6phWv z8K7=HcEESB9f;G*IBu+L=zE^OfB}#%9@0B{`JcW1sx%>{O;7Bo^ApuC*3+*=&}X42 z(<(+8wI}tF8EyCEK$o25PqDX9Rej=bU?Pj8aF`xUy$e6bg+#Pg_x6p=g5F^^t`+&1 z(|n}l5LvwWy|MK8IU)>ZnHqOIDOJ=E*16#|13$-gI)jEc^|1ti=N)IBT|nRgzSvdU zjK?!ZkG>oL(pzI@I3VMfE`?}iUDA(Ld?c8c9~Q1nfEBQ*)2EyNFrbXqfC^}d_$qX@ zYzVmTkKkdL>eUzgQjWReO9hqC+o7;ClgejG?pRGKN3&f+6t10Pl``e^y4s)dXSatZ zh+|m{P#Ha{xgOnz4ZwZxHrpdgV0D>~rKr7^;g7M5k0H~N!C-y}`TOZL2cGdFOv^D{ z7cmfI95s<(R?(SP>%*RYamV3B00hxwnFV9QLpI1Oa{^AJZAJ+&I!cpZd|*m}iqMhr zyD+{~$1vCyvq3E=gqUNma?XL;9{$#)W(5IzPCn4w<%C>rZPN8QtJ`=QBYv=SOj z9~)?mGQn4yE!R(27u!+DT#0i~eSLp*JuwSqe z8mh#bo<5)qutNGnwyLEovW_WBQO}OkrmRjRpwik;A9kj96Z0|psX1q{H< zWRbh9)v&}Um(Mzya9?!+mtW?cuYp#sYl@v#xSQ@SRL=8%bW>qzq(>X0z19i>BqO?} zS~-8dppDwdYKjkzoi#(^GrQjWsT6&t=%VP^^W>kzIZwtrx15y>v&yP8M@H5+CyZ}| z?aW|jmOh-Xi4E3B9_Op*7pw~-0f#y$-j`9D%*&=jAQFuNo;uhFJaRyjpKU?UV_$>u+rHs8yd1pFLCk_WCk#n>ho`fM#Q>3=l*ZuRl8H%xG!0JdsD4 zDP%^%MjhExZmH(HtX1ZW!|T5&gB;I$xg z?9#-ag%0RM5Bf$zP6iL)?4`<@N4C@GjaJ&R8}$E(Ab#;l`70fdt})O>!GfW>`Z6mi zc9B?Cg(;={tDO>>zTO}G$i`a`&tE3o+t*00yghOR914RA+XTY&4i~fHcuO-@3xLHw z2x{{(E%Il@JB`ZdM8|Gj&AMd_9^K#3EvtI(?6zS{R`)mIe1PjqRG!h`#eWhSek4>3 z3Pgc1Kj~g_W%#kVkXk%Cc)GIi<>6Cay|{k!>Ej)_P;FE9cUGS_@yG3iZDe7Xbn9G` z(Ec3@8oE&U*>&ZpBST0DRA7QC{%tG{7g<=gdw+G)cdM}T^9_StYrlznvjn~oC!Afm z)Z|{HfKZ81TklFe7wBuYfcril_K2_5jJDcvp#piAaEhQtD5sg6zV)UvnrUc zU8=sD^WWHGV&@YwMsV>r+K+#(bkIc)wLw1-v+%`GaB}UB%i#h314f3hAES%%i9hL% zk5Tj^vQeZ{S3%iOytfwpSgBz;v%t4;&+j%_F1fQBT&G&kw@u29TaQPV<(LBxr+u7w2Kbu`VsGhW5u!qp??*RB&X7PS!c0g7E>`N-}T z51+1iO7BXt#zegSY%IQeO;qymC5@?|KHMr3T#O%BJ+>X#hd=!!Zi=p!*KHH?Ts+#O z!nimf7OD`ir9T;P!b$Y|i%{MuLu@)|HOvEJfj<8}*t;HT`fIYx~t$U=cM ztd%Jo)f$uprR<9x&tKHY^EOS-LEUA zn{-oYLE29*2&?DUKNWoWkd*fa0Q0V(JM1-UDbP%9tI67G*9E<-d8sn#=ejJLDoPEC z+??n^63p=Ql)|Mik6?Jd5KP~H$jOnU8rVzBBRsgbR(z#oIzVT+V6cb66<(&r2XSvdsWJ~7oMDM&f0Fm%+ua_xC*pIb(5@06ooaHB zJvF)%5}k20PYr2HCKo$WC|rq~RoeeMn?3u3-OdsMJdwr*8KBD1lS1a@ zH*&?Jc4vD&!5tR^$$|fSD%~ir#P~h_U3Kz=ehr+zPy~GpYBU#2fX*fd!|~#OIEKT# zBUFuEd`S!44L=W^ym2)^g&8!XGgzud)*3u;4Rs6(!qjs8NQ<#!oCqVsy~$co8(lY` zasEdcJ@z2gx6ByGuJhL!w~pV#!gn5b}Qo2>zg#vo<-GHsYS7Jr}`$1S*vJ=QC?0F$Ge3Ds0}3{ z9{C<<=y_&~MqP3h<9cXQGOh~zW;79$M$Qx`YXr`0Zq+Um0A$Za9G<~UwT0H0)MOg) zsDV81s~A6WO4HW%xc61bUrsQV-uOR+8&#GZ{H90-so&k*6E8Cc(va`-er*0bl-qS- zM7?>f)ovRO&FVMrvFanMoosqr#6-NUOi8)*sMWIW(l8&I#cuh{s;|Ljna0b;D&GoR z+7_IAW0fP(&9@h2C2T7S%U(`sdGr@WxcMQm1eN^mk;2i=n%g(bp*kw>)ycPf_#C|+ z&7AZw880E9_)u*U4joVt9=A>~NHNEbA2szl+b&xs#GZ|Nh zfW}X1H4wXJu%=0qA7c;P@&ykj{kuQX3yY)7Kd{D{Qab+g@?+CD=w0j7tbsV-C`ojR zY8RTje(w+YLK2iiKRN|29N)K3B%&*Z8cyshsYrzmaqg12MN3gqfi-@)G_a%Pm}_?~ zpVBR!(=!&m6tz`^&Gz!BBzJ{1oDHuLUNZS`(~}eOO72<>!4C zBB3>AC9?z<0k0;_IBxl(4J^S7E28mWN59{dH}Gl z<7$BdTB7&dGlsEvsgXZEfagC$HFWz9S=X(mY3;===wHxs6(nZM?KhJ#)4#BOqgF?n z1@)s_qI)s@ed%vz=zt)ls9huMG1nd0D64*8on18y{wgtl{l~BdW~w6b`5d9sH=4PK zI)_}Czn7U1Ge^X~oqb;C8g9sW7yFF#p4kFe z&GFVU+n3JaK}2c4$i{uFFp_SO7OH5!yg+`{?P`en#gxf2@4gr8YJ|#|i7n}oJp2#V w3oBb1AG4D|R37*CkP3600P7 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 delta 8161 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png index b23e716ab470b0a83c184a3277dc67e33db1108f..828cdce7cf57e315a55d25f3880b1230c10c21f4 100644 GIT binary patch delta 6878 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-cairo-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-cairo-reference.png index b23e716ab470b0a83c184a3277dc67e33db1108f..828cdce7cf57e315a55d25f3880b1230c10c21f4 100644 GIT binary patch delta 6878 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png index b23e716ab470b0a83c184a3277dc67e33db1108f..828cdce7cf57e315a55d25f3880b1230c10c21f4 100644 GIT binary patch delta 6878 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 diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-cairo-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-cairo-reference.png index b23e716ab470b0a83c184a3277dc67e33db1108f..828cdce7cf57e315a55d25f3880b1230c10c21f4 100644 GIT binary patch delta 6878 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 From c0fcf480193a935467ef385add1cf450ee7b7345 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 4 Feb 2015 17:46:18 -0600 Subject: [PATCH 77/91] Fixed issues with SSE compare when the threshold is greater then zero. Added several new SSE methods for unsigned integers. --- include/mapnik/sse.hpp | 116 +++++++++++++++++++++++++++++ src/image_util.cpp | 11 +-- tests/python_tests/compare_test.py | 7 ++ 3 files changed, 127 insertions(+), 7 deletions(-) diff --git a/include/mapnik/sse.hpp b/include/mapnik/sse.hpp index ddf877812..d68684cd2 100644 --- a/include/mapnik/sse.hpp +++ b/include/mapnik/sse.hpp @@ -37,4 +37,120 @@ typedef union uint8_t u8[16]; } m128_int; +static inline __m128i +_mm_cmple_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x <= y: + return _mm_cmpeq_epi16(_mm_subs_epu16(x, y), _mm_setzero_si128()); +} + +static inline __m128i +_mm_cmple_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x <= y: + return _mm_cmpeq_epi8(_mm_min_epu8(x, y), x); +} + +static inline __m128i +_mm_cmpgt_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x > y: + return _mm_andnot_si128(_mm_cmpeq_epi16(x, y), _mm_cmple_epu16(y, x)); +} + +static inline __m128i +_mm_cmpgt_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x > y: + return _mm_andnot_si128( + _mm_cmpeq_epi8(x, y), + _mm_cmpeq_epi8(_mm_max_epu8(x, y), x) + ); +} + +static inline __m128i +_mm_cmplt_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x < y: + return _mm_cmpgt_epu16(y, x); +} + +static inline __m128i +_mm_cmplt_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x < y: + return _mm_cmpgt_epu8(y, x); +} + +static inline __m128i +_mm_cmpge_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x >= y: + return _mm_cmple_epu16(y, x); +} + +static inline __m128i +_mm_cmpge_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x >= y: + return _mm_cmple_epu8(y, x); +} + +// Its not often that you want to use this! +static inline __m128i +_mm_not_si128 (__m128i x) +{ + // Returns ~x, the bitwise complement of x: + return _mm_xor_si128(x, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())); +} + +static inline __m128i +_mm_absdiff_epu16 (__m128i x, __m128i y) +{ + // Calculate absolute difference: abs(x - y): + return _mm_or_si128(_mm_subs_epu16(x, y), _mm_subs_epu16(y, x)); +} + +static inline __m128i +_mm_absdiff_epu8 (__m128i x, __m128i y) +{ + // Calculate absolute difference: abs(x - y): + return _mm_or_si128(_mm_subs_epu8(x, y), _mm_subs_epu8(y, x)); +} + +static inline __m128i +_mm_div255_epu16 (__m128i x) +{ + // Divide 8 16-bit uints by 255: + // x := ((x + 1) + (x >> 8)) >> 8: + return _mm_srli_epi16(_mm_adds_epu16( + _mm_adds_epu16(x, _mm_set1_epi16(1)), + _mm_srli_epi16(x, 8)), 8); +} + +static __m128i +_mm_scale_epu8 (__m128i x, __m128i y) +{ + // Returns an "alpha blend" of x scaled by y/255; + // x := x * (y / 255) + // Reorder: x := (x * y) / 255 + + // Unpack x and y into 16-bit uints: + __m128i xlo = _mm_unpacklo_epi8(x, _mm_setzero_si128()); + __m128i ylo = _mm_unpacklo_epi8(y, _mm_setzero_si128()); + __m128i xhi = _mm_unpackhi_epi8(x, _mm_setzero_si128()); + __m128i yhi = _mm_unpackhi_epi8(y, _mm_setzero_si128()); + + // Multiply x with y, keeping the low 16 bits: + xlo = _mm_mullo_epi16(xlo, ylo); + xhi = _mm_mullo_epi16(xhi, yhi); + + // Divide by 255: + xlo = _mm_div255_epu16(xlo); + xhi = _mm_div255_epu16(xhi); + + // Repack the 16-bit uints to clamped 8-bit values: + return _mm_packus_epi16(xlo, xhi); +} + #endif // MAPNIK_SSE_HPP diff --git a/src/image_util.cpp b/src/image_util.cpp index 362323555..816db824f 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -2340,13 +2340,10 @@ MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 co __m128i rgba2 = _mm_loadu_si128((__m128i*)(row_from2 + x)); rgba = _mm_and_si128(rgba, mask); rgba2 = _mm_and_si128(rgba2, mask); - __m128i gt_comp = _mm_cmpgt_epi8(rgba, rgba2); - __m128i abs_1 = _mm_and_si128(gt_comp, _mm_sub_epi8(rgba, rgba2)); - __m128i abs_2 = _mm_andnot_si128(gt_comp, _mm_sub_epi8(rgba2, rgba)); - __m128i abs = _mm_or_si128(abs_1, abs_2); - __m128i compare = _mm_or_si128(_mm_cmplt_epi8(abs, m_thres), _mm_cmpeq_epi8(abs, m_thres)); - __m128i comp2 = _mm_cmpeq_epi32(compare, true_set); - sum = _mm_add_epi32(sum, _mm_andnot_si128(comp2, one)); + __m128i abs = _mm_absdiff_epu8(rgba, rgba2); + __m128i compare = _mm_cmple_epu8(abs, m_thres); + __m128i comp2 = _mm_cmpeq_epi32(compare, _mm_setzero_si128()); + sum = _mm_add_epi32(sum, _mm_and_si128(comp2, one)); } for (; x < im1.width(); ++x) { diff --git a/tests/python_tests/compare_test.py b/tests/python_tests/compare_test.py index 8b3049ac2..4972657be 100644 --- a/tests/python_tests/compare_test.py +++ b/tests/python_tests/compare_test.py @@ -31,6 +31,13 @@ def test_compare_rgba8(): eq_(im.compare(im3,2),1) eq_(im.compare(im3,3),0) +def test_compare_larger_image(): + im = mapnik.Image(5,5) + im.set_pixel(0,0, mapnik.Color(254, 254, 254, 254)) + im.set_pixel(4,4, mapnik.Color('white')) + im2 = mapnik.Image(5,5) + eq_(im2.compare(im,16), 2) + def test_compare_dimensions(): im = mapnik.Image(2,2) im2 = mapnik.Image(3,3) From 06ef081282ceb0091905b5a5ded14e8ac8b7e308 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 4 Feb 2015 18:26:18 -0600 Subject: [PATCH 78/91] Another set of fixes for the compare SSE code, added test where it was failing --- src/image_util.cpp | 4 ++-- tests/python_tests/compare_test.py | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/image_util.cpp b/src/image_util.cpp index 816db824f..364993fa8 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -2341,9 +2341,9 @@ MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 co rgba = _mm_and_si128(rgba, mask); rgba2 = _mm_and_si128(rgba2, mask); __m128i abs = _mm_absdiff_epu8(rgba, rgba2); - __m128i compare = _mm_cmple_epu8(abs, m_thres); + __m128i compare = _mm_cmpgt_epu8(abs, m_thres); __m128i comp2 = _mm_cmpeq_epi32(compare, _mm_setzero_si128()); - sum = _mm_add_epi32(sum, _mm_and_si128(comp2, one)); + sum = _mm_add_epi32(sum, _mm_andnot_si128(comp2, one)); } for (; x < im1.width(); ++x) { diff --git a/tests/python_tests/compare_test.py b/tests/python_tests/compare_test.py index 4972657be..f4b656309 100644 --- a/tests/python_tests/compare_test.py +++ b/tests/python_tests/compare_test.py @@ -10,6 +10,12 @@ def setup(): # from another directory we need to chdir() os.chdir(execution_path('.')) +def test_another_compare(): + im = mapnik.Image(5,5) + im2 = mapnik.Image(5,5) + im2.fill(mapnik.Color('rgba(255,255,255,0)')) + eq_(im.compare(im2,16), im.width() * im.height()) + def test_compare_rgba8(): im = mapnik.Image(5,5,mapnik.ImageType.rgba8) im.fill(mapnik.Color(0,0,0,0)) @@ -31,7 +37,7 @@ def test_compare_rgba8(): eq_(im.compare(im3,2),1) eq_(im.compare(im3,3),0) -def test_compare_larger_image(): +def test_compare_2_image(): im = mapnik.Image(5,5) im.set_pixel(0,0, mapnik.Color(254, 254, 254, 254)) im.set_pixel(4,4, mapnik.Color('white')) From 5966b129734a7f21282848a6f90081c2d532d453 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 4 Feb 2015 20:48:59 -0600 Subject: [PATCH 79/91] Small changes to hopefully fix compile issues on linux --- include/mapnik/grid/grid.hpp | 1 - include/mapnik/pixel_types.hpp | 3 +-- include/mapnik/value_types.hpp | 6 ++++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 053f5ef85..0cb948262 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -35,7 +35,6 @@ #include // stl -#include #include #include #include diff --git a/include/mapnik/pixel_types.hpp b/include/mapnik/pixel_types.hpp index 5990a3b20..aef5dca8c 100644 --- a/include/mapnik/pixel_types.hpp +++ b/include/mapnik/pixel_types.hpp @@ -23,8 +23,7 @@ #ifndef MAPNIK_PIXEL_TYPES_HPP #define MAPNIK_PIXEL_TYPES_HPP -// std -#include +#include struct rgba8_t { using type = std::uint32_t; }; struct gray8_t { using type = std::uint8_t; }; diff --git a/include/mapnik/value_types.hpp b/include/mapnik/value_types.hpp index fd5feaee5..fdaa99ee4 100644 --- a/include/mapnik/value_types.hpp +++ b/include/mapnik/value_types.hpp @@ -43,10 +43,12 @@ namespace mapnik { #ifdef BIGINT //using value_integer = boost::long_long_type; -using value_integer = long long; +//using value_integer = long long; +using value_integer = std::int64_t; using value_integer_pixel = gray64s_t; #else -using value_integer = int; +//using value_integer = int; +using value_integer = std::int32_t; using value_integer_pixel = gray32s_t; #endif From 04d51d36967ab25f4c885b1e533181fd9ae8596d Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 4 Feb 2015 21:19:59 -0600 Subject: [PATCH 80/91] Another small change hopefully to fix linux build isssues. --- include/mapnik/xml_attribute_cast.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/mapnik/xml_attribute_cast.hpp b/include/mapnik/xml_attribute_cast.hpp index 6d2e4ae25..1a3cb98f2 100644 --- a/include/mapnik/xml_attribute_cast.hpp +++ b/include/mapnik/xml_attribute_cast.hpp @@ -25,6 +25,7 @@ //mapnik #include +#include #include #include #include @@ -87,14 +88,14 @@ struct do_xml_attribute_cast #ifdef BIGINT // specialization for long long template <> -struct do_xml_attribute_cast +struct do_xml_attribute_cast { - static inline boost::optional xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source) + static inline boost::optional xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source) { int result; if (mapnik::util::string2int(source, result)) - return boost::optional(result); - return boost::optional(); + return boost::optional(result); + return boost::optional(); } }; From 9875335fb8b2fe0f8759ab901d02b8db73b65841 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Fri, 6 Feb 2015 15:27:19 -0600 Subject: [PATCH 81/91] Renamed image_cast to image_copy --- bindings/python/mapnik_image.cpp | 8 +- .../mapnik/{image_cast.hpp => image_copy.hpp} | 32 +++--- src/build.py | 2 +- src/{image_cast.cpp => image_copy.cpp} | 104 +++++++++--------- 4 files changed, 73 insertions(+), 73 deletions(-) rename include/mapnik/{image_cast.hpp => image_copy.hpp} (65%) rename src/{image_cast.cpp => image_copy.cpp} (71%) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 3dfbc0f27..68c544992 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include @@ -137,9 +137,9 @@ void fill_double(mapnik::image_any & im, double val) mapnik::fill(im, val); } -std::shared_ptr cast(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling) +std::shared_ptr copy(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling) { - return std::make_shared(std::move(mapnik::image_cast(im, type, offset, scaling))); + return std::make_shared(std::move(mapnik::image_copy(im, type, offset, scaling))); } unsigned compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha) @@ -427,7 +427,7 @@ void export_image() arg("threshold")=0.0, arg("alpha")=true )) - .def("cast",&cast, + .def("copy",©, ( arg("self"), arg("type"), arg("offset")=0.0, diff --git a/include/mapnik/image_cast.hpp b/include/mapnik/image_copy.hpp similarity index 65% rename from include/mapnik/image_cast.hpp rename to include/mapnik/image_copy.hpp index 320c41788..62e2ab215 100644 --- a/include/mapnik/image_cast.hpp +++ b/include/mapnik/image_copy.hpp @@ -20,8 +20,8 @@ * *****************************************************************************/ -#ifndef MAPNIK_IMAGE_CAST_HPP -#define MAPNIK_IMAGE_CAST_HPP +#ifndef MAPNIK_IMAGE_COPY_HPP +#define MAPNIK_IMAGE_COPY_HPP #include #include @@ -30,43 +30,43 @@ namespace mapnik { template -MAPNIK_DECL T image_cast(image_any const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_any const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_rgba8 const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_rgba8 const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray8 const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray8 const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray8s const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray8s const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray16 const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray16 const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray16s const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray16s const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray32 const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray32 const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray32s const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray32s const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray32f const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray32f const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray64 const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray64 const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray64s const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray64s const&, double offset = 0.0, double scaling = 1.0); template -MAPNIK_DECL T image_cast(image_gray64f const&, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL T image_copy(image_gray64f const&, double offset = 0.0, double scaling = 1.0); -MAPNIK_DECL image_any image_cast(image_any const&, image_dtype type, double offset = 0.0, double scaling = 1.0); +MAPNIK_DECL image_any image_copy(image_any const&, image_dtype type, double offset = 0.0, double scaling = 1.0); } // end mapnik ns -#endif // MAPNIK_IMAGE_CAST_HPP +#endif // MAPNIK_IMAGE_COPY_HPP diff --git a/src/build.py b/src/build.py index 18853aeb7..fca14e4b2 100644 --- a/src/build.py +++ b/src/build.py @@ -152,7 +152,7 @@ source = Split( miniz_png.cpp color.cpp conversions.cpp - image_cast.cpp + image_copy.cpp image_compositing.cpp image_scaling.cpp box2d.cpp diff --git a/src/image_cast.cpp b/src/image_copy.cpp similarity index 71% rename from src/image_cast.cpp rename to src/image_copy.cpp index a26323d00..e686576db 100644 --- a/src/image_cast.cpp +++ b/src/image_copy.cpp @@ -21,7 +21,7 @@ *****************************************************************************/ // mapnik -#include +#include #include #include @@ -39,7 +39,7 @@ namespace detail { template -struct visitor_image_cast +struct visitor_image_copy { using dst_type = typename T0::pixel_type; @@ -80,11 +80,11 @@ struct visitor_image_cast }; template -struct visitor_image_cast_so +struct visitor_image_copy_so { using dst_type = typename T0::pixel_type; - visitor_image_cast_so(double offset, double scaling) + visitor_image_copy_so(double offset, double scaling) : offset_(offset), scaling_(scaling) {} T0 operator() (image_null const&) @@ -135,209 +135,209 @@ struct visitor_image_cast_so } // end detail ns template -MAPNIK_DECL T image_cast(image_any const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_any const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - return util::apply_visitor(detail::visitor_image_cast(), data); + return util::apply_visitor(detail::visitor_image_copy(), data); } else { - return util::apply_visitor(detail::visitor_image_cast_so(offset, scaling), data); + return util::apply_visitor(detail::visitor_image_copy_so(offset, scaling), data); } } template -MAPNIK_DECL T image_cast(image_rgba8 const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_rgba8 const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray8 const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray8 const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray8s const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray8s const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray16 const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray16 const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray16s const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray16s const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray32 const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray32 const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray32s const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray32s const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray32f const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray32f const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray64 const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray64 const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray64s const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray64s const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } template -MAPNIK_DECL T image_cast(image_gray64f const& data, double offset, double scaling) +MAPNIK_DECL T image_copy(image_gray64f const& data, double offset, double scaling) { if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) { - detail::visitor_image_cast visit; + detail::visitor_image_copy visit; return visit(data); } else { - detail::visitor_image_cast_so visit(offset, scaling); + detail::visitor_image_copy_so visit(offset, scaling); return visit(data); } } -MAPNIK_DECL image_any image_cast(image_any const& data, image_dtype type, double offset, double scaling) +MAPNIK_DECL image_any image_copy(image_any const& data, image_dtype type, double offset, double scaling) { switch (type) { case image_dtype_rgba8: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray8: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray8s: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray16: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray16s: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray32: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray32s: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray32f: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray64: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray64s: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_gray64f: - return image_any(std::move(image_cast(data, offset, scaling))); + return image_any(std::move(image_copy(data, offset, scaling))); case image_dtype_null: throw std::runtime_error("Can not cast a null image"); } From d31bf5b17169f4c3b5d8461e8788a051092f310f Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 9 Feb 2015 13:46:48 -0800 Subject: [PATCH 82/91] Updated tests from cast to copy --- tests/python_tests/{cast_test.py => copy_test.py} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename tests/python_tests/{cast_test.py => copy_test.py} (88%) diff --git a/tests/python_tests/cast_test.py b/tests/python_tests/copy_test.py similarity index 88% rename from tests/python_tests/cast_test.py rename to tests/python_tests/copy_test.py index b469859ab..d3cf9b15c 100644 --- a/tests/python_tests/cast_test.py +++ b/tests/python_tests/copy_test.py @@ -16,13 +16,13 @@ def test_image_16_8_simple(): im.set_pixel(0,1, 999) im.set_pixel(1,0, 5) im.set_pixel(1,1, 2) - im2 = im.cast(mapnik.ImageType.gray8) + im2 = im.copy(mapnik.ImageType.gray8) eq_(im2.get_pixel(0,0), 255) eq_(im2.get_pixel(0,1), 255) eq_(im2.get_pixel(1,0), 5) eq_(im2.get_pixel(1,1), 2) # Cast back! - im = im2.cast(mapnik.ImageType.gray16) + im = im2.copy(mapnik.ImageType.gray16) eq_(im.get_pixel(0,0), 255) eq_(im.get_pixel(0,1), 255) eq_(im.get_pixel(1,0), 5) @@ -34,7 +34,7 @@ def test_image_32f_8_simple(): im.set_pixel(0,1, -23.4) im.set_pixel(1,0, 120.6) im.set_pixel(1,1, 360.2) - im2 = im.cast(mapnik.ImageType.gray8) + im2 = im.copy(mapnik.ImageType.gray8) eq_(im2.get_pixel(0,0), 120) eq_(im2.get_pixel(0,1), 0) eq_(im2.get_pixel(1,0), 120) # Notice this is truncated! @@ -57,13 +57,13 @@ def test_image_16_8_scale_and_offset(): im.set_pixel(1,1, 615) offset = 255 scaling = 3 - im2 = im.cast(mapnik.ImageType.gray8, offset, scaling) + im2 = im.copy(mapnik.ImageType.gray8, offset, scaling) eq_(im2.get_pixel(0,0), 0) eq_(im2.get_pixel(0,1), 1) eq_(im2.get_pixel(1,0), 255) eq_(im2.get_pixel(1,1), 120) # pixels will be a little off due to offsets in reverting! - im3 = im2.cast(mapnik.ImageType.gray16) + im3 = im2.copy(mapnik.ImageType.gray16) eq_(im3.get_pixel(0,0), 255) # Rounding error with ints eq_(im3.get_pixel(0,1), 258) # same eq_(im3.get_pixel(1,0), 1020) # The other one was way out of range for our scale/offset @@ -77,12 +77,12 @@ def test_image_16_32f_scale_and_offset(): im.set_pixel(1,1, 615) offset = 255 scaling = 3.2 - im2 = im.cast(mapnik.ImageType.gray32f, offset, scaling) + im2 = im.copy(mapnik.ImageType.gray32f, offset, scaling) eq_(im2.get_pixel(0,0), 0.3125) eq_(im2.get_pixel(0,1), 0.9375) eq_(im2.get_pixel(1,0), -79.6875) eq_(im2.get_pixel(1,1), 112.5) - im3 = im2.cast(mapnik.ImageType.gray16) + im3 = im2.copy(mapnik.ImageType.gray16) eq_(im3.get_pixel(0,0), 256) eq_(im3.get_pixel(0,1), 258) eq_(im3.get_pixel(1,0), 0) From 0cd9c1fc34eabb05bab006f71d4204beb164bd08 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 16 Feb 2015 14:23:55 -0600 Subject: [PATCH 83/91] Updated image_any building switch statement to support all the correct types, added tests for all the new data formats with get and set in python. --- bindings/python/mapnik_image.cpp | 14 +++--- include/mapnik/image_any.hpp | 14 ++++++ src/image_util.cpp | 15 +++++- tests/python_tests/image_test.py | 81 ++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 8 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 68c544992..c5f9a0b69 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -156,13 +156,6 @@ struct get_pixel_visitor { throw std::runtime_error("Can not return a null image from a pixel (shouldn't have reached here)"); } - - template - PyObject* operator() (T const& im) - { - using pixel_type = typename T::pixel_type; - return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); - } PyObject* operator() (mapnik::image_gray32f const& im) { @@ -174,6 +167,13 @@ struct get_pixel_visitor return PyFloat_FromDouble(mapnik::get_pixel(im, x_, y_)); } + template + PyObject* operator() (T const& im) + { + using pixel_type = typename T::pixel_type; + return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); + } + private: unsigned x_; unsigned y_; diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp index 2745886ce..55e75d1f2 100644 --- a/include/mapnik/image_any.hpp +++ b/include/mapnik/image_any.hpp @@ -285,10 +285,24 @@ inline image_any create_image_any(int width, { case image_dtype_gray8: return image_any(std::move(image_gray8(width, height, initialize, premultiplied, painted))); + case image_dtype_gray8s: + return image_any(std::move(image_gray8s(width, height, initialize, premultiplied, painted))); case image_dtype_gray16: return image_any(std::move(image_gray16(width, height, initialize, premultiplied, painted))); + case image_dtype_gray16s: + return image_any(std::move(image_gray16s(width, height, initialize, premultiplied, painted))); + case image_dtype_gray32: + return image_any(std::move(image_gray32(width, height, initialize, premultiplied, painted))); + case image_dtype_gray32s: + return image_any(std::move(image_gray32s(width, height, initialize, premultiplied, painted))); case image_dtype_gray32f: return image_any(std::move(image_gray32f(width, height, initialize, premultiplied, painted))); + case image_dtype_gray64: + return image_any(std::move(image_gray64(width, height, initialize, premultiplied, painted))); + case image_dtype_gray64s: + return image_any(std::move(image_gray64s(width, height, initialize, premultiplied, painted))); + case image_dtype_gray64f: + return image_any(std::move(image_gray64f(width, height, initialize, premultiplied, painted))); case image_dtype_null: return image_any(std::move(image_null())); case image_dtype_rgba8: diff --git a/src/image_util.cpp b/src/image_util.cpp index 364993fa8..bfe1246e6 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -1676,7 +1676,20 @@ struct visitor_get_pixel { if (check_bounds(data, x_, y_)) { - return static_cast(data(x_, y_)); + T1 val; + try + { + val = numeric_cast(data(x_,y_)); + } + catch(negative_overflow&) + { + val = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + val = std::numeric_limits::max(); + } + return val; } else { diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index d7ee92e61..f468c8b09 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -125,6 +125,78 @@ def test_set_and_get_pixel(): eq_(c0_pre.b, c1.b) eq_(c0_pre.a, c1.a) +def test_pixel_gray8(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray8s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_gray16(): + im = mapnik.Image(4,4,mapnik.ImageType.gray16) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray16s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray16s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_gray32(): + im = mapnik.Image(4,4,mapnik.ImageType.gray32) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray32s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray32s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_gray64(): + im = mapnik.Image(4,4,mapnik.ImageType.gray64) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray64s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray64s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + def test_pixel_floats(): im = mapnik.Image(4,4,mapnik.ImageType.gray32f) val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1] @@ -134,6 +206,15 @@ def test_pixel_floats(): im.set_pixel(0,0, -v) assert_almost_equal(im.get_pixel(0,0), -v) +def test_pixel_doubles(): + im = mapnik.Image(4,4,mapnik.ImageType.gray64f) + val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1] + for v in val_list: + im.set_pixel(0,0, v) + assert_almost_equal(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + assert_almost_equal(im.get_pixel(0,0), -v) + def test_pixel_overflow(): im = mapnik.Image(4,4,mapnik.ImageType.gray8) im.set_pixel(0,0,256) From 6418a129c1e94c7e2019cd8b344e709370df0241 Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Mon, 16 Feb 2015 15:56:29 -0600 Subject: [PATCH 84/91] Removed graphics.hpp from benchmark --- benchmark/compare_images.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/benchmark/compare_images.hpp b/benchmark/compare_images.hpp index 2f1f124c4..0f0c0f14d 100644 --- a/benchmark/compare_images.hpp +++ b/benchmark/compare_images.hpp @@ -1,7 +1,6 @@ #ifndef __MAPNIK_COMPARE_IMAGES_HPP__ #define __MAPNIK_COMPARE_IMAGES_HPP__ -#include #include #include #include From 842e4bebe61bf156c9b2c2dae7e473d708b7cfc4 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 16 Feb 2015 18:48:14 -0800 Subject: [PATCH 85/91] start fixing windows compile - refs #2708 --- include/mapnik/image_util.hpp | 29 ----------------------------- src/image_util.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index b2b723e8b..e59b8f086 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -409,35 +409,6 @@ void add_border(T & image) } } -#ifdef _MSC_VER - -template MAPNIK_DECL void save_to_stream( - image_rgba8 const& image, - std::ostream & stream, - std::string const& type, - rgba_palette const& palette -); - -template MAPNIK_DECL void save_to_stream( - image_rgba8 const& image, - std::ostream & stream, - std::string const& type -); - -template MAPNIK_DECL void save_to_stream ( - image_view_rgba8 const& image, - std::ostream & stream, - std::string const& type, - rgba_palette const& palette -); - -template MAPNIK_DECL void save_to_stream ( - image_view_rgba8 const& image, - std::ostream & stream, - std::string const& type -); -#endif - } #endif // MAPNIK_IMAGE_UTIL_HPP diff --git a/src/image_util.cpp b/src/image_util.cpp index bfe1246e6..0a861f128 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -613,7 +613,7 @@ struct visitor_set_alpha void operator() (image_rgba8 & data) { - using pixel_type = typename image_rgba8::pixel_type; + using pixel_type = image_rgba8::pixel_type; for (unsigned int y = 0; y < data.height(); ++y) { pixel_type* row_to = data.getRow(y); @@ -689,7 +689,7 @@ struct visitor_set_grayscale_to_alpha { void operator() (image_rgba8 & data) { - using pixel_type = typename image_rgba8::pixel_type; + using pixel_type = image_rgba8::pixel_type; for (unsigned int y = 0; y < data.height(); ++y) { pixel_type* row_from = data.getRow(y); @@ -722,7 +722,7 @@ struct visitor_set_grayscale_to_alpha_c void operator() (image_rgba8 & data) { - using pixel_type = typename image_rgba8::pixel_type; + using pixel_type = image_rgba8::pixel_type; for (unsigned int y = 0; y < data.height(); ++y) { pixel_type* row_from = data.getRow(y); @@ -834,7 +834,7 @@ struct visitor_set_color_to_alpha void operator() (image_rgba8 & data) { - using pixel_type = typename image_rgba8::pixel_type; + using pixel_type = image_rgba8::pixel_type; for (unsigned y = 0; y < data.height(); ++y) { pixel_type* row_from = data.getRow(y); @@ -942,7 +942,7 @@ struct visitor_fill void operator() (image_rgba8 & data) { - using pixel_type = typename image_rgba8::pixel_type; + using pixel_type = image_rgba8::pixel_type; pixel_type val = static_cast(val_.rgba()); data.set(val); data.set_premultiplied(val_.get_premultiplied()); @@ -1198,7 +1198,7 @@ struct visitor_set_rectangle void operator()(image_rgba8 & dst) { - using pixel_type = typename image_rgba8::pixel_type; + using pixel_type = image_rgba8::pixel_type; image_rgba8 src = util::get(src_); box2d ext0(0,0,dst.width(),dst.height()); box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); From 817489e97a1d1d79306f1f1d631a0cd803b5557c Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 16 Feb 2015 19:05:41 -0800 Subject: [PATCH 86/91] functions fully defined in hpp do not need MAPNIK_DECL - refs #2708 --- include/mapnik/image_util.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index e59b8f086..13f30204e 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -202,7 +202,7 @@ MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); // CHECK BOUNDS template -MAPNIK_DECL bool check_bounds (T const& data, std::size_t x, std::size_t y) +inline bool check_bounds (T const& data, std::size_t x, std::size_t y) { return (x < static_cast(data.width()) && y < static_cast(data.height())); } From 390fbaac92c6b41cdad9b400bd043b7c7f92b21d Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Wed, 18 Feb 2015 22:58:33 -0600 Subject: [PATCH 87/91] BOOM SHAKALAKA: This update is in Ref #2649. It provides an update to markers and their processing such that: * All shared_ptrs are no longer required around markers * Markers are now const --- include/mapnik/agg_renderer.hpp | 2 +- include/mapnik/cairo/cairo_context.hpp | 6 +- include/mapnik/cairo/cairo_renderer.hpp | 2 +- include/mapnik/grid/grid_render_marker.hpp | 2 +- include/mapnik/grid/grid_renderer.hpp | 2 +- include/mapnik/marker.hpp | 192 ++++++--- include/mapnik/marker_cache.hpp | 10 +- include/mapnik/marker_helpers.hpp | 4 +- .../process_group_symbolizer.hpp | 24 +- .../process_markers_symbolizer.hpp | 392 +++++++++++------- .../process_point_symbolizer.hpp | 10 +- .../mapnik/renderer_common/render_pattern.hpp | 11 +- include/mapnik/svg/output/svg_renderer.hpp | 2 +- include/mapnik/text/glyph_positions.hpp | 6 +- src/agg/agg_renderer.cpp | 257 ++++++++---- src/agg/process_group_symbolizer.cpp | 17 +- src/agg/process_line_pattern_symbolizer.cpp | 277 +++++++++---- src/agg/process_markers_symbolizer.cpp | 4 +- .../process_polygon_pattern_symbolizer.cpp | 385 +++++++++++------ src/agg/process_shield_symbolizer.cpp | 2 +- src/cairo/cairo_context.cpp | 65 +-- src/cairo/cairo_renderer.cpp | 164 +++++--- src/cairo/process_group_symbolizer.cpp | 2 +- src/cairo/process_line_pattern_symbolizer.cpp | 99 +++-- src/cairo/process_markers_symbolizer.cpp | 2 +- .../process_polygon_pattern_symbolizer.cpp | 68 +-- src/cairo/process_text_symbolizer.cpp | 2 +- src/grid/grid_renderer.cpp | 84 +++- src/grid/process_group_symbolizer.cpp | 17 +- src/grid/process_line_pattern_symbolizer.cpp | 11 +- src/grid/process_markers_symbolizer.cpp | 4 +- .../process_polygon_pattern_symbolizer.cpp | 9 +- src/grid/process_shield_symbolizer.cpp | 2 +- src/marker_cache.cpp | 91 ++-- .../process_group_symbolizer.cpp | 140 +------ src/renderer_common/render_pattern.cpp | 131 +----- src/text/symbolizer_helpers.cpp | 10 +- 37 files changed, 1360 insertions(+), 1148 deletions(-) diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 9052b7600..90ca07e06 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -51,7 +51,7 @@ namespace mapnik { class feature_type_style; class label_collision_detector4; class layer; - class marker; + struct marker; class proj_transform; struct rasterizer; } diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index a5826bdc9..555d5c187 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -308,10 +308,8 @@ public: void paint(); void set_pattern(cairo_pattern const& pattern); void set_gradient(cairo_gradient const& pattern, box2d const& bbox); - void add_image(double x, double y, image_any & data, double opacity); - void add_image(agg::trans_affine const& tr, image_any & data, double opacity); - void add_image(double x, double y, image_rgba8 & data, double opacity = 1.0); - void add_image(agg::trans_affine const& tr, image_rgba8 & data, double opacity = 1.0); + void add_image(double x, double y, image_rgba8 const& data, double opacity = 1.0); + void add_image(agg::trans_affine const& tr, image_rgba8 const& data, double opacity = 1.0); void set_font_face(cairo_face_manager & manager, face_ptr face); void set_font_matrix(cairo_matrix_t const& matrix); void set_matrix(cairo_matrix_t const& matrix); diff --git a/include/mapnik/cairo/cairo_renderer.hpp b/include/mapnik/cairo/cairo_renderer.hpp index 89bb8058f..0914d626a 100644 --- a/include/mapnik/cairo/cairo_renderer.hpp +++ b/include/mapnik/cairo/cairo_renderer.hpp @@ -47,7 +47,7 @@ class feature_impl; class feature_type_style; class label_collision_detector4; class layer; -class marker; +struct marker; class proj_transform; class request; struct pixel_position; diff --git a/include/mapnik/grid/grid_render_marker.hpp b/include/mapnik/grid/grid_render_marker.hpp index f8b0258b8..79c5ec097 100644 --- a/include/mapnik/grid/grid_render_marker.hpp +++ b/include/mapnik/grid/grid_render_marker.hpp @@ -41,7 +41,7 @@ namespace mapnik { template void render_raster_marker(RendererType ren, RasterizerType & ras, - image_rgba8 & src, + image_rgba8 const& src, mapnik::feature_impl const& feature, agg::trans_affine const& marker_tr, double opacity) diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp index 500c95059..2db770984 100644 --- a/include/mapnik/grid/grid_renderer.hpp +++ b/include/mapnik/grid/grid_renderer.hpp @@ -49,7 +49,7 @@ namespace mapnik { class feature_type_style; class label_collision_detector4; class layer; - class marker; + struct marker; class proj_transform; struct grid_rasterizer; class request; diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index ea03e9607..9b57b014a 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -30,6 +30,7 @@ #include #include #include +#include // agg #include "agg_array.h" @@ -47,97 +48,168 @@ using attr_storage = agg::pod_bvector; using svg_storage_type = mapnik::svg::svg_storage; using svg_path_ptr = std::shared_ptr; using image_ptr = std::shared_ptr; -/** - * A class to hold either vector or bitmap marker data. This allows these to be treated equally - * in the image caches and most of the render paths. - */ -class marker: private util::noncopyable + +struct marker_rgba8 { public: - marker() + marker_rgba8() + : bitmap_data_(4,4,true,true) { // create default OGC 4x4 black pixel - image_rgba8 image(4,4,true,true); - image.set(0xff000000); - bitmap_data_ = boost::optional(std::make_shared(std::move(image))); + bitmap_data_.set(0xff000000); } - marker(boost::optional const& data) + marker_rgba8(image_rgba8 const & data) : bitmap_data_(data) {} + + marker_rgba8(image_rgba8 && data) + : bitmap_data_(std::move(data)) {} - marker(boost::optional const& data) - : vector_data_(data) {} + marker_rgba8(marker_rgba8 const& rhs) + : bitmap_data_(rhs.bitmap_data_) {} - marker(marker const& rhs) - : bitmap_data_(rhs.bitmap_data_), - vector_data_(rhs.vector_data_) {} + marker_rgba8(marker_rgba8 && rhs) noexcept + : bitmap_data_(std::move(rhs.bitmap_data_)) {} box2d bounding_box() const { - if (is_vector()) - { - return (*vector_data_)->bounding_box(); - } - if (is_bitmap()) - { - double width = (*bitmap_data_)->width(); - double height = (*bitmap_data_)->height(); - return box2d(0, 0, width, height); - } - return box2d(); + double width = bitmap_data_.width(); + double height = bitmap_data_.height(); + return box2d(0, 0, width, height); } - inline double width() const + inline std::size_t width() const { - if (is_bitmap()) - { - return (*bitmap_data_)->width(); - } - else if (is_vector()) - { - return (*vector_data_)->bounding_box().width(); - } - return 0; - } - inline double height() const - { - if (is_bitmap()) - { - return (*bitmap_data_)->height(); - } - else if (is_vector()) - { - return (*vector_data_)->bounding_box().height(); - } - return 0; + return bitmap_data_.width(); } - inline bool is_bitmap() const + inline std::size_t height() const { - return !!bitmap_data_; + return bitmap_data_.height(); } - inline bool is_vector() const - { - return !!vector_data_; - } - - boost::optional get_bitmap_data() const + image_rgba8 const& get_data() const { return bitmap_data_; } - boost::optional get_vector_data() const +private: + image_rgba8 bitmap_data_; +}; + +struct marker_svg +{ +public: + marker_svg() { } + + marker_svg(mapnik::svg_path_ptr data) + : vector_data_(data) {} + + marker_svg(marker_svg const& rhs) + : vector_data_(rhs.vector_data_) {} + + marker_svg(marker_svg && rhs) noexcept + : vector_data_(rhs.vector_data_) {} + + box2d bounding_box() const + { + return vector_data_->bounding_box(); + } + + inline double width() const + { + return vector_data_->bounding_box().width(); + } + inline double height() const + { + return vector_data_->bounding_box().height(); + } + + mapnik::svg_path_ptr get_data() const { return vector_data_; } private: - boost::optional bitmap_data_; - boost::optional vector_data_; + mapnik::svg_path_ptr vector_data_; }; -} +struct marker_null +{ +public: + box2d bounding_box() const + { + return box2d(); + } + inline double width() const + { + return 0; + } + inline double height() const + { + return 0; + } +}; + +using marker_base = util::variant; +namespace detail { + +struct get_marker_bbox_visitor +{ + template + box2d operator()(T & data) const + { + return data.bounding_box(); + } +}; + +struct get_marker_width_visitor +{ + template + double operator()(T const& data) const + { + return static_cast(data.width()); + } +}; + +struct get_marker_height_visitor +{ + template + double operator()(T const& data) const + { + return static_cast(data.height()); + } +}; + +} // end detail ns + +struct marker : marker_base +{ + marker() = default; + + template + marker(T && data) noexcept + : marker_base(std::move(data)) {} + + double width() const + { + return util::apply_visitor(detail::get_marker_width_visitor(),*this); + } + + double height() const + { + return util::apply_visitor(detail::get_marker_height_visitor(),*this); + } + + box2d bounding_box() const + { + return util::apply_visitor(detail::get_marker_bbox_visitor(),*this); + } +}; + +} // end mapnik ns #endif // MAPNIK_MARKER_HPP diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 68cc79155..1d835d167 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -36,9 +36,7 @@ namespace mapnik { -class marker; - -using marker_ptr = std::shared_ptr; +struct marker; class MAPNIK_DECL marker_cache : public singleton , @@ -48,8 +46,8 @@ class MAPNIK_DECL marker_cache : private: marker_cache(); ~marker_cache(); - bool insert_marker(std::string const& key, marker_ptr path); - boost::unordered_map marker_cache_; + bool insert_marker(std::string const& key, marker & path); + boost::unordered_map marker_cache_; bool insert_svg(std::string const& name, std::string const& svg_string); boost::unordered_map svg_cache_; public: @@ -58,7 +56,7 @@ public: inline bool is_uri(std::string const& path) { return is_svg_uri(path) || is_image_uri(path); } bool is_svg_uri(std::string const& path); bool is_image_uri(std::string const& path); - boost::optional find(std::string const& key, bool update_cache = false); + marker const& find(std::string const& key, bool update_cache = false); void clear(); }; diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index a99b92327..1f03b117b 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -118,7 +118,7 @@ protected: template struct raster_markers_dispatch : util::noncopyable { - raster_markers_dispatch(image_any & src, + raster_markers_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -163,7 +163,7 @@ struct raster_markers_dispatch : util::noncopyable virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0; protected: - image_any & src_; + image_rgba8 const& src_; agg::trans_affine const& marker_trans_; symbolizer_base const& sym_; Detector & detector_; diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 44eb09450..da5900de9 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -130,13 +130,13 @@ struct vector_marker_render_thunk : util::noncopyable template struct raster_marker_render_thunk : util::noncopyable { - BufferType & src_; + BufferType const& src_; agg::trans_affine tr_; double opacity_; composite_mode_e comp_op_; bool snap_to_pixels_; - raster_marker_render_thunk(BufferType & src, + raster_marker_render_thunk(BufferType const& src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -151,16 +151,6 @@ struct raster_marker_render_thunk : util::noncopyable }; template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; -template struct raster_marker_render_thunk; using helper_ptr = std::unique_ptr; @@ -192,16 +182,6 @@ struct text_render_thunk : util::noncopyable using render_thunk = util::variant, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, - raster_marker_render_thunk, text_render_thunk>; using render_thunk_ptr = std::unique_ptr; using render_thunk_list = std::list; diff --git a/include/mapnik/renderer_common/process_markers_symbolizer.hpp b/include/mapnik/renderer_common/process_markers_symbolizer.hpp index 04ff0bbaa..996867efc 100644 --- a/include/mapnik/renderer_common/process_markers_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_markers_symbolizer.hpp @@ -32,6 +32,230 @@ namespace mapnik { +template +struct render_marker_symbolizer_visitor +{ + using vector_dispatch_type = VD; + using raster_dispatch_type = RD; + using buffer_type = typename std::tuple_element<0,ContextType>::type; + + render_marker_symbolizer_visitor(std::string const& filename, + markers_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans, + RendererType const& common, + box2d const& clip_box, + ContextType const& renderer_context) + : filename_(filename), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans), + common_(common), + clip_box_(clip_box), + renderer_context_(renderer_context) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& mark) + { + using namespace mapnik::svg; + bool clip = get(sym_, feature_, common_.vars_); + double offset = get(sym_, feature_, common_.vars_); + double simplify_tolerance = get(sym_, feature_, common_.vars_); + double smooth = get(sym_, feature_, common_.vars_); + + // https://github.com/mapnik/mapnik/issues/1316 + bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename_); + + agg::trans_affine geom_tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_); + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + + boost::optional const& stock_vector_marker = mark.get_data(); + + // special case for simple ellipse markers + // to allow for full control over rx/ry dimensions + if (filename_ == "shape://ellipse" + && (has_key(sym_,keys::width) || has_key(sym_,keys::height))) + { + svg_path_ptr marker_ellipse = std::make_shared(); + vertex_stl_adapter stl_storage(marker_ellipse->source()); + svg_path_adapter svg_path(stl_storage); + build_ellipse(sym_, feature_, common_.vars_, *marker_ellipse, svg_path); + svg_attribute_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym_, feature_, common_.vars_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + vector_dispatch_type rasterizer_dispatch(marker_ellipse, + svg_path, + result ? attributes : (*stock_vector_marker)->attributes(), + image_tr, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + snap_to_pixels, + renderer_context_); + + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(clip_box_, + rasterizer_dispatch, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + common_.vars_, + common_.scale_factor_); + if (clip && feature_.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature_.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + else if (type == geometry_type::types::LineString) + converter.template set(); + } + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature_, common_.vars_, converter, sym_); + } + else + { + box2d const& bbox = mark.bounding_box(); + setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature_, common_.vars_, sym_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); + svg_path_adapter svg_path(stl_storage); + svg_attribute_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym_, feature_, common_.vars_); + vector_dispatch_type rasterizer_dispatch(*stock_vector_marker, + svg_path, + result ? attributes : (*stock_vector_marker)->attributes(), + image_tr, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + snap_to_pixels, + renderer_context_); + + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(clip_box_, + rasterizer_dispatch, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + common_.vars_, + common_.scale_factor_); + if (clip && feature_.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature_.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + else if (type == geometry_type::types::LineString) + converter.template set(); + } + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature_, common_.vars_, converter, sym_); + } + } + + void operator() (marker_rgba8 const& mark) + { + using namespace mapnik::svg; + bool clip = get(sym_, feature_, common_.vars_); + double offset = get(sym_, feature_, common_.vars_); + double simplify_tolerance = get(sym_, feature_, common_.vars_); + double smooth = get(sym_, feature_, common_.vars_); + + agg::trans_affine geom_tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_); + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + + setup_transform_scaling(image_tr, mark.width(), mark.height(), feature_, common_.vars_, sym_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + box2d const& bbox = mark.bounding_box(); + mapnik::image_rgba8 const& marker = mark.get_data(); + // - clamp sizes to > 4 pixels of interactivity + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * image_tr; + raster_dispatch_type rasterizer_dispatch(marker, + marker_trans, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + renderer_context_); + + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(clip_box_, + rasterizer_dispatch, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + common_.vars_, + common_.scale_factor_); + + if (clip && feature_.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature_.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + else if (type == geometry_type::types::LineString) + converter.template set(); + } + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature_, common_.vars_, converter, sym_); + } + + private: + std::string const& filename_; + markers_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; + RendererType const& common_; + box2d const& clip_box_; + ContextType const& renderer_context_; +}; + template void render_markers_symbolizer(markers_symbolizer const& sym, mapnik::feature_impl & feature, @@ -41,168 +265,18 @@ void render_markers_symbolizer(markers_symbolizer const& sym, ContextType const& renderer_context) { using namespace mapnik::svg; - using vector_dispatch_type = VD; - using raster_dispatch_type = RD; - using buffer_type = typename std::tuple_element<0,ContextType>::type; - std::string filename = get(sym, keys::file, feature, common.vars_, "shape://ellipse"); - bool clip = get(sym, feature, common.vars_); - double offset = get(sym, feature, common.vars_); - double simplify_tolerance = get(sym, feature, common.vars_); - double smooth = get(sym, feature, common.vars_); - - // https://github.com/mapnik/mapnik/issues/1316 - bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename); if (!filename.empty()) { - boost::optional mark = mapnik::marker_cache::instance().find(filename, true); - if (mark && *mark) - { - agg::trans_affine geom_tr; - auto transform = get_optional(sym, keys::geometry_transform); - if (transform) evaluate_transform(geom_tr, feature, common.vars_, *transform, common.scale_factor_); - agg::trans_affine image_tr = agg::trans_affine_scaling(common.scale_factor_); - - if ((*mark)->is_vector()) - { - boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); - - // special case for simple ellipse markers - // to allow for full control over rx/ry dimensions - if (filename == "shape://ellipse" - && (has_key(sym,keys::width) || has_key(sym,keys::height))) - { - svg_path_ptr marker_ellipse = std::make_shared(); - vertex_stl_adapter stl_storage(marker_ellipse->source()); - svg_path_adapter svg_path(stl_storage); - build_ellipse(sym, feature, common.vars_, *marker_ellipse, svg_path); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym, feature, common.vars_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform); - vector_dispatch_type rasterizer_dispatch(marker_ellipse, - svg_path, - result ? attributes : (*stock_vector_marker)->attributes(), - image_tr, - sym, - *common.detector_, - common.scale_factor_, - feature, - common.vars_, - snap_to_pixels, - renderer_context); - - using vertex_converter_type = vertex_converter; - vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - else if (type == geometry_type::types::LineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, common.vars_, converter, sym); - } - else - { - box2d const& bbox = (*mark)->bounding_box(); - setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature, common.vars_, sym); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform); - vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); - svg_path_adapter svg_path(stl_storage); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym, feature, common.vars_); - vector_dispatch_type rasterizer_dispatch(*stock_vector_marker, - svg_path, - result ? attributes : (*stock_vector_marker)->attributes(), - image_tr, - sym, - *common.detector_, - common.scale_factor_, - feature, - common.vars_, - snap_to_pixels, - renderer_context); - - using vertex_converter_type = vertex_converter; - vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - else if (type == geometry_type::types::LineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, common.vars_, converter, sym); - } - } - else // raster markers - { - setup_transform_scaling(image_tr, (*mark)->width(), (*mark)->height(), feature, common.vars_, sym); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform); - box2d const& bbox = (*mark)->bounding_box(); - boost::optional marker = (*mark)->get_bitmap_data(); - // - clamp sizes to > 4 pixels of interactivity - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * image_tr; - raster_dispatch_type rasterizer_dispatch(**marker, - marker_trans, - sym, - *common.detector_, - common.scale_factor_, - feature, - common.vars_, - renderer_context); - - using vertex_converter_type = vertex_converter; - vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_); - - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - else if (type == geometry_type::types::LineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, common.vars_, converter, sym); - } - } + mapnik::marker const& mark = mapnik::marker_cache::instance().find(filename, true); + render_marker_symbolizer_visitor visitor(filename, + sym, + feature, + prj_trans, + common, + clip_box, + renderer_context); + util::apply_visitor(visitor, mark); } } diff --git a/include/mapnik/renderer_common/process_point_symbolizer.hpp b/include/mapnik/renderer_common/process_point_symbolizer.hpp index 9030aab9d..4fd3df6b8 100644 --- a/include/mapnik/renderer_common/process_point_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_point_symbolizer.hpp @@ -41,18 +41,18 @@ void render_point_symbolizer(point_symbolizer const &sym, F render_marker) { std::string filename = get(sym,feature, common.vars_); - boost::optional marker = filename.empty() - ? std::make_shared() + mapnik::marker const& mark = filename.empty() + ? mapnik::marker(std::move(mapnik::marker_rgba8())) : marker_cache::instance().find(filename, true); - if (marker) + if (!mark.is()) { value_double opacity = get(sym, feature, common.vars_); value_bool allow_overlap = get(sym, feature, common.vars_); value_bool ignore_placement = get(sym, feature, common.vars_); point_placement_enum placement= get(sym, feature, common.vars_); - box2d const& bbox = (*marker)->bounding_box(); + box2d const& bbox = mark.bounding_box(); coord2d center = bbox.center(); agg::trans_affine tr; @@ -89,7 +89,7 @@ void render_point_symbolizer(point_symbolizer const &sym, { render_marker(pixel_position(x, y), - **marker, + mark, tr, opacity); diff --git a/include/mapnik/renderer_common/render_pattern.hpp b/include/mapnik/renderer_common/render_pattern.hpp index 4cbf211c5..ffa3140c2 100644 --- a/include/mapnik/renderer_common/render_pattern.hpp +++ b/include/mapnik/renderer_common/render_pattern.hpp @@ -35,13 +35,14 @@ namespace mapnik { // fwd decl struct rasterizer; -class marker; +struct marker_svg; template -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity); +void render_pattern(rasterizer & ras, + marker_svg const& marker, + agg::trans_affine const& tr, + double opacity, + T & image); } // namespace mapnik diff --git a/include/mapnik/svg/output/svg_renderer.hpp b/include/mapnik/svg/output/svg_renderer.hpp index 43b3a77c2..fe4fc65e0 100644 --- a/include/mapnik/svg/output/svg_renderer.hpp +++ b/include/mapnik/svg/output/svg_renderer.hpp @@ -53,7 +53,7 @@ namespace mapnik { class feature_type_style; class label_collision_detector4; class layer; - class marker; + struct marker; class proj_transform; } diff --git a/include/mapnik/text/glyph_positions.hpp b/include/mapnik/text/glyph_positions.hpp index 884de2786..26c63b8d2 100644 --- a/include/mapnik/text/glyph_positions.hpp +++ b/include/mapnik/text/glyph_positions.hpp @@ -50,10 +50,10 @@ struct glyph_position struct marker_info { - marker_info() : marker(), transform() {} - marker_info(marker_ptr _marker, agg::trans_affine const& _transform) : + //marker_info() : marker(), transform() {} + marker_info(marker const& _marker, agg::trans_affine const& _transform) : marker(_marker), transform(_transform) {} - marker_ptr marker; + marker const& marker; agg::trans_affine transform; }; diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index ea2f7e21b..d988e9a2c 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -108,6 +108,48 @@ agg_renderer::agg_renderer(Map const& m, T0 & pixmap, std::shared_ptr setup(m); } +template +struct setup_agg_bg_visitor +{ + setup_agg_bg_visitor(buffer_type & pixmap, + renderer_common const& common, + composite_mode_e mode, + double opacity) + : pixmap_(pixmap), + common_(common), + mode_(mode), + opacity_(opacity) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const&) {} + + void operator() (marker_rgba8 const& marker) + { + mapnik::image_rgba8 const& bg_image = marker.get_data(); + int w = bg_image.width(); + int h = bg_image.height(); + if ( w > 0 && h > 0) + { + // repeat background-image both vertically and horizontally + unsigned x_steps = static_cast(std::ceil(common_.width_/double(w))); + unsigned y_steps = static_cast(std::ceil(common_.height_/double(h))); + for (unsigned x=0;x void agg_renderer::setup(Map const &m) { @@ -133,26 +175,12 @@ void agg_renderer::setup(Map const &m) if (image_filename) { // NOTE: marker_cache returns premultiplied image, if needed - boost::optional bg_marker = mapnik::marker_cache::instance().find(*image_filename,true); - if (bg_marker && (*bg_marker)->is_bitmap()) - { - mapnik::image_ptr bg_image = *(*bg_marker)->get_bitmap_data(); - int w = bg_image->width(); - int h = bg_image->height(); - if ( w > 0 && h > 0) - { - // repeat background-image both vertically and horizontally - unsigned x_steps = static_cast(std::ceil(common_.width_/double(w))); - unsigned y_steps = static_cast(std::ceil(common_.height_/double(h))); - for (unsigned x=0;x(*bg_image), m.background_image_comp_op(), m.background_image_opacity(), x*w, y*h); - } - } - } - } + mapnik::marker const& bg_marker = mapnik::marker_cache::instance().find(*image_filename,true); + setup_agg_bg_visitor visitor(pixmap_, + common_, + m.background_image_comp_op(), + m.background_image_opacity()); + util::apply_visitor(visitor, bg_marker); } MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Scale=" << m.scale(); } @@ -305,86 +333,128 @@ void agg_renderer::end_style_processing(feature_type_style const& st) MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End processing style"; } -template -void agg_renderer::render_marker(pixel_position const& pos, - marker const& marker, - agg::trans_affine const& tr, - double opacity, - composite_mode_e comp_op) +template +struct agg_render_marker_visitor { - using color_type = agg::rgba8; - using order_type = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender - using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - using renderer_type = agg::renderer_scanline_aa_solid; - using svg_attribute_type = agg::pod_bvector; + agg_render_marker_visitor(renderer_common & common, + buffer_type * current_buffer, + std::unique_ptr const& ras_ptr, + gamma_method_enum & gamma_method, + double & gamma, + pixel_position const& pos, + agg::trans_affine const& tr, + double opacity, + composite_mode_e comp_op) + : common_(common), + current_buffer_(current_buffer), + ras_ptr_(ras_ptr), + gamma_method_(gamma_method), + gamma_(gamma), + pos_(pos), + tr_(tr), + opacity_(opacity), + comp_op_(comp_op) {} - ras_ptr->reset(); - if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) - { - ras_ptr->gamma(agg::gamma_power()); - gamma_method_ = GAMMA_POWER; - gamma_ = 1.0; - } - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->getBytes(), - current_buffer_->width(), - current_buffer_->height(), - current_buffer_->getRowSize()); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(comp_op)); - renderer_base renb(pixf); + void operator() (marker_null const&) {} - if (marker.is_vector()) + void operator() (marker_svg const& marker) { - box2d const& bbox = (*marker.get_vector_data())->bounding_box(); + using color_type = agg::rgba8; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender + using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_scanline_aa_solid; + using svg_attribute_type = agg::pod_bvector; + + ras_ptr_->reset(); + if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) + { + ras_ptr_->gamma(agg::gamma_power()); + gamma_method_ = GAMMA_POWER; + gamma_ = 1.0; + } + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->getBytes(), + current_buffer_->width(), + current_buffer_->height(), + current_buffer_->getRowSize()); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(comp_op_)); + renderer_base renb(pixf); + + box2d const& bbox = marker.get_data()->bounding_box(); coord c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); // apply symbol transformation to get to map space - mtx *= tr; + mtx *= tr_; mtx *= agg::trans_affine_scaling(common_.scale_factor_); // render the marker at the center of the marker box - mtx.translate(pos.x, pos.y); + mtx.translate(pos_.x, pos_.y); using namespace mapnik::svg; - vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + vertex_stl_adapter stl_storage(marker.get_data()->source()); svg_path_adapter svg_path(stl_storage); svg_renderer_agg svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); + marker.get_data()->attributes()); // https://github.com/mapnik/mapnik/issues/1316 // https://github.com/mapnik/mapnik/issues/1866 mtx.tx = std::floor(mtx.tx+.5); mtx.ty = std::floor(mtx.ty+.5); - svg_renderer.render(*ras_ptr, sl, renb, mtx, opacity, bbox); + svg_renderer.render(*ras_ptr_, sl, renb, mtx, opacity_, bbox); } - else + + void operator() (marker_rgba8 const& marker) { - double width = (*marker.get_bitmap_data())->width(); - double height = (*marker.get_bitmap_data())->height(); + using color_type = agg::rgba8; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender + using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_scanline_aa_solid; + using svg_attribute_type = agg::pod_bvector; + + ras_ptr_->reset(); + if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) + { + ras_ptr_->gamma(agg::gamma_power()); + gamma_method_ = GAMMA_POWER; + gamma_ = 1.0; + } + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->getBytes(), + current_buffer_->width(), + current_buffer_->height(), + current_buffer_->getRowSize()); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(comp_op_)); + renderer_base renb(pixf); + + double width = marker.width(); + double height = marker.height(); if (std::fabs(1.0 - common_.scale_factor_) < 0.001 - && (std::fabs(1.0 - tr.sx) < agg::affine_epsilon) - && (std::fabs(0.0 - tr.shy) < agg::affine_epsilon) - && (std::fabs(0.0 - tr.shx) < agg::affine_epsilon) - && (std::fabs(1.0 - tr.sy) < agg::affine_epsilon)) + && (std::fabs(1.0 - tr_.sx) < agg::affine_epsilon) + && (std::fabs(0.0 - tr_.shy) < agg::affine_epsilon) + && (std::fabs(0.0 - tr_.shx) < agg::affine_epsilon) + && (std::fabs(1.0 - tr_.sy) < agg::affine_epsilon)) { double cx = 0.5 * width; double cy = 0.5 * height; - composite(*current_buffer_, util::get(**marker.get_bitmap_data()), - comp_op, opacity, - std::floor(pos.x - cx + .5), - std::floor(pos.y - cy + .5)); + composite(*current_buffer_, marker.get_data(), + comp_op_, opacity_, + std::floor(pos_.x - cx + .5), + std::floor(pos_.y - cy + .5)); } else { double p[8]; - double x0 = pos.x - 0.5 * width; - double y0 = pos.y - 0.5 * height; + double x0 = pos_.x - 0.5 * width; + double y0 = pos_.y - 0.5 * height; p[0] = x0; p[1] = y0; p[2] = x0 + width; p[3] = y0; p[4] = x0 + width; p[5] = y0 + height; @@ -392,27 +462,27 @@ void agg_renderer::render_marker(pixel_position const& pos, agg::trans_affine marker_tr; - marker_tr *= agg::trans_affine_translation(-pos.x,-pos.y); - marker_tr *= tr; + marker_tr *= agg::trans_affine_translation(-pos_.x,-pos_.y); + marker_tr *= tr_; marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); - marker_tr *= agg::trans_affine_translation(pos.x,pos.y); + marker_tr *= agg::trans_affine_translation(pos_.x,pos_.y); marker_tr.transform(&p[0], &p[1]); marker_tr.transform(&p[2], &p[3]); marker_tr.transform(&p[4], &p[5]); marker_tr.transform(&p[6], &p[7]); - ras_ptr->move_to_d(p[0],p[1]); - ras_ptr->line_to_d(p[2],p[3]); - ras_ptr->line_to_d(p[4],p[5]); - ras_ptr->line_to_d(p[6],p[7]); + ras_ptr_->move_to_d(p[0],p[1]); + ras_ptr_->line_to_d(p[2],p[3]); + ras_ptr_->line_to_d(p[4],p[5]); + ras_ptr_->line_to_d(p[6],p[7]); agg::span_allocator sa; agg::image_filter_bilinear filter_kernel; agg::image_filter_lut filter(filter_kernel, false); - buffer_type const& src = util::get(**marker.get_bitmap_data()); + buffer_type const& src = marker.get_data(); agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), src.width(), src.height(), @@ -431,10 +501,41 @@ void agg_renderer::render_marker(pixel_position const& pos, final_tr.ty = std::floor(final_tr.ty+.5); interpolator_type interpolator(final_tr); span_gen_type sg(ia, interpolator, filter); - renderer_type rp(renb,sa, sg, unsigned(opacity*255)); - agg::render_scanlines(*ras_ptr, sl, rp); + renderer_type rp(renb,sa, sg, unsigned(opacity_*255)); + agg::render_scanlines(*ras_ptr_, sl, rp); } } + + private: + renderer_common & common_; + buffer_type * current_buffer_; + std::unique_ptr const& ras_ptr_; + gamma_method_enum & gamma_method_; + double & gamma_; + pixel_position const& pos_; + agg::trans_affine const& tr_; + double opacity_; + composite_mode_e comp_op_; + +}; + +template +void agg_renderer::render_marker(pixel_position const& pos, + marker const& marker, + agg::trans_affine const& tr, + double opacity, + composite_mode_e comp_op) +{ + agg_render_marker_visitor visitor(common_, + current_buffer_, + ras_ptr, + gamma_method_, + gamma_, + pos, + tr, + opacity, + comp_op); + util::apply_visitor(visitor, marker); } template diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index d84ae23f8..5ed8cae1c 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -112,21 +112,6 @@ struct thunk_renderer render_raster_marker(renb, *ras_ptr_, thunk.src_, offset_tr, thunk.opacity_, common_.scale_factor_, thunk.snap_to_pixels_); } - void operator()(raster_marker_render_thunk const &thunk) const - { - throw std::runtime_error("Rendering of this image_gray8 type is not supported currently by the image_rgba8 renderer"); - } - - void operator()(raster_marker_render_thunk const &thunk) const - { - throw std::runtime_error("Rendering of this image_gray16 type is not supported currently by the image_rgba8 renderer"); - } - - void operator()(raster_marker_render_thunk const &thunk) const - { - throw std::runtime_error("Rendering of this image_gray32f type is not supported currently by the image_rgba8 renderer"); - } - void operator()(text_render_thunk const &thunk) const { text_renderer_type ren(*buf_, thunk.halo_rasterizer_, thunk.comp_op_, thunk.comp_op_, @@ -140,7 +125,7 @@ struct thunk_renderer if (glyphs->marker()) { ren_.render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, thunk.opacity_, thunk.comp_op_); } diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index 5e3ada14e..11e214518 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -52,106 +52,201 @@ namespace mapnik { +template +struct agg_renderer_process_visitor_l +{ + agg_renderer_process_visitor_l(renderer_common & common, + buffer_type & pixmap, + buffer_type * current_buffer, + std::unique_ptr const& ras_ptr, + line_pattern_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans) + : common_(common), + pixmap_(pixmap), + current_buffer_(current_buffer), + ras_ptr_(ras_ptr), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) + { + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; + using pattern_type = agg::line_image_pattern; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_outline_image; + using rasterizer_type = agg::rasterizer_outline_aa; + + value_double opacity = get(sym_, feature_, common_.vars_); + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; + image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double offset = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + renderer_base ren_base(pixf); + agg::pattern_filter_bilinear_rgba8 filter; + + pattern_source source(image, opacity); + pattern_type pattern (filter,source); + renderer_type ren(ren_base, pattern); + rasterizer_type ras(ren); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + box2d clip_box = clipping_extent(common_); + if (clip) + { + double padding = (double)(common_.query_extent_.width()/pixmap_.width()); + double half_stroke = marker.width()/2.0; + if (half_stroke > 1) + padding *= half_stroke; + if (std::fabs(offset) > 0) + padding *= std::fabs(offset) * 1.2; + padding *= common_.scale_factor_; + clip_box.pad(padding); + } + + vertex_converter + converter(clip_box,ras,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (std::fabs(offset) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (smooth > 0.0) converter.set(); // optional smooth converter + + for (geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 1) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + } + + void operator() (marker_rgba8 const& marker) + { + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; + using pattern_type = agg::line_image_pattern; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_outline_image; + using rasterizer_type = agg::rasterizer_outline_aa; + + value_double opacity = get(sym_, feature_, common_.vars_); + mapnik::image_rgba8 const& image = marker.get_data(); + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double offset = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + renderer_base ren_base(pixf); + agg::pattern_filter_bilinear_rgba8 filter; + + pattern_source source(image, opacity); + pattern_type pattern (filter,source); + renderer_type ren(ren_base, pattern); + rasterizer_type ras(ren); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + box2d clip_box = clipping_extent(common_); + if (clip) + { + double padding = (double)(common_.query_extent_.width()/pixmap_.width()); + double half_stroke = marker.width()/2.0; + if (half_stroke > 1) + padding *= half_stroke; + if (std::fabs(offset) > 0) + padding *= std::fabs(offset) * 1.2; + padding *= common_.scale_factor_; + clip_box.pad(padding); + } + + vertex_converter + converter(clip_box,ras,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (std::fabs(offset) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (smooth > 0.0) converter.set(); // optional smooth converter + + for (geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 1) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + } + + private: + renderer_common & common_; + buffer_type & pixmap_; + buffer_type * current_buffer_; + std::unique_ptr const& ras_ptr_; + line_pattern_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; +}; + template void agg_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - using color = agg::rgba8; - using order = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; - using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; - using pattern_type = agg::line_image_pattern; - using pixfmt_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - using renderer_type = agg::renderer_outline_image; - using rasterizer_type = agg::rasterizer_outline_aa; std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional marker_ptr = marker_cache::instance().find(filename, true); - if (!marker_ptr || !(*marker_ptr)) return; - boost::optional > pat; - // TODO - re-implement at renderer level like polygon_pattern symbolizer - value_double opacity = get(sym, feature, common_.vars_); - if ((*marker_ptr)->is_bitmap()) - { - // FIXME: copy is necessary atm to transform a - // shared_ptr into shared_ptr - boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); - if (bitmap) { - mapnik::image_any const& im = *(bitmap)->get(); - if (im.is()) { - // invoke copy ctor of image_rgba8 - pat = std::make_shared(util::get(im)); - } - } - } - else - { - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); - } - - if (!pat) return; - - value_bool clip = get(sym, feature, common_.vars_); - value_double offset = get(sym, feature, common_.vars_); - value_double simplify_tolerance = get(sym, feature, common_.vars_); - value_double smooth = get(sym, feature, common_.vars_); - - agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); - pixfmt_type pixf(buf); - pixf.comp_op(static_cast(get(sym, feature, common_.vars_))); - renderer_base ren_base(pixf); - agg::pattern_filter_bilinear_rgba8 filter; - - pattern_source source(*(*pat), opacity); - pattern_type pattern (filter,source); - renderer_type ren(ren_base, pattern); - rasterizer_type ras(ren); - - agg::trans_affine tr; - auto transform = get_optional(sym, keys::geometry_transform); - if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); - - box2d clip_box = clipping_extent(common_); - if (clip) - { - double padding = (double)(common_.query_extent_.width()/pixmap_.width()); - double half_stroke = (*marker_ptr)->width()/2.0; - if (half_stroke > 1) - padding *= half_stroke; - if (std::fabs(offset) > 0) - padding *= std::fabs(offset) * 1.2; - padding *= common_.scale_factor_; - clip_box.pad(padding); - } - - vertex_converter - converter(clip_box,ras,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - - if (clip) converter.set(); //optional clip (default: true) - converter.set(); //always transform - if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter - if (std::fabs(offset) > 0.0) converter.set(); // parallel offset - converter.set(); // optional affine transform - if (smooth > 0.0) converter.set(); // optional smooth converter - - for (geometry_type const& geom : feature.paths()) - { - if (geom.size() > 1) - { - vertex_adapter va(geom); - converter.apply(va); - } - } + mapnik::marker const & marker = marker_cache::instance().find(filename, true); + agg_renderer_process_visitor_l visitor(common_, + pixmap_, + current_buffer_, + ras_ptr, + sym, + feature, + prj_trans); + util::apply_visitor(visitor, marker); } template void agg_renderer::process(line_pattern_symbolizer const&, diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 49b6bef89..446cfa2ff 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -124,7 +124,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch; using renderer_base = agg::renderer_base; - raster_markers_rasterizer_dispatch(image_any & src, + raster_markers_rasterizer_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -149,7 +149,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_ provided that converts // the destination pixel type required. - render_raster_marker(renb_, ras_, util::get(this->src_), marker_tr, opacity, this->scale_factor_, snap_to_pixels_); + render_raster_marker(renb_, ras_, this->src_, marker_tr, opacity, this->scale_factor_, snap_to_pixels_); } private: diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 1d47d20ce..9a0622ca0 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -53,6 +53,254 @@ namespace mapnik { +template +struct agg_renderer_process_visitor_p +{ + agg_renderer_process_visitor_p(renderer_common & common, + buffer_type * current_buffer, + std::unique_ptr const& ras_ptr, + gamma_method_enum & gamma_method, + double & gamma, + polygon_pattern_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans) + : common_(common), + current_buffer_(current_buffer), + ras_ptr_(ras_ptr), + gamma_method_(gamma_method), + gamma_(gamma), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) + { + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; + mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + + using clipped_geometry_type = agg::conv_clip_polygon; + using path_type = transform_path_adapter; + + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), + current_buffer_->height(), current_buffer_->getRowSize()); + ras_ptr_->reset(); + value_double gamma = get(sym_, feature_, common_.vars_); + gamma_method_enum gamma_method = get(sym_, feature_, common_.vars_); + if (gamma != gamma_ || gamma_method != gamma_method_) + { + set_gamma_method(ras_ptr_, gamma, gamma_method); + gamma_method_ = gamma_method; + gamma_ = gamma; + } + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double opacity = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + box2d clip_box = clipping_extent(common_); + + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + + using wrap_x_type = agg::wrap_mode_repeat; + using wrap_y_type = agg::wrap_mode_repeat; + using img_source_type = agg::image_accessor_wrap; + + using span_gen_type = agg::span_pattern_rgba; + using ren_base = agg::renderer_base; + + using renderer_type = agg::renderer_scanline_aa_alpha, + span_gen_type>; + + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + ren_base renb(pixf); + + unsigned w = image.width(); + unsigned h = image.height(); + agg::rendering_buffer pattern_rbuf((agg::int8u*)image.getBytes(),w,h,w*4); + agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); + img_source_type img_src(pixf_pattern); + + pattern_alignment_enum alignment = get(sym_, feature_, common_.vars_); + unsigned offset_x=0; + unsigned offset_y=0; + + if (alignment == LOCAL_ALIGNMENT) + { + double x0 = 0; + double y0 = 0; + if (feature_.num_geometries() > 0) + { + vertex_adapter va(feature_.get_geometry(0)); + clipped_geometry_type clipped(va); + clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy()); + path_type path(common_.t_,clipped,prj_trans_); + path.vertex(&x0,&y0); + } + offset_x = unsigned(current_buffer_->width() - x0); + offset_y = unsigned(current_buffer_->height() - y0); + } + + span_gen_type sg(img_src, offset_x, offset_y); + + agg::span_allocator sa; + renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + vertex_converter + converter(clip_box,*ras_ptr_,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (prj_trans_.equal() && clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + converter.set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (smooth > 0.0) converter.set(); // optional smooth converter + + for ( geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 2) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + agg::scanline_u8 sl; + ras_ptr_->filling_rule(agg::fill_even_odd); + agg::render_scanlines(*ras_ptr_, sl, rp); + } + + void operator() (marker_rgba8 const& marker) + { + using clipped_geometry_type = agg::conv_clip_polygon; + using path_type = transform_path_adapter; + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + + using wrap_x_type = agg::wrap_mode_repeat; + using wrap_y_type = agg::wrap_mode_repeat; + using img_source_type = agg::image_accessor_wrap; + + using span_gen_type = agg::span_pattern_rgba; + using ren_base = agg::renderer_base; + + using renderer_type = agg::renderer_scanline_aa_alpha, + span_gen_type>; + mapnik::image_rgba8 const& image = marker.get_data(); + + + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), + current_buffer_->height(), current_buffer_->getRowSize()); + ras_ptr_->reset(); + value_double gamma = get(sym_, feature_, common_.vars_); + gamma_method_enum gamma_method = get(sym_, feature_, common_.vars_); + if (gamma != gamma_ || gamma_method != gamma_method_) + { + set_gamma_method(ras_ptr_, gamma, gamma_method); + gamma_method_ = gamma_method; + gamma_ = gamma; + } + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double opacity = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + box2d clip_box = clipping_extent(common_); + + + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + ren_base renb(pixf); + + unsigned w = image.width(); + unsigned h = image.height(); + agg::rendering_buffer pattern_rbuf((agg::int8u*)image.getBytes(),w,h,w*4); + agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); + img_source_type img_src(pixf_pattern); + + pattern_alignment_enum alignment = get(sym_, feature_, common_.vars_); + unsigned offset_x=0; + unsigned offset_y=0; + + if (alignment == LOCAL_ALIGNMENT) + { + double x0 = 0; + double y0 = 0; + if (feature_.num_geometries() > 0) + { + vertex_adapter va(feature_.get_geometry(0)); + clipped_geometry_type clipped(va); + clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy()); + path_type path(common_.t_,clipped,prj_trans_); + path.vertex(&x0,&y0); + } + offset_x = unsigned(current_buffer_->width() - x0); + offset_y = unsigned(current_buffer_->height() - y0); + } + + span_gen_type sg(img_src, offset_x, offset_y); + + agg::span_allocator sa; + renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + vertex_converter + converter(clip_box,*ras_ptr_,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (prj_trans_.equal() && clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + converter.set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (smooth > 0.0) converter.set(); // optional smooth converter + + for ( geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 2) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + agg::scanline_u8 sl; + ras_ptr_->filling_rule(agg::fill_even_odd); + agg::render_scanlines(*ras_ptr_, sl, rp); + } + + private: + renderer_common & common_; + buffer_type * current_buffer_; + std::unique_ptr const& ras_ptr_; + gamma_method_enum & gamma_method_; + double & gamma_; + polygon_pattern_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; +}; + template void agg_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -60,133 +308,16 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, { std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional marker_ptr = marker_cache::instance().find(filename, true); - if (!marker_ptr || !(*marker_ptr)) return; - - boost::optional > pat; - - if ((*marker_ptr)->is_bitmap()) - { - // FIXME: copy is necessary atm to transform a - // shared_ptr into shared_ptr - boost::optional bitmap = (*marker_ptr)->get_bitmap_data(); - if (bitmap) { - mapnik::image_any const& im = *(bitmap)->get(); - if (im.is()) { - // invoke copy ctor of image_rgba8 - pat = std::make_shared(util::get(im)); - } - } - } - else - { - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); - } - - if (!pat) return; - - using clipped_geometry_type = agg::conv_clip_polygon; - using path_type = transform_path_adapter; - - agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), - current_buffer_->height(), current_buffer_->getRowSize()); - ras_ptr->reset(); - value_double gamma = get(sym, feature, common_.vars_); - gamma_method_enum gamma_method = get(sym, feature, common_.vars_); - if (gamma != gamma_ || gamma_method != gamma_method_) - { - set_gamma_method(ras_ptr, gamma, gamma_method); - gamma_method_ = gamma_method; - gamma_ = gamma; - } - - value_bool clip = get(sym, feature, common_.vars_); - value_double opacity = get(sym, feature, common_.vars_); - value_double simplify_tolerance = get(sym, feature, common_.vars_); - value_double smooth = get(sym, feature, common_.vars_); - - box2d clip_box = clipping_extent(common_); - - using color = agg::rgba8; - using order = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; - using pixfmt_type = agg::pixfmt_custom_blend_rgba; - - using wrap_x_type = agg::wrap_mode_repeat; - using wrap_y_type = agg::wrap_mode_repeat; - using img_source_type = agg::image_accessor_wrap; - - using span_gen_type = agg::span_pattern_rgba; - using ren_base = agg::renderer_base; - - using renderer_type = agg::renderer_scanline_aa_alpha, - span_gen_type>; - - pixfmt_type pixf(buf); - pixf.comp_op(static_cast(get(sym, feature, common_.vars_))); - ren_base renb(pixf); - - unsigned w=(*pat)->width(); - unsigned h=(*pat)->height(); - agg::rendering_buffer pattern_rbuf((agg::int8u*)(*pat)->getBytes(),w,h,w*4); - agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); - img_source_type img_src(pixf_pattern); - - pattern_alignment_enum alignment = get(sym, feature, common_.vars_); - unsigned offset_x=0; - unsigned offset_y=0; - - if (alignment == LOCAL_ALIGNMENT) - { - double x0 = 0; - double y0 = 0; - if (feature.num_geometries() > 0) - { - vertex_adapter va(feature.get_geometry(0)); - clipped_geometry_type clipped(va); - clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy()); - path_type path(common_.t_,clipped,prj_trans); - path.vertex(&x0,&y0); - } - offset_x = unsigned(current_buffer_->width() - x0); - offset_y = unsigned(current_buffer_->height() - y0); - } - - span_gen_type sg(img_src, offset_x, offset_y); - - agg::span_allocator sa; - renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); - - agg::trans_affine tr; - auto transform = get_optional(sym, keys::geometry_transform); - if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); - - vertex_converter - converter(clip_box,*ras_ptr,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - - if (prj_trans.equal() && clip) converter.set(); //optional clip (default: true) - converter.set(); //always transform - converter.set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter - if (smooth > 0.0) converter.set(); // optional smooth converter - - for ( geometry_type const& geom : feature.paths()) - { - if (geom.size() > 2) - { - vertex_adapter va(geom); - converter.apply(va); - } - } - agg::scanline_u8 sl; - ras_ptr->filling_rule(agg::fill_even_odd); - agg::render_scanlines(*ras_ptr, sl, rp); + mapnik::marker const& marker = marker_cache::instance().find(filename, true); + agg_renderer_process_visitor_p visitor(common_, + current_buffer_, + ras_ptr, + gamma_method_, + gamma_, + sym, + feature, + prj_trans); + util::apply_visitor(visitor, marker); } diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 619fb163c..008b427c6 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -64,7 +64,7 @@ void agg_renderer::process(shield_symbolizer const& sym, { if (glyphs->marker()) render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, opacity, comp_op); ren.render(*glyphs); diff --git a/src/cairo/cairo_context.cpp b/src/cairo/cairo_context.cpp index ba6774cae..fe35c3a9f 100644 --- a/src/cairo/cairo_context.cpp +++ b/src/cairo/cairo_context.cpp @@ -32,57 +32,6 @@ #include namespace mapnik { -namespace detail { - -struct visitor_context_add_image_1 -{ - visitor_context_add_image_1(cairo_context & context, double x, double y, double opacity) - : context_(context), x_(x), y_(y), opacity_(opacity) {} - - template - void operator() (T & data) - { - throw std::runtime_error("Cairo currently does not support this image data type."); - } - - private: - cairo_context & context_; - double x_; - double y_; - double opacity_; -}; - -template <> -void visitor_context_add_image_1::operator() (image_rgba8 & data) -{ - context_.add_image(x_, y_, data, opacity_); -} - -struct visitor_context_add_image_2 -{ - visitor_context_add_image_2(cairo_context & context, agg::trans_affine const& tr, double opacity) - : context_(context), tr_(tr), opacity_(opacity) {} - - template - void operator() (T & data) - { - throw std::runtime_error("Cairo currently does not support this image data type."); - } - - private: - cairo_context & context_; - agg::trans_affine const& tr_; - double opacity_; -}; - -template <> -void visitor_context_add_image_2::operator() (image_rgba8 & data) -{ - context_.add_image(tr_, data, opacity_); -} - -} // end detail ns - cairo_face::cairo_face(std::shared_ptr const& library, face_ptr const& face) : face_(face) { @@ -388,17 +337,7 @@ void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d::cairo_renderer(Map const& m, template cairo_renderer::~cairo_renderer() {} +struct setup_marker_visitor +{ + setup_marker_visitor(cairo_context & context, renderer_common const& common) + : context_(context), common_(common) {} + + void operator() (marker_null const &) {} + void operator() (marker_svg const &) {} + + void operator() (marker_rgba8 const& marker) + { + mapnik::image_rgba8 const& bg_image = marker.get_data(); + int w = bg_image.width(); + int h = bg_image.height(); + if ( w > 0 && h > 0) + { + // repeat background-image both vertically and horizontally + unsigned x_steps = unsigned(std::ceil(common_.width_/double(w))); + unsigned y_steps = unsigned(std::ceil(common_.height_/double(h))); + for (unsigned x=0;x void cairo_renderer::setup(Map const& map) { @@ -113,29 +149,8 @@ void cairo_renderer::setup(Map const& map) if (image_filename) { // NOTE: marker_cache returns premultiplied image, if needed - boost::optional bg_marker = mapnik::marker_cache::instance().find(*image_filename,true); - if (bg_marker && (*bg_marker)->is_bitmap()) - { - mapnik::image_ptr bg_image = *(*bg_marker)->get_bitmap_data(); - int w = bg_image->width(); - int h = bg_image->height(); - if ( w > 0 && h > 0) - { - // repeat background-image both vertically and horizontally - unsigned x_steps = unsigned(std::ceil(common_.width_/double(w))); - unsigned y_steps = unsigned(std::ceil(common_.height_/double(h))); - for (unsigned x=0;x bbox = vmarker->bounding_box(); + agg::trans_affine marker_tr = tr_; + if (recenter_) + { + coord c = bbox.center(); + marker_tr = agg::trans_affine_translation(-c.x,-c.y); + marker_tr *= tr_; + } + marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); + agg::pod_bvector const & attributes = vmarker->attributes(); + svg::vertex_stl_adapter stl_storage(vmarker->source()); + svg::svg_path_adapter svg_path(stl_storage); + marker_tr.translate(pos_.x, pos_.y); + render_vector_marker(context_, svg_path, attributes, bbox, marker_tr, opacity_); + } + } + + void operator() (marker_rgba8 const& marker) + { + double width = marker.get_data().width(); + double height = marker.get_data().height(); + double cx = 0.5 * width; + double cy = 0.5 * height; + agg::trans_affine marker_tr; + marker_tr *= agg::trans_affine_translation(-cx,-cy); + marker_tr *= tr_; + marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); + marker_tr *= agg::trans_affine_translation(pos_.x,pos_.y); + context_.add_image(marker_tr, marker.get_data(), opacity_); + } + + private: + cairo_context & context_; + renderer_common const& common_; + pixel_position const& pos_; + agg::trans_affine const& tr_; + double opacity_; + bool recenter_; +}; + template void cairo_renderer::render_marker(pixel_position const& pos, marker const& marker, @@ -196,40 +273,13 @@ void cairo_renderer::render_marker(pixel_position const& pos, { cairo_save_restore guard(context_); - if (marker.is_vector()) - { - mapnik::svg_path_ptr vmarker = *marker.get_vector_data(); - if (vmarker) - { - box2d bbox = vmarker->bounding_box(); - agg::trans_affine marker_tr = tr; - if (recenter) - { - coord c = bbox.center(); - marker_tr = agg::trans_affine_translation(-c.x,-c.y); - marker_tr *= tr; - } - marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); - agg::pod_bvector const & attributes = vmarker->attributes(); - svg::vertex_stl_adapter stl_storage(vmarker->source()); - svg::svg_path_adapter svg_path(stl_storage); - marker_tr.translate(pos.x, pos.y); - render_vector_marker(context_, svg_path, attributes, bbox, marker_tr, opacity); - } - } - else if (marker.is_bitmap()) - { - double width = (*marker.get_bitmap_data())->width(); - double height = (*marker.get_bitmap_data())->height(); - double cx = 0.5 * width; - double cy = 0.5 * height; - agg::trans_affine marker_tr; - marker_tr *= agg::trans_affine_translation(-cx,-cy); - marker_tr *= tr; - marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); - marker_tr *= agg::trans_affine_translation(pos.x,pos.y); - context_.add_image(marker_tr, **marker.get_bitmap_data(), opacity); - } + cairo_render_marker_visitor visitor(context_, + common_, + pos, + tr, + opacity, + recenter); + util::apply_visitor(visitor, marker); } template class cairo_renderer; diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index f5150aa97..216114347 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -100,7 +100,7 @@ struct thunk_renderer if (glyphs->marker()) { ren_.render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, thunk.opacity_, thunk.comp_op_); } diff --git a/src/cairo/process_line_pattern_symbolizer.cpp b/src/cairo/process_line_pattern_symbolizer.cpp index ed675fa79..7048ff812 100644 --- a/src/cairo/process_line_pattern_symbolizer.cpp +++ b/src/cairo/process_line_pattern_symbolizer.cpp @@ -36,32 +36,53 @@ namespace mapnik { -namespace detail +struct cairo_renderer_process_visitor_l { + cairo_renderer_process_visitor_l(renderer_common const& common, + line_pattern_symbolizer const& sym, + mapnik::feature_impl & feature, + unsigned & width, + unsigned & height) + : common_(common), + sym_(sym), + feature_(feature), + width_(width), + height_(height) {} -struct visitor_create_pattern -{ - visitor_create_pattern(float opacity) - : opacity_(opacity) {} - - template - std::shared_ptr operator() (T & data) + std::shared_ptr operator() (mapnik::marker_null const&) { - throw std::runtime_error("This data type is not supported by cairo rendering in mapnik."); + throw std::runtime_error("This should not have been reached."); + } + + std::shared_ptr operator() (mapnik::marker_svg const& marker) + { + double opacity = get(sym_, feature_, common_.vars_); + mapnik::rasterizer ras; + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; + mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(ras, marker, image_tr, 1.0, image); + width_ = image.width(); + height_ = image.height(); + return std::make_shared(image, opacity); + } + + std::shared_ptr operator() (mapnik::marker_rgba8 const& marker) + { + double opacity = get(sym_, feature_, common_.vars_); + return std::make_shared(marker.get_data(), opacity); } private: - float opacity_; + renderer_common const& common_; + line_pattern_symbolizer const& sym_; + mapnik::feature_impl & feature_; + unsigned & width_; + unsigned & height_; }; -template <> -std::shared_ptr visitor_create_pattern::operator() (image_rgba8 & data) -{ - return std::make_shared(data, opacity_); -} - -} // end detail ns - template void cairo_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -74,39 +95,29 @@ void cairo_renderer::process(line_pattern_symbolizer const& sym, value_double simplify_tolerance = get(sym, feature, common_.vars_); value_double smooth = get(sym, feature, common_.vars_); - boost::optional marker; - if ( !filename.empty() ) + if (filename.empty()) { - marker = marker_cache::instance().find(filename, true); + return; } - if (!marker || !(*marker)) return; - unsigned width = (*marker)->width(); - unsigned height = (*marker)->height(); + mapnik::marker const& marker = marker_cache::instance().find(filename, true); + + if (marker.is()) return; + + unsigned width = marker.width(); + unsigned height = marker.height(); cairo_save_restore guard(context_); context_.set_operator(comp_op); - std::shared_ptr pattern; - std::shared_ptr image = nullptr; // TODO - re-implement at renderer level like polygon_pattern symbolizer - double opacity = get(sym, feature, common_.vars_); - if ((*marker)->is_bitmap()) - { - pattern = util::apply_visitor(detail::visitor_create_pattern(opacity), **((*marker)->get_bitmap_data())); - context_.set_line_width(height); - } - else - { - mapnik::rasterizer ras; - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - image = render_pattern(ras, **marker, image_tr, 1.0); - pattern = std::make_unique(*image, opacity); - width = image->width(); - height = image->height(); - context_.set_line_width(height); - } + cairo_renderer_process_visitor_l visit(common_, + sym, + feature, + width, + height); + std::shared_ptr pattern = util::apply_visitor(visit, marker); + + context_.set_line_width(height); pattern->set_extend(CAIRO_EXTEND_REPEAT); pattern->set_filter(CAIRO_FILTER_BILINEAR); diff --git a/src/cairo/process_markers_symbolizer.cpp b/src/cairo/process_markers_symbolizer.cpp index 323160320..3cfb39496 100644 --- a/src/cairo/process_markers_symbolizer.cpp +++ b/src/cairo/process_markers_symbolizer.cpp @@ -86,7 +86,7 @@ private: template struct raster_markers_dispatch_cairo : public raster_markers_dispatch { - raster_markers_dispatch_cairo(image_any & src, + raster_markers_dispatch_cairo(image_rgba8 const& src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, diff --git a/src/cairo/process_polygon_pattern_symbolizer.cpp b/src/cairo/process_polygon_pattern_symbolizer.cpp index ccc1c8f5e..f074260eb 100644 --- a/src/cairo/process_polygon_pattern_symbolizer.cpp +++ b/src/cairo/process_polygon_pattern_symbolizer.cpp @@ -37,37 +37,49 @@ namespace mapnik { -namespace detail +struct cairo_renderer_process_visitor_p { + cairo_renderer_process_visitor_p(cairo_context & context, + agg::trans_affine & image_tr, + unsigned offset_x, + unsigned offset_y, + float opacity) + : context_(context), + image_tr_(image_tr), + offset_x_(offset_x), + offset_y_(offset_y), + opacity_(opacity) {} -struct visitor_set_pattern -{ - visitor_set_pattern(cairo_context & context, unsigned offset_x, unsigned offset_y, float opacity) - : context_(context), offset_x_(offset_x), offset_y_(offset_y), opacity_(opacity) {} + void operator() (marker_null const&) {} - template - void operator() (T & data) + void operator() (marker_svg const& marker) { - throw std::runtime_error("This data type is not supported by cairo rendering in mapnik."); + mapnik::rasterizer ras; + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr_; + mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(ras, marker, image_tr_, 1.0, image); + cairo_pattern pattern(image, opacity_); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_origin(offset_x_, offset_y_); + context_.set_pattern(pattern); } + + void operator() (marker_rgba8 const& marker) + { + cairo_pattern pattern(marker.get_data(), opacity_); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_origin(offset_x_, offset_y_); + context_.set_pattern(pattern); + } + private: cairo_context & context_; + agg::trans_affine & image_tr_; unsigned offset_x_; unsigned offset_y_; float opacity_; }; -template <> -void visitor_set_pattern::operator() (image_rgba8 & data) -{ - cairo_pattern pattern(data, opacity_); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x_, offset_y_); - context_.set_pattern(pattern); -} - -} // end detail ns - template void cairo_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -86,8 +98,8 @@ void cairo_renderer::process(polygon_pattern_symbolizer const& sym, cairo_save_restore guard(context_); context_.set_operator(comp_op); - boost::optional marker = mapnik::marker_cache::instance().find(filename,true); - if (!marker || !(*marker)) return; + mapnik::marker const& marker = mapnik::marker_cache::instance().find(filename,true); + if (marker.is()) return; unsigned offset_x=0; unsigned offset_y=0; @@ -113,19 +125,7 @@ void cairo_renderer::process(polygon_pattern_symbolizer const& sym, offset_y = std::abs(clip_box.height() - y0); } - if ((*marker)->is_bitmap()) - { - util::apply_visitor(detail::visitor_set_pattern(context_, offset_x, offset_y, opacity), **((*marker)->get_bitmap_data())); - } - else - { - mapnik::rasterizer ras; - std::shared_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // - cairo_pattern pattern(*image, opacity); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x, offset_y); - context_.set_pattern(pattern); - } + util::apply_visitor(cairo_renderer_process_visitor_p(context_, image_tr, offset_x, offset_y, opacity), marker); agg::trans_affine tr; auto geom_transform = get_optional(sym, keys::geometry_transform); diff --git a/src/cairo/process_text_symbolizer.cpp b/src/cairo/process_text_symbolizer.cpp index 365e5f662..061e6b7c2 100644 --- a/src/cairo/process_text_symbolizer.cpp +++ b/src/cairo/process_text_symbolizer.cpp @@ -60,7 +60,7 @@ void cairo_renderer::process(shield_symbolizer const& sym, if (glyphs->marker()) { pixel_position pos = glyphs->marker_pos(); render_marker(pos, - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, opacity); } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 427435667..e48444242 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -125,10 +125,27 @@ void grid_renderer::end_layer_processing(layer const&) MAPNIK_LOG_DEBUG(grid_renderer) << "grid_renderer: End layer processing"; } -template -void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e /*comp_op*/) +template +struct grid_render_marker_visitor { - if (marker.is_vector()) + grid_render_marker_visitor(buffer_type & pixmap, + std::unique_ptr const& ras_ptr, + renderer_common const& common, + mapnik::feature_impl const& feature, + pixel_position const& pos, + agg::trans_affine const& tr, + double opacity) + : pixmap_(pixmap), + ras_ptr_(ras_ptr), + common_(common), + feature_(feature), + pos_(pos), + tr_(tr), + opacity_(opacity) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) { using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; using renderer_type = agg::renderer_scanline_bin_solid; @@ -140,42 +157,42 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ grid_renderer_base_type renb(pixf); renderer_type ren(renb); - ras_ptr->reset(); + ras_ptr_->reset(); - box2d const& bbox = (*marker.get_vector_data())->bounding_box(); + box2d const& bbox = marker.get_data()->bounding_box(); coord c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); // apply symbol transformation to get to map space - mtx *= tr; + mtx *= tr_; mtx *= agg::trans_affine_scaling(common_.scale_factor_); // render the marker at the center of the marker box - mtx.translate(pos.x, pos.y); + mtx.translate(pos_.x, pos_.y); using namespace mapnik::svg; - vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + vertex_stl_adapter stl_storage(marker.get_data()->source()); svg_path_adapter svg_path(stl_storage); svg_renderer_agg, renderer_type, pixfmt_type> svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), mtx, opacity, bbox); + marker.get_data()->attributes()); + svg_renderer.render_id(*ras_ptr_, sl, renb, feature_.id(), mtx, opacity_, bbox); } - else + + void operator() (marker_rgba8 const& marker) { - image_rgba8 const& data = util::get(**marker.get_bitmap_data()); + image_rgba8 const& data = marker.get_data(); double width = data.width(); double height = data.height(); double cx = 0.5 * width; double cy = 0.5 * height; - if ((std::fabs(1.0 - common_.scale_factor_) < 0.001 && tr.is_identity())) + if ((std::fabs(1.0 - common_.scale_factor_) < 0.001 && tr_.is_identity())) { // TODO - support opacity - pixmap_.set_rectangle(feature.id(), data, - boost::math::iround(pos.x - cx), - boost::math::iround(pos.y - cy)); + pixmap_.set_rectangle(feature_.id(), data, + boost::math::iround(pos_.x - cx), + boost::math::iround(pos_.y - cy)); } else { @@ -186,11 +203,38 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ 1, 1, 0.0, 0.0, 1.0); // TODO: is 1.0 a valid default here, and do we even care in grid_renderer what the image looks like? - pixmap_.set_rectangle(feature.id(), target, - boost::math::iround(pos.x - cx), - boost::math::iround(pos.y - cy)); + pixmap_.set_rectangle(feature_.id(), target, + boost::math::iround(pos_.x - cx), + boost::math::iround(pos_.y - cy)); } } + + private: + buffer_type & pixmap_; + std::unique_ptr const& ras_ptr_; + renderer_common const& common_; + mapnik::feature_impl const& feature_; + pixel_position const& pos_; + agg::trans_affine const& tr_; + double opacity_; +}; + +template +void grid_renderer::render_marker(mapnik::feature_impl const& feature, + pixel_position const& pos, + marker const& marker, + agg::trans_affine const& tr, + double opacity, + composite_mode_e /*comp_op*/) +{ + grid_render_marker_visitor visitor(pixmap_, + ras_ptr, + common_, + feature, + pos, + tr, + opacity); + util::apply_visitor(visitor, marker); pixmap_.add_feature(feature); } diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 3bae9a101..154b9b894 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -121,21 +121,6 @@ struct thunk_renderer pixmap_.add_feature(feature_); } - void operator()(raster_marker_render_thunk const &thunk) const - { - throw std::runtime_error("Rendering of this image_gray8 type is not supported currently by the image_rgba8 renderer"); - } - - void operator()(raster_marker_render_thunk const &thunk) const - { - throw std::runtime_error("Rendering of this image_gray16 type is not supported currently by the image_rgba8 renderer"); - } - - void operator()(raster_marker_render_thunk const &thunk) const - { - throw std::runtime_error("Rendering of this image_gray32f type is not supported currently by the image_rgba8 renderer"); - } - void operator()(text_render_thunk const &thunk) const { text_renderer_type ren(pixmap_, thunk.comp_op_, common_.scale_factor_); @@ -150,7 +135,7 @@ struct thunk_renderer { ren_.render_marker(feature_, glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, thunk.opacity_, thunk.comp_op_); } diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp index 5f831c261..3a5a2e66c 100644 --- a/src/grid/process_line_pattern_symbolizer.cpp +++ b/src/grid/process_line_pattern_symbolizer.cpp @@ -53,18 +53,15 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, { std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional mark = marker_cache::instance().find(filename, true); - if (!mark) return; + mapnik::marker const& mark = marker_cache::instance().find(filename, true); + if (mark.is()) return; - if (!(*mark)->is_bitmap()) + if (!mark.is()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; return; } - boost::optional pat = (*mark)->get_bitmap_data(); - if (!pat) return; - value_bool clip = get(sym, feature, common_.vars_); value_double offset = get(sym, feature, common_.vars_); value_double simplify_tolerance = get(sym, feature, common_.vars_); @@ -84,7 +81,7 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, ras_ptr->reset(); - int stroke_width = (*pat)->width(); + int stroke_width = mark.width(); agg::trans_affine tr; auto transform = get_optional(sym, keys::geometry_transform); diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index be38f83f5..8c6a6d7dd 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -146,7 +146,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch::type; using PixMapType = typename std::tuple_element<2,RendererContext>::type; - raster_markers_rasterizer_dispatch(image_any & src, + raster_markers_rasterizer_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, @@ -167,7 +167,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_ provided that converts // the destination pixel type required. - render_raster_marker(RendererType(renb_), ras_, util::get(this->src_), this->feature_, marker_tr, opacity); + render_raster_marker(RendererType(renb_), ras_, this->src_, this->feature_, marker_tr, opacity); if (!placed_) { pixmap_.add_feature(this->feature_); diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 9dc97a0c1..bab9a7eeb 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -52,18 +52,15 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, { std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional mark = marker_cache::instance().find(filename, true); - if (!mark) return; + mapnik::marker const& mark = marker_cache::instance().find(filename, true); + if (mark.is()) return; - if (!(*mark)->is_bitmap()) + if (!mark.is()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; return; } - boost::optional pat = (*mark)->get_bitmap_data(); - if (!pat) return; - ras_ptr->reset(); value_bool clip = get(sym, feature, common_.vars_); diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 42f42dcd2..fbcbe342f 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -70,7 +70,7 @@ void grid_renderer::process(shield_symbolizer const& sym, { render_marker(feature, glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, opacity, comp_op); } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 897fab04a..7f4ba5cb9 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -62,11 +62,7 @@ marker_cache::marker_cache() "" "" ""); - image_rgba8 im(4,4,true,true); - im.set(0xff000000); - boost::optional bitmap_data = boost::optional(std::make_shared(std::move(im))); - marker_ptr mark = std::make_shared(bitmap_data); - marker_cache_.emplace("image://square",mark); + marker_cache_.emplace("image://square",mapnik::marker_rgba8()); } marker_cache::~marker_cache() {} @@ -76,7 +72,7 @@ void marker_cache::clear() #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - using iterator_type = boost::unordered_map::const_iterator; + using iterator_type = boost::unordered_map::const_iterator; iterator_type itr = marker_cache_.begin(); while(itr != marker_cache_.end()) { @@ -113,12 +109,12 @@ bool marker_cache::insert_svg(std::string const& name, std::string const& svg_st return false; } -bool marker_cache::insert_marker(std::string const& uri, marker_ptr path) +bool marker_cache::insert_marker(std::string const& uri, mapnik::marker & path) { #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - return marker_cache_.emplace(uri,path).second; + return marker_cache_.emplace(uri,std::move(path)).second; } namespace detail @@ -126,49 +122,42 @@ namespace detail struct visitor_create_marker { - template - marker_ptr operator() (T & data) + marker operator() (image_rgba8 & data) { - std::shared_ptr image = std::make_shared(data); - return std::make_shared(image); + mapnik::premultiply_alpha(data); + return mapnik::marker(mapnik::marker_rgba8(data)); + } + + marker operator() (image_null & data) + { + throw std::runtime_error("Can not make marker from null image data type"); + } + + template + marker operator() (T & data) + { + throw std::runtime_error("Can not make marker from this data type"); } }; -template<> -marker_ptr visitor_create_marker::operator() (image_rgba8 & data) -{ - std::shared_ptr image = std::make_shared(data); - mapnik::premultiply_alpha(*image); - return std::make_shared(image); -} - -template<> -marker_ptr visitor_create_marker::operator() (image_null & data) -{ - throw std::runtime_error("Can not make marker from null image data type"); -} - } // end detail ns -boost::optional marker_cache::find(std::string const& uri, - bool update_cache) +marker const& marker_cache::find(std::string const& uri, + bool update_cache) { - - boost::optional result; if (uri.empty()) { - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - using iterator_type = boost::unordered_map::const_iterator; + using iterator_type = boost::unordered_map::const_iterator; iterator_type itr = marker_cache_.find(uri); if (itr != marker_cache_.end()) { - result.reset(itr->second); - return result; + return itr->second; } try @@ -180,7 +169,7 @@ boost::optional marker_cache::find(std::string const& uri, if (mark_itr == svg_cache_.end()) { MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } std::string known_svg_string = mark_itr->second; using namespace mapnik::svg; @@ -195,11 +184,14 @@ boost::optional marker_cache::find(std::string const& uri, svg.bounding_rect(&lox, &loy, &hix, &hiy); marker_path->set_bounding_box(lox,loy,hix,hiy); marker_path->set_dimensions(svg.width(),svg.height()); - marker_ptr mark(std::make_shared(marker_path)); - result.reset(mark); if (update_cache) { - marker_cache_.emplace(uri,*result); + auto emplace_result = marker_cache_.emplace(uri,mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); + return emplace_result.first->second; + } + else + { + return std::move(mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); } } // otherwise assume file-based @@ -208,7 +200,7 @@ boost::optional marker_cache::find(std::string const& uri, if (!mapnik::util::exists(uri)) { MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } if (is_svg(uri)) { @@ -224,11 +216,14 @@ boost::optional marker_cache::find(std::string const& uri, svg.bounding_rect(&lox, &loy, &hix, &hiy); marker_path->set_bounding_box(lox,loy,hix,hiy); marker_path->set_dimensions(svg.width(),svg.height()); - marker_ptr mark(std::make_shared(marker_path)); - result.reset(mark); if (update_cache) { - marker_cache_.emplace(uri,*result); + auto emplace_result = marker_cache_.emplace(uri,mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); + return emplace_result.first->second; + } + else + { + return std::move(mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); } } else @@ -241,16 +236,20 @@ boost::optional marker_cache::find(std::string const& uri, unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); image_any im = reader->read(0,0,width,height); - marker_ptr mark(util::apply_visitor(detail::visitor_create_marker(), im)); - result.reset(mark); if (update_cache) { - marker_cache_.emplace(uri,*result); + auto emplace_result = marker_cache_.emplace(uri,util::apply_visitor(detail::visitor_create_marker(), im)); + return emplace_result.first->second; + } + else + { + return std::move(util::apply_visitor(detail::visitor_create_marker(), im)); } } else { MAPNIK_LOG_ERROR(marker_cache) << "could not intialize reader for: '" << uri << "'"; + return std::move(mapnik::marker(mapnik::marker_null())); } } } @@ -259,7 +258,7 @@ boost::optional marker_cache::find(std::string const& uri, { MAPNIK_LOG_ERROR(marker_cache) << "Exception caught while loading: '" << uri << "' (" << ex.what() << ")"; } - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } } diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index df49fc28c..eedd1e1a1 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -40,107 +40,7 @@ vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, {} template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray8 & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray8s & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray16 & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray16s & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray32 & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray32s & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray32f & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray64 & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray64s & src, - agg::trans_affine const& marker_trans, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : src_(src), tr_(marker_trans), opacity_(opacity), comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) -{} - -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_gray64f & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 const& src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -195,43 +95,10 @@ private: render_thunk_list & thunks_; }; -struct visitor_push_thunk -{ - visitor_push_thunk(render_thunk_list & thunks, - agg::trans_affine const& marker_tr, - double opacity, - composite_mode_e comp_op, - bool snap_to_pixels) - : thunks_(thunks), - marker_tr_(marker_tr), - opacity_(opacity), - comp_op_(comp_op), - snap_to_pixels_(snap_to_pixels) {} - - void operator() (image_null &) - { - throw std::runtime_error("Push thunk does not support null images"); - } - - template - void operator() (T & data) - { - raster_marker_render_thunk thunk(data, marker_tr_, opacity_, comp_op_, snap_to_pixels_); - thunks_.push_back(std::make_unique(std::move(thunk))); - } - - private: - render_thunk_list & thunks_; - agg::trans_affine const& marker_tr_; - double opacity_; - composite_mode_e comp_op_; - bool snap_to_pixels_; -}; - template struct raster_marker_thunk_dispatch : public raster_markers_dispatch { - raster_marker_thunk_dispatch(image_any & src, + raster_marker_thunk_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -249,7 +116,8 @@ struct raster_marker_thunk_dispatch : public raster_markers_dispatch void render_marker(agg::trans_affine const& marker_tr, double opacity) { - util::apply_visitor(visitor_push_thunk(thunks_, marker_tr, opacity, comp_op_, snap_to_pixels_), this->src_); + raster_marker_render_thunk thunk(this->src_, marker_tr, opacity, comp_op_, snap_to_pixels_); + thunks_.push_back(std::make_unique(std::move(thunk))); } private: diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index 39213cc0f..fc9a047a0 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -38,149 +38,36 @@ namespace mapnik { template <> -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity) +void render_pattern(rasterizer & ras, + marker_svg const& marker, + agg::trans_affine const& tr, + double opacity, + image_rgba8 & image) { using pixfmt = agg::pixfmt_rgba32_pre; using renderer_base = agg::renderer_base; using renderer_solid = agg::renderer_scanline_aa_solid; agg::scanline_u8 sl; - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; + mapnik::box2d const& bbox = marker.bounding_box() * tr; mapnik::coord c = bbox.center(); agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); mtx = tr * mtx; - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); + agg::rendering_buffer buf(image.getBytes(), image.width(), image.height(), image.getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + mapnik::svg::vertex_stl_adapter stl_storage(marker.get_data()->source()); mapnik::svg::svg_path_adapter svg_path(stl_storage); mapnik::svg::svg_renderer_agg, renderer_solid, pixfmt > svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); + marker.get_data()->attributes()); svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); - return image; } -template <> -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity) -{ - throw std::runtime_error("Can not return image_null type from render pattern"); -} -/* -template <> -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity) -{ - using pixfmt = agg::pixfmt_gray8_pre; - using renderer_base = agg::renderer_base; - using renderer_solid = agg::renderer_scanline_aa_solid; - agg::scanline_u8 sl; - - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; - mapnik::coord c = bbox.center(); - agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); - mtx = tr * mtx; - - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); - pixfmt pixf(buf); - renderer_base renb(pixf); - - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); - mapnik::svg::svg_path_adapter svg_path(stl_storage); - mapnik::svg::svg_renderer_agg, - renderer_solid, - pixfmt > svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); - return image; -} - -template <> -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity) -{ - using pixfmt = agg::pixfmt_gray16_pre; - using renderer_base = agg::renderer_base; - using renderer_solid = agg::renderer_scanline_aa_solid; - agg::scanline_u8 sl; - - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; - mapnik::coord c = bbox.center(); - agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); - mtx = tr * mtx; - - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); - pixfmt pixf(buf); - renderer_base renb(pixf); - - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); - mapnik::svg::svg_path_adapter svg_path(stl_storage); - mapnik::svg::svg_renderer_agg, - renderer_solid, - pixfmt > svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); - return image; -} - -template <> -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity) -{ - using pixfmt = agg::pixfmt_gray32_pre; - using renderer_base = agg::renderer_base; - using renderer_solid = agg::renderer_scanline_aa_solid; - agg::scanline_u8 sl; - - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; - mapnik::coord c = bbox.center(); - agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); - mtx = tr * mtx; - - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->getRowSize()); - pixfmt pixf(buf); - renderer_base renb(pixf); - - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); - mapnik::svg::svg_path_adapter svg_path(stl_storage); - mapnik::svg::svg_renderer_agg, - renderer_solid, - pixfmt > svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); - return image; -} -*/ - } // namespace mapnik diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index 8002cf305..70106de32 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -302,13 +302,13 @@ void text_symbolizer_helper::init_marker() const { std::string filename = mapnik::get(sym_, feature_, vars_); if (filename.empty()) return; - boost::optional marker = marker_cache::instance().find(filename, true); - if (!marker) return; + mapnik::marker const& marker = marker_cache::instance().find(filename, true); + if (marker.is()) return; agg::trans_affine trans; auto image_transform = get_optional(sym_, keys::image_transform); if (image_transform) evaluate_transform(trans, feature_, vars_, *image_transform); - double width = (*marker)->width(); - double height = (*marker)->height(); + double width = marker.width(); + double height = marker.height(); double px0 = - 0.5 * width; double py0 = - 0.5 * height; double px1 = 0.5 * width; @@ -329,7 +329,7 @@ void text_symbolizer_helper::init_marker() const value_double shield_dy = mapnik::get(sym_, feature_, vars_); pixel_position marker_displacement; marker_displacement.set(shield_dx,shield_dy); - finder_.set_marker(std::make_shared(*marker, trans), bbox, unlock_image, marker_displacement); + finder_.set_marker(std::make_shared(marker, trans), bbox, unlock_image, marker_displacement); } From cb869e60f32ebf01ab278e27ffa5070165b2d32b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 19 Feb 2015 01:36:43 -0800 Subject: [PATCH 88/91] no need for templated 'raster_marker_render_thunk' --- .../mapnik/renderer_common/process_group_symbolizer.hpp | 9 +++------ src/agg/process_group_symbolizer.cpp | 2 +- src/cairo/process_group_symbolizer.cpp | 2 +- src/renderer_common/process_group_symbolizer.cpp | 5 ++--- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index da5900de9..d1dbcf474 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -127,16 +127,15 @@ struct vector_marker_render_thunk : util::noncopyable snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} }; -template struct raster_marker_render_thunk : util::noncopyable { - BufferType const& src_; + image_rgba8 const& src_; agg::trans_affine tr_; double opacity_; composite_mode_e comp_op_; bool snap_to_pixels_; - raster_marker_render_thunk(BufferType const& src, + raster_marker_render_thunk(image_rgba8 const& src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -150,8 +149,6 @@ struct raster_marker_render_thunk : util::noncopyable snap_to_pixels_(std::move(rhs.snap_to_pixels_)) {} }; -template struct raster_marker_render_thunk; - using helper_ptr = std::unique_ptr; struct text_render_thunk : util::noncopyable @@ -181,7 +178,7 @@ struct text_render_thunk : util::noncopyable // via a static visitor later. using render_thunk = util::variant, + raster_marker_render_thunk, text_render_thunk>; using render_thunk_ptr = std::unique_ptr; using render_thunk_list = std::list; diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index 5ed8cae1c..df930f2ac 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -94,7 +94,7 @@ struct thunk_renderer render_vector_marker(svg_renderer, *ras_ptr_, renb, thunk.src_->bounding_box(), offset_tr, thunk.opacity_, thunk.snap_to_pixels_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender using buf_type = agg::rendering_buffer; diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index 216114347..1e46a2028 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -77,7 +77,7 @@ struct thunk_renderer thunk.opacity_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const& thunk) const { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index eedd1e1a1..3725220fb 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -39,8 +39,7 @@ vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) {} -template <> -raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 const& src, +raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 const& src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -116,7 +115,7 @@ struct raster_marker_thunk_dispatch : public raster_markers_dispatch void render_marker(agg::trans_affine const& marker_tr, double opacity) { - raster_marker_render_thunk thunk(this->src_, marker_tr, opacity, comp_op_, snap_to_pixels_); + raster_marker_render_thunk thunk(this->src_, marker_tr, opacity, comp_op_, snap_to_pixels_); thunks_.push_back(std::make_unique(std::move(thunk))); } From 2aa23eca437c3524c671d2bbeb528714b962d018 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 19 Feb 2015 01:37:19 -0800 Subject: [PATCH 89/91] fix type of raster_marker_render_thunk' --- src/grid/process_group_symbolizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 154b9b894..1931f9ce4 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -105,7 +105,7 @@ struct thunk_renderer pixmap_.add_feature(feature_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const &thunk) const { using buf_type = grid_rendering_buffer; using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; From dd0b8459f5cd5960fc34f84242ecb0f7eebd9b3b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 19 Feb 2015 01:37:45 -0800 Subject: [PATCH 90/91] insert_marker to take rvalue it if is moved inside the function --- include/mapnik/marker_cache.hpp | 2 +- src/marker_cache.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 1d835d167..40cf8048f 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -46,7 +46,7 @@ class MAPNIK_DECL marker_cache : private: marker_cache(); ~marker_cache(); - bool insert_marker(std::string const& key, marker & path); + bool insert_marker(std::string const& key, marker && path); boost::unordered_map marker_cache_; bool insert_svg(std::string const& name, std::string const& svg_string); boost::unordered_map svg_cache_; diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 7f4ba5cb9..e4daeb559 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -109,7 +109,7 @@ bool marker_cache::insert_svg(std::string const& name, std::string const& svg_st return false; } -bool marker_cache::insert_marker(std::string const& uri, mapnik::marker & path) +bool marker_cache::insert_marker(std::string const& uri, mapnik::marker && path) { #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); From 2ebce8e7e1691530f3ba5eff0f2ada26b32a885d Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Thu, 19 Feb 2015 12:19:01 -0600 Subject: [PATCH 91/91] Updated svg2png for new markers --- utils/svg2png/svg2png.cpp | 157 +++++++++++++++++++++----------------- 1 file changed, 89 insertions(+), 68 deletions(-) diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index f770cbc83..c81392710 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -50,6 +50,92 @@ #include // for xmlInitParser(), xmlCleanupParser() +struct main_marker_visitor +{ + main_marker_visitor(std::string & svg_name, + int & return_value, + bool verbose, + bool auto_open) + : svg_name_(svg_name), + return_value_(return_value), + verbose_(verbose), + auto_open_(auto_open) {} + + void operator() (mapnik::marker_null const&) + { + std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n"; + return_value_ = -1; + } + + void operator() (mapnik::marker_rgba8 const&) + { + std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n"; + return_value_ = -1; + } + + void operator() (mapnik::marker_svg const& marker) + { + using pixfmt = agg::pixfmt_rgba32_pre; + using renderer_base = agg::renderer_base; + using renderer_solid = agg::renderer_scanline_aa_solid; + agg::rasterizer_scanline_aa<> ras_ptr; + agg::scanline_u8 sl; + + double opacity = 1; + int w = marker.width(); + int h = marker.height(); + if (verbose_) + { + std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; + } + // 10 pixel buffer to avoid edge clipping of 100% svg's + mapnik::image_rgba8 im(w+0,h+0); + agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.getRowSize()); + pixfmt pixf(buf); + renderer_base renb(pixf); + + mapnik::box2d const& bbox = marker.get_data()->bounding_box(); + mapnik::coord c = bbox.center(); + // center the svg marker on '0,0' + agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); + // render the marker at the center of the marker box + mtx.translate(0.5 * im.width(), 0.5 * im.height()); + + mapnik::svg::vertex_stl_adapter stl_storage(marker.get_data()->source()); + mapnik::svg::svg_path_adapter svg_path(stl_storage); + mapnik::svg::svg_renderer_agg, + renderer_solid, + agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path, + marker.get_data()->attributes()); + + svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox); + + boost::algorithm::ireplace_last(svg_name_,".svg",".png"); + demultiply_alpha(im); + mapnik::save_to_file(im,svg_name_,"png"); + if (auto_open_) + { + std::ostringstream s; +#ifdef DARWIN + s << "open " << svg_name_; +#else + s << "xdg-open " << svg_name_; +#endif + int ret = system(s.str().c_str()); + if (ret != 0) + return_value_ = ret; + } + std::clog << "rendered to: " << svg_name_ << "\n"; + + } + + private: + std::string & svg_name_; + int & return_value_; + bool verbose_; + bool auto_open_; +}; int main (int argc,char** argv) { @@ -127,74 +213,9 @@ int main (int argc,char** argv) std::clog << "found: " << svg_name << "\n"; } - boost::optional marker_ptr = - mapnik::marker_cache::instance().find(svg_name, false); - if (!marker_ptr) - { - std::clog << "svg2png error: could not open: '" << svg_name << "'\n"; - return_value = -1; - continue; - } - mapnik::marker marker = **marker_ptr; - if (!marker.is_vector()) - { - std::clog << "svg2png error: '" << svg_name << "' is not a valid vector!\n"; - return_value = -1; - continue; - } - - using pixfmt = agg::pixfmt_rgba32_pre; - using renderer_base = agg::renderer_base; - using renderer_solid = agg::renderer_scanline_aa_solid; - agg::rasterizer_scanline_aa<> ras_ptr; - agg::scanline_u8 sl; - - double opacity = 1; - int w = marker.width(); - int h = marker.height(); - if (verbose) - { - std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; - } - // 10 pixel buffer to avoid edge clipping of 100% svg's - mapnik::image_rgba8 im(w+0,h+0); - agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.getRowSize()); - pixfmt pixf(buf); - renderer_base renb(pixf); - - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box(); - mapnik::coord c = bbox.center(); - // center the svg marker on '0,0' - agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - // render the marker at the center of the marker box - mtx.translate(0.5 * im.width(), 0.5 * im.height()); - - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); - mapnik::svg::svg_path_adapter svg_path(stl_storage); - mapnik::svg::svg_renderer_agg, - renderer_solid, - agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox); - - boost::algorithm::ireplace_last(svg_name,".svg",".png"); - demultiply_alpha(im); - mapnik::save_to_file(im,svg_name,"png"); - if (auto_open) - { - std::ostringstream s; -#ifdef DARWIN - s << "open " << svg_name; -#else - s << "xdg-open " << svg_name; -#endif - int ret = system(s.str().c_str()); - if (ret != 0) - return_value = ret; - } - std::clog << "rendered to: " << svg_name << "\n"; + mapnik::marker const& marker = mapnik::marker_cache::instance().find(svg_name, false); + main_marker_visitor visitor(svg_name, return_value, verbose, auto_open); + mapnik::util::apply_visitor(visitor, marker); } } catch (...)