[mapnik] 04/13: Imported Upstream version 3.0.3+ds

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Tue Aug 25 19:37:34 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository mapnik.

commit a8ab0b32ef54af82d31028caed5c2e034263d735
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Tue Aug 25 20:14:51 2015 +0200

    Imported Upstream version 3.0.3+ds
---
 CHANGELOG.md                                       |  21 ++
 SConstruct                                         |   4 +
 include/mapnik/geometry.hpp                        |   8 +-
 include/mapnik/geometry_adapters.hpp               |   7 +-
 include/mapnik/geometry_fusion_adapted.hpp         |   5 +-
 include/mapnik/image_filter.hpp                    | 205 ++++++++++-
 include/mapnik/image_filter_grammar_impl.hpp       |   6 +
 include/mapnik/image_filter_types.hpp              |  48 ++-
 include/mapnik/image_util_jpeg.hpp                 |   4 +-
 include/mapnik/json/geometry_generator_grammar.hpp |   2 +-
 include/mapnik/svg/svg_converter.hpp               |   4 +-
 include/mapnik/text/placement_finder.hpp           |   2 +-
 include/mapnik/util/singleton.hpp                  |   2 +
 include/mapnik/util/spirit_transform_attribute.hpp |   9 +-
 include/mapnik/version.hpp                         |   4 +-
 plugins/input/ogr/ogr_featureset.cpp               |   8 +-
 plugins/input/ogr/ogr_index_featureset.cpp         |   8 +-
 src/agg/agg_renderer.cpp                           |  15 +-
 src/agg/process_dot_symbolizer.cpp                 |   4 +-
 src/image_util_jpeg.cpp                            |  31 +-
 src/load_map.cpp                                   |   2 +-
 src/save_map.cpp                                   |   1 -
 src/text/placement_finder.cpp                      |   9 +-
 test/unit/datasource/ogr.cpp                       |  58 ++++
 test/unit/imaging/image_filter.cpp                 | 377 +++++++++++++++++++++
 test/unit/imaging/image_io_test.cpp                |  14 +
 26 files changed, 804 insertions(+), 54 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8facec3..789b725 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,27 @@ Developers: Please commit along with changes.
 
 For a complete change history, see the git log.
 
+## Future
+
+Released: YYYY XX, 2015
+
+(Packaged from xxxx)
+
+## 3.0.3
+
+Released: August 12, 2015
+
+(Packaged from 3d262c7)
+
+#### Summary
+
+- Fixed an issue with fields over size of int32 in OGR plugin (https://github.com/mapnik/node-mapnik/issues/499)
+- Added 3 new image-filters to simulate types of colorblindness (`color-blind-protanope`,`color-blind-deuteranope`,`color-blind-tritanope`)
+- Fix so that null text boxes have no bounding boxes when attempting placement ( 162f82cba5b0fb984c425586c6a4b354917abc47 )
+- Patch to add legacy method for setting JPEG quality in images ( #3024 )
+- Added `filter_image` method which can modify an image in place or return a new image that is filtered.
+- Added missing typedef's in mapnik::geometry to allow experiementing with different containers 
+
 ## 3.0.2
 
 Released: July 31, 2015
diff --git a/SConstruct b/SConstruct
index 359801d..b1c7f30 100644
--- a/SConstruct
+++ b/SConstruct
@@ -301,6 +301,7 @@ opts.AddVariables(
     ('HOST', 'Set the target host for cross compiling', ''),
     ('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG),
     BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'),
+    BoolVariable('NO_ATEXIT', 'Will prevent Singletons from being deleted atexit of main thread', 'False'),
     # http://www.scons.org/wiki/GoFastButton
     # http://stackoverflow.com/questions/1318863/how-to-optimize-an-scons-script
     BoolVariable('FAST', "Make SCons faster at the cost of less precise dependency tracking", 'False'),
@@ -1706,6 +1707,9 @@ if not preconfigured:
         if env['THREADING'] == 'multi':
             env.Append(CPPDEFINES = '-DMAPNIK_THREADSAFE')
 
+        if env['NO_ATEXIT']:
+            env.Append(CPPDEFINES = '-DMAPNIK_NO_ATEXIT')
+
         # Mac OSX (Darwin) special settings
         if env['PLATFORM'] == 'Darwin':
             pthread = ''
diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp
index 970f8dd..3766ebf 100644
--- a/include/mapnik/geometry.hpp
+++ b/include/mapnik/geometry.hpp
@@ -29,6 +29,8 @@
 #include <type_traits>
 #include <cstddef>
 
+
+
 namespace mapnik { namespace geometry {
 
 template <typename T>
@@ -91,10 +93,14 @@ struct linear_ring : line_string<T>
 };
 
 template <typename T>
+using rings_container = std::vector<linear_ring<T>>;
+
+template <typename T, template <typename> class InteriorRings = rings_container>
 struct polygon
 {
     linear_ring<T> exterior_ring;
-    std::vector<linear_ring<T>> interior_rings;
+    using rings_container = InteriorRings<T>;
+    rings_container interior_rings;
 
     polygon() = default;
     inline void set_exterior_ring(linear_ring<T> && ring)
diff --git a/include/mapnik/geometry_adapters.hpp b/include/mapnik/geometry_adapters.hpp
index 0c7a657..3f08c2b 100644
--- a/include/mapnik/geometry_adapters.hpp
+++ b/include/mapnik/geometry_adapters.hpp
@@ -47,7 +47,6 @@
 #include <mapnik/box2d.hpp>
 
 #include <cstdint>
-#include <vector>
 
 // register point
 BOOST_GEOMETRY_REGISTER_POINT_2D (mapnik::geometry::point<double>, double, boost::geometry::cs::cartesian, x, y)
@@ -180,13 +179,13 @@ struct ring_mutable_type<mapnik::geometry::polygon<CoordinateType> >
 template <typename CoordinateType>
 struct interior_const_type<mapnik::geometry::polygon<CoordinateType> >
 {
-    using type = typename std::vector<mapnik::geometry::linear_ring<CoordinateType> > const&;
+    using type = typename mapnik::geometry::polygon<CoordinateType>::rings_container const&;
 };
 
 template <typename CoordinateType>
 struct interior_mutable_type<mapnik::geometry::polygon<CoordinateType> >
 {
-    using type = typename std::vector<mapnik::geometry::linear_ring<CoordinateType> >&;
+    using type = typename mapnik::geometry::polygon<CoordinateType>::rings_container&;
 };
 
 // exterior
@@ -207,7 +206,7 @@ struct exterior_ring<mapnik::geometry::polygon<CoordinateType> >
 template <typename CoordinateType>
 struct interior_rings<mapnik::geometry::polygon<CoordinateType> >
 {
-    using holes_type = std::vector<mapnik::geometry::linear_ring<CoordinateType> >;
+    using holes_type = typename mapnik::geometry::polygon<CoordinateType>::rings_container;
     static holes_type&  get(mapnik::geometry::polygon<CoordinateType> & p)
     {
         return p.interior_rings;
diff --git a/include/mapnik/geometry_fusion_adapted.hpp b/include/mapnik/geometry_fusion_adapted.hpp
index 6889de6..e3bdd7e 100644
--- a/include/mapnik/geometry_fusion_adapted.hpp
+++ b/include/mapnik/geometry_fusion_adapted.hpp
@@ -26,7 +26,6 @@
 
 #include <mapnik/geometry.hpp>
 #include <boost/fusion/include/adapt_struct.hpp>
-#include <vector>
 
 BOOST_FUSION_ADAPT_STRUCT(
     mapnik::geometry::point<double>,
@@ -43,11 +42,11 @@ BOOST_FUSION_ADAPT_STRUCT(
 BOOST_FUSION_ADAPT_STRUCT(
     mapnik::geometry::polygon<double>,
     (mapnik::geometry::linear_ring<double> const&, exterior_ring)
-    (std::vector<mapnik::geometry::linear_ring<double> > const& , interior_rings))
+    (mapnik::geometry::polygon<double>::rings_container const& , interior_rings))
 
 BOOST_FUSION_ADAPT_STRUCT(
     mapnik::geometry::polygon<std::int64_t>,
     (mapnik::geometry::linear_ring<std::int64_t> const&, exterior_ring)
-    (std::vector<mapnik::geometry::linear_ring<std::int64_t> > const& , interior_rings))
+    (mapnik::geometry::polygon<std::int64_t>::rings_container const& , interior_rings))
 
 #endif // MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP
diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp
index 8301ade..d6ed0cd 100644
--- a/include/mapnik/image_filter.hpp
+++ b/include/mapnik/image_filter.hpp
@@ -26,6 +26,7 @@
 
 //mapnik
 #include <mapnik/image_filter_types.hpp>
+#include <mapnik/image_util.hpp>
 #include <mapnik/util/hsl.hpp>
 
 // boost GIL
@@ -394,17 +395,15 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, Filter const& fi
 template <typename Src, typename Filter>
 void apply_filter(Src & src, Filter const& filter)
 {
-    {
-        demultiply_alpha(src);
-        double_buffer<Src> tb(src);
-        apply_convolution_3x3(tb.src_view, tb.dst_view, filter);
-    } // ensure ~double_buffer() is called before premultiplying
-    premultiply_alpha(src);
+    demultiply_alpha(src);
+    double_buffer<Src> tb(src);
+    apply_convolution_3x3(tb.src_view, tb.dst_view, filter);
 }
 
 template <typename Src>
 void apply_filter(Src & src, agg_stack_blur const& op)
 {
+    premultiply_alpha(src);
     agg::rendering_buffer buf(src.bytes(),src.width(),src.height(), src.row_size());
     agg::pixfmt_rgba32_pre pixf(buf);
     agg::stack_blur_rgba32(pixf,op.rx,op.ry);
@@ -427,6 +426,7 @@ template <typename Src>
 void apply_filter(Src & src, color_to_alpha const& op)
 {
     using namespace boost::gil;
+    bool premultiplied = src.get_premultiplied();
     rgba8_view_t src_view = rgba8_view(src);
     double cr = static_cast<double>(op.color.red())/255.0;
     double cg = static_cast<double>(op.color.green())/255.0;
@@ -450,7 +450,7 @@ void apply_filter(Src & src, color_to_alpha const& op)
                 r = g = b = 0;
                 continue;
             }
-            else
+            else if (premultiplied)
             {
                 sr /= sa;
                 sg /= sa;
@@ -479,6 +479,8 @@ void apply_filter(Src & src, color_to_alpha const& op)
             }
         }
     }
+    // set as premultiplied
+    set_premultiplied_alpha(src, true);
 }
 
 template <typename Src>
@@ -509,6 +511,8 @@ void apply_filter(Src & src, colorize_alpha const& op)
                 }
             }
         }
+        // set as premultiplied
+        set_premultiplied_alpha(src, true);
     }
     else if (size > 1)
     {
@@ -584,6 +588,8 @@ void apply_filter(Src & src, colorize_alpha const& op)
                 }
             }
         }
+        // set as premultiplied
+        set_premultiplied_alpha(src, true);
     }
 }
 
@@ -597,6 +603,7 @@ void apply_filter(Src & src, scale_hsla const& transform)
     // should be run to avoid overhead of temp buffer
     if (tinting || set_alpha)
     {
+        bool premultiplied = src.get_premultiplied();
         rgba8_view_t src_view = rgba8_view(src);
         for (std::ptrdiff_t y = 0; y < src_view.height(); ++y)
         {
@@ -617,12 +624,13 @@ void apply_filter(Src & src, scale_hsla const& transform)
                     r = g = b = 0;
                     continue;
                 }
-                else
+                else if (premultiplied)
                 {
                     r2 /= a2;
                     g2 /= a2;
                     b2 /= a2;
                 }
+
                 if (set_alpha)
                 {
                     a2 = transform.a0 + (a2 * (transform.a1 - transform.a0));
@@ -671,12 +679,154 @@ void apply_filter(Src & src, scale_hsla const& transform)
                 if (b>a) b=a;
             }
         }
+        // set as premultiplied
+        set_premultiplied_alpha(src, true);
+    }
+}
+
+template <typename Src, typename ColorBlindFilter>
+void color_blind_filter(Src & src, ColorBlindFilter const& op)
+{
+    using namespace boost::gil;
+    rgba8_view_t src_view = rgba8_view(src);
+    bool premultiplied = src.get_premultiplied();
+    
+    for (std::ptrdiff_t y = 0; y < src_view.height(); ++y)
+    {
+        rgba8_view_t::x_iterator src_it = src_view.row_begin(static_cast<long>(y));
+        for (std::ptrdiff_t x = 0; x < src_view.width(); ++x)
+        {
+            // formula taken from boost/gil/color_convert.hpp:rgb_to_luminance
+            uint8_t & r = get_color(src_it[x], red_t());
+            uint8_t & g = get_color(src_it[x], green_t());
+            uint8_t & b = get_color(src_it[x], blue_t());
+            uint8_t & a = get_color(src_it[x], alpha_t());
+            double dr = static_cast<double>(r)/255.0;
+            double dg = static_cast<double>(g)/255.0;
+            double db = static_cast<double>(b)/255.0;
+            double da = static_cast<double>(a)/255.0;
+            // demultiply
+            if (da <= 0.0)
+            {
+                r = g = b = 0;
+                continue;
+            }
+            else if (premultiplied)
+            {
+                dr /= da;
+                dg /= da;
+                db /= da;
+            }
+            // Convert source color into XYZ color space
+            double pow_r = std::pow(dr, 2.2);
+            double pow_g = std::pow(dg, 2.2);
+            double pow_b = std::pow(db, 2.2);
+            double X = (0.412424 * pow_r) + (0.357579 * pow_g) + (0.180464 * pow_b);
+            double Y = (0.212656 * pow_r) + (0.715158 * pow_g) + (0.0721856 * pow_b);
+            double Z = (0.0193324 * pow_r) + (0.119193 * pow_g) + (0.950444 * pow_b);
+            // Convert XYZ into xyY Chromacity Coordinates (xy) and Luminance (Y)
+            double chroma_x = X / (X + Y + Z);
+            double chroma_y = Y / (X + Y + Z);
+            // Generate the "Confusion Line" between the source color and the Confusion Point
+            double m_div = chroma_x - op.x;
+            if (std::abs(m_div) < (std::numeric_limits<double>::epsilon())) continue;
+            double m = (chroma_y - op.y) / (chroma_x - op.x); // slope of Confusion Line
+            double yint = chroma_y - chroma_x * m; // y-intercept of confusion line (x-intercept = 0.0)
+            // How far the xy coords deviate from the simulation
+            double m_div2 = m - op.m;
+            if (std::abs(m_div2) < (std::numeric_limits<double>::epsilon())) continue;
+            double deviate_x = (op.yint - yint) / (m - op.m);
+            double deviate_y = (m * deviate_x) + yint;
+            if (std::abs(deviate_y) < (std::numeric_limits<double>::epsilon()))
+            {
+                deviate_y = std::numeric_limits<double>::epsilon() * 2.0;
+            }
+            // Compute the simulated color's XYZ coords
+            X = deviate_x * Y / deviate_y;
+            Z = (1.0 - (deviate_x + deviate_y)) * Y / deviate_y;
+            // Neutral grey calculated from luminance (in D65)
+            double neutral_X = 0.312713 * Y / 0.329016; 
+            double neutral_Z = 0.358271 * Y / 0.329016;
+            // Difference between simulated color and neutral grey
+            double diff_X = neutral_X - X;
+            double diff_Z = neutral_Z - Z;
+            double diff_r = diff_X * 3.24071 + diff_Z * -0.498571; // XYZ->RGB (sRGB:D65)
+            double diff_g = diff_X * -0.969258 + diff_Z * 0.0415557;
+            double diff_b = diff_X * 0.0556352 + diff_Z * 1.05707;
+            if (std::abs(diff_r) < (std::numeric_limits<double>::epsilon()))
+            {
+                diff_r = std::numeric_limits<double>::epsilon() * 2.0;
+            }
+            if (std::abs(diff_g) < (std::numeric_limits<double>::epsilon()))
+            {
+                diff_g = std::numeric_limits<double>::epsilon() * 2.0;
+            }
+            if (std::abs(diff_b) < (std::numeric_limits<double>::epsilon()))
+            {
+                diff_b = std::numeric_limits<double>::epsilon() * 2.0;
+            }
+            // Convert to RGB color space
+            dr = X * 3.24071 + Y * -1.53726 + Z * -0.498571; // XYZ->RGB (sRGB:D65)
+            dg = X * -0.969258 + Y * 1.87599 + Z * 0.0415557;
+            db = X * 0.0556352 + Y * -0.203996 + Z * 1.05707;            
+            // Compensate simulated color towards a neutral fit in RGB space
+            double fit_r = ((dr < 0.0 ? 0.0 : 1.0) - dr) / diff_r;
+            double fit_g = ((dg < 0.0 ? 0.0 : 1.0) - dg) / diff_g;
+            double fit_b = ((db < 0.0 ? 0.0 : 1.0) - db) / diff_b;
+            double adjust = std::max( (fit_r > 1.0 || fit_r < 0.0) ? 0.0 : fit_r, 
+                                      (fit_g > 1.0 || fit_g < 0.0) ? 0.0 : fit_g
+                                    );
+            adjust = std::max((fit_b > 1.0 || fit_b < 0.0) ? 0.0 : fit_b, adjust);
+            // Shift proportional to the greatest shift
+            dr = dr + (adjust * diff_r);
+            dg = dg + (adjust * diff_g);
+            db = db + (adjust * diff_b);
+            // Apply gamma correction
+            dr = std::pow(dr, 1.0 / 2.2);
+            dg = std::pow(dg, 1.0 / 2.2);
+            db = std::pow(db, 1.0 / 2.2);            
+            // premultiply
+            dr *= da;
+            dg *= da;
+            db *= da;
+            // Clamp values
+            if(dr < 0.0)  dr = 0.0;
+            if(dr > 1.0) dr = 1.0;
+            if(dg < 0.0) dg = 0.0;
+            if(dg > 1.0) dg = 1.0;
+            if(db < 0.0) db = 0.0;
+            if(db > 1.0) db = 1.0;
+            r = static_cast<uint8_t>(dr * 255.0);
+            g = static_cast<uint8_t>(dg * 255.0);
+            b = static_cast<uint8_t>(db * 255.0);
+        }
     }
+    // set as premultiplied
+    set_premultiplied_alpha(src, true);
+}
+
+template <typename Src>
+void apply_filter(Src & src, color_blind_protanope const& op)
+{
+    color_blind_filter(src, op);
+}
+
+template <typename Src>
+void apply_filter(Src & src, color_blind_deuteranope const& op)
+{
+    color_blind_filter(src, op);
+}
+
+template <typename Src>
+void apply_filter(Src & src, color_blind_tritanope const& op)
+{
+    color_blind_filter(src, op);
 }
 
 template <typename Src>
 void apply_filter(Src & src, gray const& /*op*/)
 {
+    premultiply_alpha(src);
     using namespace boost::gil;
 
     rgba8_view_t src_view = rgba8_view(src);
@@ -727,6 +877,7 @@ void x_gradient_impl(Src const& src_view, Dst const& dst_view)
 template <typename Src>
 void apply_filter(Src & src, x_gradient const& /*op*/)
 {
+    premultiply_alpha(src);
     double_buffer<Src> tb(src);
     x_gradient_impl(tb.src_view, tb.dst_view);
 }
@@ -734,6 +885,7 @@ void apply_filter(Src & src, x_gradient const& /*op*/)
 template <typename Src>
 void apply_filter(Src & src, y_gradient const& /*op*/)
 {
+    premultiply_alpha(src);
     double_buffer<Src> tb(src);
     x_gradient_impl(rotated90ccw_view(tb.src_view),
                     rotated90ccw_view(tb.dst_view));
@@ -742,6 +894,7 @@ void apply_filter(Src & src, y_gradient const& /*op*/)
 template <typename Src>
 void apply_filter(Src & src, invert const& /*op*/)
 {
+    premultiply_alpha(src);
     using namespace boost::gil;
 
     rgba8_view_t src_view = rgba8_view(src);
@@ -794,6 +947,40 @@ struct filter_radius_visitor
     }
 };
 
-}}
+template<typename Src>
+void filter_image(Src & src, std::string const& filter)
+{
+    std::vector<filter_type> filter_vector;
+    if(!parse_image_filters(filter, filter_vector))
+    {
+        throw std::runtime_error("Failed to parse filter argument in filter_image: '" + filter + "'");
+    }
+    filter_visitor<Src> visitor(src);
+    for (filter_type const& filter_tag : filter_vector)
+    {
+        util::apply_visitor(visitor, filter_tag);
+    }
+}
+
+template<typename Src>
+Src filter_image(Src const& src, std::string const& filter)
+{
+    std::vector<filter_type> filter_vector;
+    if(!parse_image_filters(filter, filter_vector))
+    {
+        throw std::runtime_error("Failed to parse filter argument in filter_image: '" + filter + "'");
+    }
+    Src new_src(src);
+    filter_visitor<Src> visitor(new_src);
+    for (filter_type const& filter_tag : filter_vector)
+    {
+        util::apply_visitor(visitor, filter_tag);
+    }
+    return new_src;
+}
+
+} // End Namespace Filter
+
+} // End Namespace Mapnik
 
 #endif // MAPNIK_IMAGE_FILTER_HPP
diff --git a/include/mapnik/image_filter_grammar_impl.hpp b/include/mapnik/image_filter_grammar_impl.hpp
index a9f11d8..e41f63e 100644
--- a/include/mapnik/image_filter_grammar_impl.hpp
+++ b/include/mapnik/image_filter_grammar_impl.hpp
@@ -80,6 +80,12 @@ image_filter_grammar<Iterator,ContType>::image_filter_grammar()
         |
         lit("invert") >> no_args [push_back(_val,construct<mapnik::filter::invert>())]
         |
+        lit("color-blind-protanope") >> no_args [push_back(_val,construct<mapnik::filter::color_blind_protanope>())]
+        |
+        lit("color-blind-deuteranope") >> no_args [push_back(_val,construct<mapnik::filter::color_blind_deuteranope>())]
+        |
+        lit("color-blind-tritanope") >> no_args [push_back(_val,construct<mapnik::filter::color_blind_tritanope>())]
+        |
         agg_blur_filter(_val)
         |
         scale_hsla_filter(_val)
diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp
index 5d61d1d..67e03da 100644
--- a/include/mapnik/image_filter_types.hpp
+++ b/include/mapnik/image_filter_types.hpp
@@ -55,6 +55,31 @@ struct x_gradient : image_filter_base {};
 struct y_gradient : image_filter_base {};
 struct invert : image_filter_base {};
 
+// http://vision.psychol.cam.ac.uk/jdmollon/papers/colourmaps.pdf
+struct color_blind_protanope : image_filter_base 
+{
+    const double x = 0.7465;
+    const double y = 0.2535;
+    const double m = 1.273463;
+    const double yint = -0.073894;
+};
+
+struct color_blind_deuteranope : image_filter_base
+{
+    const double x = 1.4;
+    const double y = -0.4;
+    const double m = 0.968437;
+    const double yint = 0.003331;
+};
+
+struct color_blind_tritanope : image_filter_base
+{
+    const double x = 0.1748;
+    const double y = 0.0;
+    const double m = 0.062921;
+    const double yint = 0.292119;
+};
+
 struct agg_stack_blur : image_filter_base
 {
     agg_stack_blur(unsigned rx_, unsigned ry_)
@@ -169,7 +194,10 @@ using filter_type =  util::variant<filter::blur,
                                    filter::invert,
                                    filter::scale_hsla,
                                    filter::colorize_alpha,
-                                   filter::color_to_alpha>;
+                                   filter::color_to_alpha,
+                                   filter::color_blind_protanope,
+                                   filter::color_blind_deuteranope,
+                                   filter::color_blind_tritanope>;
 
 inline std::ostream& operator<< (std::ostream& os, blur)
 {
@@ -247,6 +275,24 @@ inline std::ostream& operator<< (std::ostream& os, invert)
     return os;
 }
 
+inline std::ostream& operator<< (std::ostream& os, color_blind_protanope)
+{
+    os << "color-blind-protanope";
+    return os;
+}
+
+inline std::ostream& operator<< (std::ostream& os, color_blind_deuteranope)
+{
+    os << "color-blind-deuteranope";
+    return os;
+}
+
+inline std::ostream& operator<< (std::ostream& os, color_blind_tritanope)
+{
+    os << "color-blind-tritanope";
+    return os;
+}
+
 inline std::ostream& operator<< (std::ostream& os, colorize_alpha const& filter)
 {
     os << "colorize-alpha(";
diff --git a/include/mapnik/image_util_jpeg.hpp b/include/mapnik/image_util_jpeg.hpp
index b4d2648..b8b213a 100644
--- a/include/mapnik/image_util_jpeg.hpp
+++ b/include/mapnik/image_util_jpeg.hpp
@@ -28,7 +28,9 @@
 #include <iostream>
 
 namespace mapnik {
-
+namespace detail {
+MAPNIK_DECL int parse_jpeg_quality(std::string const& params);
+}
 struct jpeg_saver
 {
     jpeg_saver(std::ostream &, std::string const&);
diff --git a/include/mapnik/json/geometry_generator_grammar.hpp b/include/mapnik/json/geometry_generator_grammar.hpp
index 01b6318..1095d32 100644
--- a/include/mapnik/json/geometry_generator_grammar.hpp
+++ b/include/mapnik/json/geometry_generator_grammar.hpp
@@ -104,7 +104,7 @@ struct geometry_generator_grammar :
     karma::rule<OutputIterator, geometry::geometry<double> const&()> polygon;
     karma::rule<OutputIterator, geometry::polygon<double> const&()> polygon_coord;
     karma::rule<OutputIterator, geometry::linear_ring<double> const&()> exterior_ring_coord;
-    karma::rule<OutputIterator, std::vector<geometry::linear_ring<double> > const&()> interior_ring_coord;
+    karma::rule<OutputIterator, geometry::polygon<double>::rings_container const&()> interior_ring_coord;
     karma::rule<OutputIterator, geometry::geometry<double> const& ()> multi_point;
     karma::rule<OutputIterator, geometry::multi_point<double> const& ()> multi_point_coord;
     karma::rule<OutputIterator, geometry::geometry<double> const& ()> multi_linestring;
diff --git a/include/mapnik/svg/svg_converter.hpp b/include/mapnik/svg/svg_converter.hpp
index 0066a1f..27fee31 100644
--- a/include/mapnik/svg/svg_converter.hpp
+++ b/include/mapnik/svg/svg_converter.hpp
@@ -320,12 +320,12 @@ public:
         svg_height_ = h;
     }
 
-    double width()
+    double width() const
     {
         return svg_width_;
     }
 
-    double height()
+    double height() const
     {
         return svg_height_;
     }
diff --git a/include/mapnik/text/placement_finder.hpp b/include/mapnik/text/placement_finder.hpp
index 0460b2c..8bb63a7 100644
--- a/include/mapnik/text/placement_finder.hpp
+++ b/include/mapnik/text/placement_finder.hpp
@@ -74,7 +74,7 @@ private:
     // Checks for collision.
     bool collision(box2d<double> const& box, const value_unicode_string &repeat_key, bool line_placement) const;
     // Adds marker to glyph_positions and to collision detector. Returns false if there is a collision.
-    bool add_marker(glyph_positions_ptr & glyphs, pixel_position const& pos) const;
+    bool add_marker(glyph_positions_ptr & glyphs, pixel_position const& pos, std::vector<box2d<double>> & bboxes) const;
     // Maps upright==auto, left-only and right-only to left,right to simplify processing.
     // angle = angle of at start of line (to estimate best option for upright==auto)
     text_upright_e simplify_upright(text_upright_e upright, double angle) const;
diff --git a/include/mapnik/util/singleton.hpp b/include/mapnik/util/singleton.hpp
index 2c40406..e77b25b 100644
--- a/include/mapnik/util/singleton.hpp
+++ b/include/mapnik/util/singleton.hpp
@@ -119,8 +119,10 @@ template <typename T,
                     {
                         tmp = CreatePolicy<T>::create();
                         pInstance_.store(tmp, std::memory_order_release);
+#ifndef MAPNIK_NO_ATEXIT
                         // register destruction
                         std::atexit(&DestroySingleton);
+#endif
                     }
                 }
             }
diff --git a/include/mapnik/util/spirit_transform_attribute.hpp b/include/mapnik/util/spirit_transform_attribute.hpp
index e924fd8..f7fb1ca 100644
--- a/include/mapnik/util/spirit_transform_attribute.hpp
+++ b/include/mapnik/util/spirit_transform_attribute.hpp
@@ -26,7 +26,6 @@
 #include <mapnik/geometry.hpp>
 #include <mapnik/util/variant.hpp>
 
-#include <vector>
 #include <cstdint>
 
 // boost
@@ -76,9 +75,9 @@ namespace boost { namespace spirit { namespace traits {
 
     template <>
     struct transform_attribute<mapnik::geometry::polygon<double> const,
-                               std::vector<mapnik::geometry::linear_ring<double> > const&, karma::domain>
+                               mapnik::geometry::polygon<double>::rings_container const&, karma::domain>
     {
-        using type = std::vector<mapnik::geometry::linear_ring<double> > const&;
+        using type = mapnik::geometry::polygon<double>::rings_container const&;
         static type pre(mapnik::geometry::polygon<double> const& poly)
         {
             return poly.interior_rings;
@@ -164,9 +163,9 @@ namespace boost { namespace spirit { namespace traits {
 
     template <>
     struct transform_attribute<mapnik::geometry::polygon<std::int64_t> const,
-                               std::vector<mapnik::geometry::linear_ring<std::int64_t> > const&, karma::domain>
+                               mapnik::geometry::polygon<std::int64_t>::rings_container const&, karma::domain>
     {
-        using type = std::vector<mapnik::geometry::linear_ring<std::int64_t> > const&;
+        using type = mapnik::geometry::polygon<std::int64_t>::rings_container const&;
         static type pre(mapnik::geometry::polygon<std::int64_t> const& poly)
         {
             return poly.interior_rings;
diff --git a/include/mapnik/version.hpp b/include/mapnik/version.hpp
index 9e511c1..9b16040 100644
--- a/include/mapnik/version.hpp
+++ b/include/mapnik/version.hpp
@@ -27,9 +27,9 @@
 
 #define MAPNIK_MAJOR_VERSION 3
 #define MAPNIK_MINOR_VERSION 0
-#define MAPNIK_PATCH_VERSION 2
+#define MAPNIK_PATCH_VERSION 3
 
-// translates to 300001
+// translates to 300003
 #define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
 
 #ifndef MAPNIK_STRINGIFY
diff --git a/plugins/input/ogr/ogr_featureset.cpp b/plugins/input/ogr/ogr_featureset.cpp
index 3d46fcf..267ebc0 100644
--- a/plugins/input/ogr/ogr_featureset.cpp
+++ b/plugins/input/ogr/ogr_featureset.cpp
@@ -125,13 +125,17 @@ feature_ptr ogr_featureset::next()
             switch (type_oid)
             {
             case OFTInteger:
+            {
+                feature->put<mapnik::value_integer>( fld_name, poFeature->GetFieldAsInteger(i));
+                break;
+            }
 #if GDAL_VERSION_MAJOR >= 2
             case OFTInteger64:
-#endif
             {
-                feature->put<mapnik::value_integer>( fld_name, poFeature->GetFieldAsInteger(i));
+                feature->put<mapnik::value_integer>( fld_name, poFeature->GetFieldAsInteger64(i));
                 break;
             }
+#endif
 
             case OFTReal:
             {
diff --git a/plugins/input/ogr/ogr_index_featureset.cpp b/plugins/input/ogr/ogr_index_featureset.cpp
index c59ef29..9338f95 100644
--- a/plugins/input/ogr/ogr_index_featureset.cpp
+++ b/plugins/input/ogr/ogr_index_featureset.cpp
@@ -148,13 +148,17 @@ feature_ptr ogr_index_featureset<filterT>::next()
             switch (type_oid)
             {
             case OFTInteger:
+            {
+                feature->put<mapnik::value_integer>(fld_name,poFeature->GetFieldAsInteger (i));
+                break;
+            }
 #if GDAL_VERSION_MAJOR >= 2
             case OFTInteger64:
-#endif
             {
-                feature->put<mapnik::value_integer>(fld_name,poFeature->GetFieldAsInteger (i));
+                feature->put<mapnik::value_integer>( fld_name, poFeature->GetFieldAsInteger64(i));
                 break;
             }
+#endif
 
             case OFTReal:
             {
diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp
index 56e1710..74e3c93 100644
--- a/src/agg/agg_renderer.cpp
+++ b/src/agg/agg_renderer.cpp
@@ -197,7 +197,7 @@ void agg_renderer<T0,T1>::start_map_processing(Map const& map)
 }
 
 template <typename T0, typename T1>
-void agg_renderer<T0,T1>::end_map_processing(Map const& )
+void agg_renderer<T0,T1>::end_map_processing(Map const& map)
 {
     mapnik::demultiply_alpha(pixmap_);
     MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End map processing";
@@ -309,6 +309,7 @@ void agg_renderer<T0,T1>::end_style_processing(feature_type_style const& st)
             {
                 util::apply_visitor(visitor, filter_tag);
             }
+            mapnik::premultiply_alpha(*current_buffer_);
         }
         if (st.comp_op())
         {
@@ -325,11 +326,15 @@ void agg_renderer<T0,T1>::end_style_processing(feature_type_style const& st)
                       -common_.t_.offset());
         }
     }
-    // apply any 'direct' image filters
-    mapnik::filter::filter_visitor<buffer_type> visitor(pixmap_);
-    for (mapnik::filter::filter_type const& filter_tag : st.direct_image_filters())
+    if (st.direct_image_filters().size() > 0)
     {
-        util::apply_visitor(visitor, filter_tag);
+        // apply any 'direct' image filters
+        mapnik::filter::filter_visitor<buffer_type> visitor(pixmap_);
+        for (mapnik::filter::filter_type const& filter_tag : st.direct_image_filters())
+        {
+            util::apply_visitor(visitor, filter_tag);
+        }
+        mapnik::premultiply_alpha(pixmap_);
     }
     MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End processing style";
 }
diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp
index 322bfea..cc37586 100644
--- a/src/agg/process_dot_symbolizer.cpp
+++ b/src/agg/process_dot_symbolizer.cpp
@@ -106,8 +106,8 @@ void agg_renderer<T0,T1>::process(dot_symbolizer const& sym,
     {
         width = height = get<double>(sym, keys::height, feature, common_.vars_, 0.0);
     }
-    double rx = width/2.0;
-    double ry = height/2.0;
+    double rx = width/2.0 * common_.scale_factor_;
+    double ry = height/2.0 * common_.scale_factor_;
     double opacity = get<double>(sym, keys::opacity, feature, common_.vars_, 1.0);
     color const& fill = get<mapnik::color>(sym, keys::fill, feature, common_.vars_, mapnik::color(128,128,128));
     ras_ptr->reset();
diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp
index 22d6ed4..8966eb2 100644
--- a/src/image_util_jpeg.cpp
+++ b/src/image_util_jpeg.cpp
@@ -38,22 +38,29 @@
 namespace mapnik
 {
 
-jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t):
-    stream_(stream), t_(t) {}
+jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t)
+    : stream_(stream), t_(t) {}
 
-template <typename T>
-void process_rgba8_jpeg(T const& image, std::string const& type, std::ostream & stream)
+namespace detail {
+
+MAPNIK_DECL int parse_jpeg_quality(std::string const& params)
 {
-#if defined(HAVE_JPEG)
     int quality = 85;
-    if (type != "jpeg")
+    if (params != "jpeg")
     {
-        for (auto const& kv : parse_image_options(type))
+        for (auto const& kv : parse_image_options(params))
         {
             auto const& key = kv.first;
             auto const& val = kv.second;
 
             if ( key == "jpeg" ) continue;
+            else if ( key.size() > 4  && key.substr(0,4) == "jpeg")
+            {
+                if (!mapnik::util::string2int(key.substr(4), quality))
+                {
+                    throw image_writer_exception("invalid jpeg quality: '" + key.substr(4)  + "'");
+                }
+            }
             else if ( key == "quality")
             {
                 if (val && ! (*val).empty())
@@ -66,6 +73,16 @@ void process_rgba8_jpeg(T const& image, std::string const& type, std::ostream &
             }
         }
     }
+    return quality;
+}
+
+}
+
+template <typename T>
+void process_rgba8_jpeg(T const& image, std::string const& type, std::ostream & stream)
+{
+#if defined(HAVE_JPEG)
+    int quality = detail::parse_jpeg_quality(type);
     save_as_jpeg(stream, quality, image);
 #else
     throw image_writer_exception("jpeg output is not enabled in your build of Mapnik");
diff --git a/src/load_map.cpp b/src/load_map.cpp
index 44d1276..6e15ba2 100644
--- a/src/load_map.cpp
+++ b/src/load_map.cpp
@@ -196,7 +196,7 @@ void map_parser::parse_map(Map & map, xml_node const& node, std::string const& b
             {
                 map.set_background(*bgcolor);
             }
-
+            
             optional<std::string> image_filename = map_node.get_opt_attr<std::string>("background-image");
             if (image_filename)
             {
diff --git a/src/save_map.cpp b/src/save_map.cpp
index d757f9e..7ba9757 100644
--- a/src/save_map.cpp
+++ b/src/save_map.cpp
@@ -624,7 +624,6 @@ void serialize_map(ptree & pt, Map const& map, bool explicit_defaults)
         set_attr(map_node, "background-image-opacity", opacity);
     }
 
-
     int buffer_size = map.buffer_size();
     if ( buffer_size || explicit_defaults)
     {
diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp
index 53dda7d..086501e 100644
--- a/src/text/placement_finder.cpp
+++ b/src/text/placement_finder.cpp
@@ -143,7 +143,7 @@ bool placement_finder::find_point_placement(pixel_position const& pos)
         /* For point placements it is faster to just check the bounding box. */
         if (collision(bbox, layouts_.text(), false)) return false;
 
-        if (layout.num_lines()) bboxes.push_back(std::move(bbox));
+        if (layout.glyphs_count()) bboxes.push_back(std::move(bbox));
 
         pixel_position layout_offset = layout_center - glyphs->get_base_point();
         layout_offset.y = -layout_offset.y;
@@ -178,7 +178,7 @@ bool placement_finder::find_point_placement(pixel_position const& pos)
     }
 
     // add_marker first checks for collision and then updates the detector.
-    if (has_marker_ && !add_marker(glyphs, pos)) return false;
+    if (has_marker_ && !add_marker(glyphs, pos, bboxes)) return false;
 
     box2d<double> label_box;
     bool first = true;
@@ -418,14 +418,15 @@ void placement_finder::set_marker(marker_info_ptr m, box2d<double> box, bool mar
 }
 
 
-bool placement_finder::add_marker(glyph_positions_ptr & glyphs, pixel_position const& pos) const
+bool placement_finder::add_marker(glyph_positions_ptr & glyphs, pixel_position const& pos, std::vector<box2d<double>> & bboxes) const
 {
     pixel_position real_pos = (marker_unlocked_ ? pos : glyphs->get_base_point()) + marker_displacement_;
     box2d<double> bbox = marker_box_;
     bbox.move(real_pos.x, real_pos.y);
-    glyphs->set_marker(marker_, real_pos);
     if (collision(bbox, layouts_.text(), false)) return false;
     detector_.insert(bbox);
+    bboxes.push_back(std::move(bbox));
+    glyphs->set_marker(marker_, real_pos);
     return true;
 }
 
diff --git a/test/unit/datasource/ogr.cpp b/test/unit/datasource/ogr.cpp
new file mode 100644
index 0000000..3dddb85
--- /dev/null
+++ b/test/unit/datasource/ogr.cpp
@@ -0,0 +1,58 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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 "catch.hpp"
+
+#include <mapnik/map.hpp>
+#include <mapnik/load_map.hpp>
+#include <mapnik/agg_renderer.hpp>
+#include <mapnik/image.hpp>
+#include <mapnik/image_reader.hpp>
+#include <mapnik/image_util.hpp>
+#include <mapnik/font_engine_freetype.hpp>
+#include <mapnik/util/fs.hpp>
+
+TEST_CASE("ogr") {
+
+    std::string geojson_plugin("./plugins/input/ogr.input");
+    if (mapnik::util::exists(geojson_plugin))
+    {
+        SECTION("ogr point feature")
+        {
+            mapnik::Map m(256,256);
+            mapnik::load_map(m, "./test/data/good_maps/point_json.xml");
+            std::string fontdir("fonts/");
+            REQUIRE( m.register_fonts(fontdir , true ) );
+            m.zoom_all();
+            mapnik::image_rgba8 im(256,256);
+            mapnik::agg_renderer<mapnik::image_rgba8> ren(m, im);
+            ren.apply();
+            //mapnik::save_to_file(im, "./test/data/images/point_json.png");
+            std::string filename("./test/data/images/point_json.png");
+            std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename,"png"));
+            mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height());
+            mapnik::image_rgba8 expected = mapnik::util::get<mapnik::image_rgba8>(data);
+            REQUIRE(mapnik::compare(expected, im) == 0);
+        }
+
+    }
+}
diff --git a/test/unit/imaging/image_filter.cpp b/test/unit/imaging/image_filter.cpp
new file mode 100644
index 0000000..f07836d
--- /dev/null
+++ b/test/unit/imaging/image_filter.cpp
@@ -0,0 +1,377 @@
+#include "catch.hpp"
+
+// mapnik
+#include <mapnik/value.hpp>
+#include <mapnik/image_any.hpp>
+#include <mapnik/color.hpp>
+#include <mapnik/image_filter.hpp>
+#include <mapnik/image_util.hpp>
+
+TEST_CASE("image filter") {
+
+SECTION("test bad filter input") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+    
+    REQUIRE_THROWS( mapnik::filter::filter_image(im, "foo,asdfasdf()"); );
+    REQUIRE_THROWS( mapnik::filter::filter_image(im, "colorize-alpha("); );
+    REQUIRE_THROWS( mapnik::filter::filter_image(im, "color-to-alpha(blue"); );
+    REQUIRE_THROWS( mapnik::filter::filter_image(im, "color-to-alpha(,blue)"); );
+    REQUIRE_THROWS( mapnik::filter::filter_image(im, "colorize-alpha()"); );
+
+    REQUIRE_THROWS( 
+        mapnik::image_rgba8 const& im2 = im;
+        mapnik::image_rgba8 new_im = mapnik::filter::filter_image(im2, "foo");
+    );
+    
+    CHECK(im(0,0) == 0xffff0000);
+    CHECK(im(0,1) == 0xffff0000);
+    CHECK(im(0,2) == 0xffff0000);
+    CHECK(im(1,0) == 0xffff0000);
+    CHECK(im(1,1) == 0xff0000ff);
+    CHECK(im(1,2) == 0xffff0000);
+    CHECK(im(2,0) == 0xffff0000);
+    CHECK(im(2,1) == 0xffff0000);
+    CHECK(im(2,2) == 0xffff0000);
+    
+} // END SECTION
+
+SECTION("test blur") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    mapnik::filter::filter_image(im, "blur");
+
+    CHECK(im(0,0) == 0xffc60038);
+    CHECK(im(0,1) == 0xffe2001c);
+    CHECK(im(0,2) == 0xffc60038);
+    CHECK(im(1,0) == 0xffc60038);
+    CHECK(im(1,1) == 0xffe2001c);
+    CHECK(im(1,2) == 0xffc60038);
+    CHECK(im(2,0) == 0xffc60038);
+    CHECK(im(2,1) == 0xffe2001c);
+    CHECK(im(2,2) == 0xffc60038);
+    
+} // END SECTION
+
+SECTION("test blur constant") {
+    
+    mapnik::image_rgba8 im_orig(3,3);
+    mapnik::fill(im_orig,mapnik::color("blue"));
+    mapnik::set_pixel(im_orig, 1, 1, mapnik::color("red"));
+
+    mapnik::image_rgba8 const& im_new = im_orig;
+    mapnik::image_rgba8 im = mapnik::filter::filter_image(im_new, "blur");
+
+    CHECK(im(0,0) == 0xffc60038);
+    CHECK(im(0,1) == 0xffe2001c);
+    CHECK(im(0,2) == 0xffc60038);
+    CHECK(im(1,0) == 0xffc60038);
+    CHECK(im(1,1) == 0xffe2001c);
+    CHECK(im(1,2) == 0xffc60038);
+    CHECK(im(2,0) == 0xffc60038);
+    CHECK(im(2,1) == 0xffe2001c);
+    CHECK(im(2,2) == 0xffc60038);
+    
+} // END SECTION
+
+SECTION("test gray") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    mapnik::filter::filter_image(im, "gray");
+
+    CHECK(im(0,0) == 0xff1c1c1c);
+    CHECK(im(0,1) == 0xff1c1c1c);
+    CHECK(im(0,2) == 0xff1c1c1c);
+    CHECK(im(1,0) == 0xff1c1c1c);
+    CHECK(im(1,1) == 0xff4c4c4c);
+    CHECK(im(1,2) == 0xff1c1c1c);
+    CHECK(im(2,0) == 0xff1c1c1c);
+    CHECK(im(2,1) == 0xff1c1c1c);
+    CHECK(im(2,2) == 0xff1c1c1c);
+    
+} // END SECTION
+
+SECTION("test agg stack blur") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    mapnik::filter::filter_image(im, "agg-stack-blur(1,1)");
+
+    CHECK(im(0,0) == 0xffef000f);
+    CHECK(im(0,1) == 0xffdf001f);
+    CHECK(im(0,2) == 0xffef000f);
+    CHECK(im(1,0) == 0xffdf001f);
+    CHECK(im(1,1) == 0xffbf003f);
+    CHECK(im(1,2) == 0xffdf001f);
+    CHECK(im(2,0) == 0xffef000f);
+    CHECK(im(2,1) == 0xffdf001f);
+    CHECK(im(2,2) == 0xffef000f);
+
+} // END SECTION
+
+SECTION("test scale-hsla") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    // Should throw because a value is greater then 1.0
+    REQUIRE_THROWS(mapnik::filter::filter_image(im, "scale-hsla(0.0,1.5,0.0,1.0,0.0,0.5,0.0,0.5)"););
+
+    mapnik::filter::filter_image(im, "scale-hsla(0.0,0.5,0.0,1.0,0.0,0.5,0.0,0.5)");
+
+    CHECK(im(0,0) == 0x80004000);
+    CHECK(im(0,1) == 0x80004000);
+    CHECK(im(0,2) == 0x80004000);
+    CHECK(im(1,0) == 0x80004000);
+    CHECK(im(1,1) == 0x80000040);
+    CHECK(im(1,2) == 0x80004000);
+    CHECK(im(2,0) == 0x80004000);
+    CHECK(im(2,1) == 0x80004000);
+    CHECK(im(2,2) == 0x80004000);
+    
+} // END SECTION
+
+SECTION("test emboss") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("white"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("orange"));
+
+    mapnik::filter::filter_image(im, "emboss");
+
+    CHECK(im(0,0) == 0xff004bff);
+    CHECK(im(0,1) == 0xff00a5ff);
+    CHECK(im(0,2) == 0xff004bff);
+    CHECK(im(1,0) == 0xffffffff);
+    CHECK(im(1,1) == 0xff00a5ff);
+    CHECK(im(1,2) == 0xffffffff);
+    CHECK(im(2,0) == 0xffffffff);
+    CHECK(im(2,1) == 0xffffffff);
+    CHECK(im(2,2) == 0xffffffff);
+    
+} // END SECTION
+
+SECTION("test sharpen") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "sharpen");
+
+    CHECK(im(0,0) == 0xffff0000);
+    CHECK(im(0,1) == 0xffff0000);
+    CHECK(im(0,2) == 0xffff0000);
+    CHECK(im(1,0) == 0xffff0000);
+    CHECK(im(1,1) == 0xff00ffff);
+    CHECK(im(1,2) == 0xffff0000);
+    CHECK(im(2,0) == 0xffff0000);
+    CHECK(im(2,1) == 0xffff0000);
+    CHECK(im(2,2) == 0xffff0000);
+    
+} // END SECTION
+
+SECTION("test edge detect") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "edge-detect");
+
+    CHECK(im(0,0) == 0xff000000);
+    CHECK(im(0,1) == 0xff008080);
+    CHECK(im(0,2) == 0xff000000);
+    CHECK(im(1,0) == 0xff00ffff);
+    CHECK(im(1,1) == 0xffff0000);
+    CHECK(im(1,2) == 0xff00ffff);
+    CHECK(im(2,0) == 0xff000000);
+    CHECK(im(2,1) == 0xff008080);
+    CHECK(im(2,2) == 0xff000000);
+    
+} // END SECTION
+
+SECTION("test sobel") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "sobel");
+
+    CHECK(im(0,0) == 0xfffeffff);
+    CHECK(im(0,1) == 0xfffeffff);
+    CHECK(im(0,2) == 0xfffeffff);
+    CHECK(im(1,0) == 0xff000000);
+    CHECK(im(1,1) == 0xff000000);
+    CHECK(im(1,2) == 0xff000000);
+    CHECK(im(2,0) == 0xfffeffff);
+    CHECK(im(2,1) == 0xfffeffff);
+    CHECK(im(2,2) == 0xfffeffff);
+    
+} // END SECTION
+
+SECTION("test x-gradient") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "x-gradient");
+
+    CHECK(im(0,0) == 0xff808080);
+    CHECK(im(0,1) == 0xffbf4040);
+    CHECK(im(0,2) == 0xff808080);
+    CHECK(im(1,0) == 0xff808080);
+    CHECK(im(1,1) == 0xff808080);
+    CHECK(im(1,2) == 0xff808080);
+    CHECK(im(2,0) == 0xff808080);
+    CHECK(im(2,1) == 0xff41c0c0);
+    CHECK(im(2,2) == 0xff808080);
+    
+} // END SECTION
+
+SECTION("test y-gradient") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "y-gradient");
+
+    CHECK(im(0,0) == 0xff808080);
+    CHECK(im(0,1) == 0xff808080);
+    CHECK(im(0,2) == 0xff808080);
+    CHECK(im(1,0) == 0xffbf4040);
+    CHECK(im(1,1) == 0xff808080);
+    CHECK(im(1,2) == 0xff41c0c0);
+    CHECK(im(2,0) == 0xff808080);
+    CHECK(im(2,1) == 0xff808080);
+    CHECK(im(2,2) == 0xff808080);
+    
+} // END SECTION
+
+SECTION("test invert") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "invert");
+
+    CHECK(im(0,0) == 0xff00ffff);
+    CHECK(im(0,1) == 0xff00ffff);
+    CHECK(im(0,2) == 0xff00ffff);
+    CHECK(im(1,0) == 0xff00ffff);
+    CHECK(im(1,1) == 0xff7f7f7f);
+    CHECK(im(1,2) == 0xff00ffff);
+    CHECK(im(2,0) == 0xff00ffff);
+    CHECK(im(2,1) == 0xff00ffff);
+    CHECK(im(2,2) == 0xff00ffff);
+    
+} // END SECTION
+
+SECTION("test colorize-alpha - one color") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "colorize-alpha(blue)");
+
+    CHECK(im(0,0) == 0xffff0000);
+    CHECK(im(0,1) == 0xffff0000);
+    CHECK(im(0,2) == 0xffff0000);
+    CHECK(im(1,0) == 0xffff0000);
+    CHECK(im(1,1) == 0xffff0000);
+    CHECK(im(1,2) == 0xffff0000);
+    CHECK(im(2,0) == 0xffff0000);
+    CHECK(im(2,1) == 0xffff0000);
+    CHECK(im(2,2) == 0xffff0000);
+    
+} // END SECTION
+
+SECTION("test colorize-alpha - two color") {
+    
+    mapnik::image_rgba8 im(3,3);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("gray"));
+
+    mapnik::filter::filter_image(im, "colorize-alpha(green,blue)");
+
+    CHECK(im(0,0) == 0xfffc0000);
+    CHECK(im(0,1) == 0xfffc0000);
+    CHECK(im(0,2) == 0xfffc0000);
+    CHECK(im(1,0) == 0xfffc0000);
+    CHECK(im(1,1) == 0xfffc0000);
+    CHECK(im(1,2) == 0xfffc0000);
+    CHECK(im(2,0) == 0xfffc0000);
+    CHECK(im(2,1) == 0xfffc0000);
+    CHECK(im(2,2) == 0xfffc0000);
+    
+} // END SECTION
+
+SECTION("test color-blind-protanope") {
+    
+    mapnik::image_rgba8 im(2,2);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 0, 1, mapnik::color("green"));
+    mapnik::set_pixel(im, 1, 0, mapnik::color("yellow"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    mapnik::filter::filter_image(im, "color-blind-protanope");
+
+    CHECK(im(0,0) == 0xff9a4a00);
+    CHECK(im(0,1) == 0xff006e7c);
+    CHECK(im(1,0) == 0xffd9f6ff);
+    CHECK(im(1,1) == 0xff1d7e8e);
+    
+} // END SECTION
+
+SECTION("test color-blind-deuteranope") {
+    
+    mapnik::image_rgba8 im(2,2);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 0, 1, mapnik::color("green"));
+    mapnik::set_pixel(im, 1, 0, mapnik::color("yellow"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    mapnik::filter::filter_image(im, "color-blind-deuteranope");
+
+    CHECK(im(0,0) == 0xff824f00);
+    CHECK(im(0,1) == 0xff1c688b);
+    CHECK(im(1,0) == 0xffe9f5ff);
+    CHECK(im(1,1) == 0xff0077a0);
+    
+} // END SECTION
+
+SECTION("test color-blind-tritanope") {
+    
+    mapnik::image_rgba8 im(2,2);
+    mapnik::fill(im,mapnik::color("blue"));
+    mapnik::set_pixel(im, 0, 1, mapnik::color("green"));
+    mapnik::set_pixel(im, 1, 0, mapnik::color("yellow"));
+    mapnik::set_pixel(im, 1, 1, mapnik::color("red"));
+
+    mapnik::filter::filter_image(im, "color-blind-tritanope");
+
+    CHECK(im(0,0) == 0xff595500);
+    CHECK(im(0,1) == 0xff80763a);
+    CHECK(im(1,0) == 0xfff8f3ff);
+    CHECK(im(1,1) == 0xff0017fd);
+    
+} // END SECTION
+
+} // END TEST CASE
+
diff --git a/test/unit/imaging/image_io_test.cpp b/test/unit/imaging/image_io_test.cpp
index d0a984d..6daeca8 100644
--- a/test/unit/imaging/image_io_test.cpp
+++ b/test/unit/imaging/image_io_test.cpp
@@ -4,6 +4,7 @@
 #include <mapnik/image.hpp>
 #include <mapnik/image_reader.hpp>
 #include <mapnik/image_util.hpp>
+#include <mapnik/image_util_jpeg.hpp>
 #include <mapnik/util/fs.hpp>
 #include <vector>
 #include <algorithm>
@@ -41,6 +42,7 @@ SECTION("readers") {
         {
             REQUIRE( std::string(ex.what()) == std::string("JPEG Reader: libjpeg could not read image: Not a JPEG file: starts with 0x89 0x50") );
         }
+
 #endif
 
         REQUIRE_THROWS(mapnik::image_rgba8 im(-10,-10)); // should throw rather than overflow
@@ -95,5 +97,17 @@ SECTION("readers") {
 
 } // END SECTION
 
+SECTION("writers options")
+{
+#if defined(HAVE_JPEG)
+    // test we can parse both jpegXX and quality=XX options
+    REQUIRE_THROWS(mapnik::detail::parse_jpeg_quality("jpegXX"));
+    REQUIRE_THROWS(mapnik::detail::parse_jpeg_quality("jpeg:quality=XX"));
+    int q0 = mapnik::detail::parse_jpeg_quality("jpeg50");
+    int q1 = mapnik::detail::parse_jpeg_quality("jpeg:quality=50");
+    REQUIRE(q0 == q1);
+#endif
+
+} // END SECTION
 
 } // END TEST_CASE

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapnik.git



More information about the Pkg-grass-devel mailing list