From 857a6950f72f48d6a2b7f57a4812954fc445c80b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 4 Jun 2012 11:11:29 -0700 Subject: [PATCH 01/17] fix warning message for pending features for markers --- src/agg/process_markers_symbolizer.cpp | 2 +- src/cairo_renderer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 9e02e2f01..21a37d0bd 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -88,7 +88,7 @@ void agg_renderer::process(markers_symbolizer const& sym, { if (!(*mark)->is_vector()) { - MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer do not yet support SVG markers"; + MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers"; return; } diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 8b4bab54c..df7af16bb 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1387,7 +1387,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) { if (!(*mark)->is_vector()) { - MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: markers_symbolizer does not yet support SVG markers"; + MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: markers_symbolizer does not yet support non-SVG markers"; return; } From c8c2d98c0e588640763d15461e3250f9d59f3dc9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 4 Jun 2012 11:36:27 -0700 Subject: [PATCH 02/17] avoid compiler warnings with msvc --- src/box2d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/box2d.cpp b/src/box2d.cpp index 879eeb159..b7dcc2b5b 100644 --- a/src/box2d.cpp +++ b/src/box2d.cpp @@ -362,7 +362,7 @@ bool box2d::from_string(const std::string& s) if (success) { - init(d[0], d[1], d[2], d[3]); + init(static_cast(d[0]),static_cast(d[1]),static_cast(d[2]),static_cast(d[3])); } return success; From f3073f3693dd11a350d477ca5f70529d57db53fe Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 4 Jun 2012 13:41:35 -0700 Subject: [PATCH 03/17] agg/grid renderers - match cairo by using buffered detector dimensions for placement_finder collision tests --- src/agg/process_text_symbolizer.cpp | 2 +- src/grid/process_text_symbolizer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 5c16652af..9da346a48 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -35,7 +35,7 @@ void agg_renderer::process(text_symbolizer const& sym, text_symbolizer_helper, label_collision_detector4> helper( sym, *feature, prj_trans, - width_, height_, + detector_->extent().width(), detector_->extent().height(), scale_factor_, t_, font_manager_, *detector_, query_extent_); diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index 0587a9231..f943746c2 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -35,7 +35,7 @@ void grid_renderer::process(text_symbolizer const& sym, text_symbolizer_helper, label_collision_detector4> helper( sym, *feature, prj_trans, - width_, height_, + detector_.extent().width(), detector_.extent().height(), scale_factor_ * (1.0/pixmap_.get_resolution()), t_, font_manager_, detector_, query_extent); From 11e81fdb03958cdc6aca3f71770a833f00028bce Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 4 Jun 2012 13:42:51 -0700 Subject: [PATCH 04/17] finish exposing markers symbolizer in python - closes #612 --- bindings/python/mapnik_markers_symbolizer.cpp | 19 +++++++++++++++++++ include/mapnik/markers_symbolizer.hpp | 4 ++-- src/agg/process_markers_symbolizer.cpp | 6 +++--- src/cairo_renderer.cpp | 6 +++--- src/grid/process_markers_symbolizer.cpp | 6 +++--- src/load_map.cpp | 6 ++++-- src/markers_symbolizer.cpp | 4 ++-- tests/python_tests/object_test.py | 9 +++++++-- 8 files changed, 43 insertions(+), 17 deletions(-) diff --git a/bindings/python/mapnik_markers_symbolizer.cpp b/bindings/python/mapnik_markers_symbolizer.cpp index aad93b7f7..84bcf53da 100644 --- a/bindings/python/mapnik_markers_symbolizer.cpp +++ b/bindings/python/mapnik_markers_symbolizer.cpp @@ -27,6 +27,7 @@ #include #include #include "mapnik_svg.hpp" +#include "mapnik_enumeration.hpp" using mapnik::markers_symbolizer; using mapnik::symbolizer_with_image; @@ -90,6 +91,16 @@ void export_markers_symbolizer() { using namespace boost::python; + mapnik::enumeration_("marker_placement") + .value("POINT_PLACEMENT",mapnik::MARKER_POINT_PLACEMENT) + .value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT) + ; + + mapnik::enumeration_("marker_type") + .value("ARROW",mapnik::MARKER_ARROW) + .value("ELLIPSE",mapnik::MARKER_ELLIPSE) + ; + class_("MarkersSymbolizer", init<>("Default Markers Symbolizer - blue arrow")) .def (init("")) @@ -134,5 +145,13 @@ void export_markers_symbolizer() return_value_policy()), &markers_symbolizer::set_stroke, "Set/get the marker stroke (outline)") + .add_property("marker_type", + &markers_symbolizer::get_marker_type, + &markers_symbolizer::set_marker_type, + "Set/get the marker-type") + .add_property("placement", + &markers_symbolizer::get_marker_placement, + &markers_symbolizer::set_marker_placement, + "Set/get the marker placement") ; } diff --git a/include/mapnik/markers_symbolizer.hpp b/include/mapnik/markers_symbolizer.hpp index ccd249da9..f5a79cab8 100644 --- a/include/mapnik/markers_symbolizer.hpp +++ b/include/mapnik/markers_symbolizer.hpp @@ -42,8 +42,8 @@ enum marker_placement_enum { DEFINE_ENUM( marker_placement_e, marker_placement_enum ); enum marker_type_enum { - ARROW, - ELLIPSE, + MARKER_ARROW, + MARKER_ELLIPSE, marker_type_enum_MAX }; diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 21a37d0bd..df498436c 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, double dx = w + (2*strk_width); double dy = h + (2*strk_width); - if (marker_type == ARROW) + if (marker_type == MARKER_ARROW) { extent = arrow_.extent(); double x1 = extent.minx(); @@ -268,7 +268,7 @@ void agg_renderer::process(markers_symbolizer const& sym, else { - if (marker_type == ARROW) + if (marker_type == MARKER_ARROW) marker.concat_path(arrow_); clipped_geometry_type clipped(geom); @@ -284,7 +284,7 @@ void agg_renderer::process(markers_symbolizer const& sym, { agg::trans_affine matrix; - if (marker_type == ELLIPSE) + if (marker_type == MARKER_ELLIPSE) { // todo proper bbox - this is buggy agg::ellipse c(x_t, y_t, rx, ry); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index df7af16bb..1c8e87536 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1476,7 +1476,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) double dx = w + (2*strk_width); double dy = h + (2*strk_width); - if (marker_type == ARROW) + if (marker_type == MARKER_ARROW) { extent = arrow_.extent(); double x1 = extent.minx(); @@ -1543,7 +1543,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) } else { - if (marker_type == ARROW) + if (marker_type == MARKER_ARROW) marker.concat_path(arrow_); clipped_geometry_type clipped(geom); @@ -1559,7 +1559,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) { agg::trans_affine matrix; - if (marker_type == ELLIPSE) + if (marker_type == MARKER_ELLIPSE) { agg::ellipse c(x_t, y_t, rx, ry); marker.concat_path(c); diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 2170ff039..4d83e521a 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -178,7 +178,7 @@ void grid_renderer::process(markers_symbolizer const& sym, double dx = w + (2*strk_width); double dy = h + (2*strk_width); - if (marker_type == ARROW) + if (marker_type == MARKER_ARROW) { extent = arrow_.extent(); double x1 = extent.minx(); @@ -239,7 +239,7 @@ void grid_renderer::process(markers_symbolizer const& sym, { agg::path_storage marker; - if (marker_type == ARROW) + if (marker_type == MARKER_ARROW) marker.concat_path(arrow_); path_type path(t_,geom,prj_trans); @@ -253,7 +253,7 @@ void grid_renderer::process(markers_symbolizer const& sym, { agg::trans_affine matrix; - if (marker_type == ELLIPSE) + if (marker_type == MARKER_ELLIPSE) { // todo proper bbox - this is buggy agg::ellipse c(x_t, y_t, rx, ry); diff --git a/src/load_map.cpp b/src/load_map.cpp index 3944db538..27f1ea84c 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -1071,10 +1071,12 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) marker_placement_e placement = sym.get_attr("placement", MARKER_LINE_PLACEMENT); symbol.set_marker_placement(placement); - marker_type_e dfl_marker_type = ARROW; + marker_type_e dfl_marker_type = MARKER_ARROW; if (placement == MARKER_POINT_PLACEMENT) - dfl_marker_type = ELLIPSE; + { + dfl_marker_type = MARKER_ELLIPSE; + } marker_type_e marker_type = sym.get_attr("marker-type", dfl_marker_type); symbol.set_marker_type(marker_type); diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index f29741096..6c8201a1b 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -54,7 +54,7 @@ markers_symbolizer::markers_symbolizer() height_(10.0), stroke_(), marker_p_(MARKER_LINE_PLACEMENT), - marker_type_(ARROW) {} + marker_type_(MARKER_ARROW) {} markers_symbolizer::markers_symbolizer(path_expression_ptr filename) : symbolizer_with_image(filename), @@ -68,7 +68,7 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr filename) height_(10.0), stroke_(), marker_p_(MARKER_LINE_PLACEMENT), - marker_type_(ARROW) {} + marker_type_(MARKER_ARROW) {} markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) : symbolizer_with_image(rhs), diff --git a/tests/python_tests/object_test.py b/tests/python_tests/object_test.py index 563559e99..20776ed93 100644 --- a/tests/python_tests/object_test.py +++ b/tests/python_tests/object_test.py @@ -114,12 +114,18 @@ def test_pointsymbolizer_init(): eq_(p.placement, mapnik.point_placement.INTERIOR) -# PointSymbolizer initialization +# MarkersSymbolizer initialization def test_markersymbolizer_init(): p = mapnik.MarkersSymbolizer() eq_(p.allow_overlap, False) eq_(p.opacity,1) eq_(p.filename,'') + eq_(p.marker_type,mapnik.marker_type.ARROW) + eq_(p.placement,mapnik.marker_placement.LINE_PLACEMENT) + eq_(p.fill,mapnik.Color(0,0,255)) + eq_(p.ignore_placement,False) + eq_(p.spacing,100) + eq_(p.max_error,0.2) stroke = mapnik.Stroke() stroke.color = mapnik.Color('black') @@ -290,7 +296,6 @@ def test_map_init_from_string(): m.base = 'foo' mapnik.load_map_from_string(m, map_string, True, ".") eq_(m.base, '.') - raise(Todo("Need to write more map property tests in 'object_test.py'...")) except RuntimeError, e: # only test datasources that we have installed if not 'Could not create datasource' in str(e): From eb779b1580d1546e8483e8c0df436e33b2c1dcb7 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 4 Jun 2012 15:23:08 -0700 Subject: [PATCH 05/17] only link libjpeg if we are building with jpeg support --- src/build.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/build.py b/src/build.py index 7df2f8eb5..a75c0bc13 100644 --- a/src/build.py +++ b/src/build.py @@ -56,8 +56,10 @@ regex = 'boost_regex%s' % env['BOOST_APPEND'] system = 'boost_system%s' % env['BOOST_APPEND'] # clear out and re-set libs for this env -lib_env['LIBS'] = ['freetype','ltdl','png','tiff','z','jpeg','proj',env['ICU_LIB_NAME'],filesystem,system,regex] +lib_env['LIBS'] = ['freetype','ltdl','png','tiff','z','proj',env['ICU_LIB_NAME'],filesystem,system,regex] +if env['JPEG']: + lib_env['LIBS'].append('jpeg') if len(env['EXTRA_FREETYPE_LIBS']): lib_env['LIBS'].extend(copy(env['EXTRA_FREETYPE_LIBS'])) From 291bc9b8ba5db82873c501b34731ed43e64b20fe Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 4 Jun 2012 17:16:44 -0700 Subject: [PATCH 06/17] explicitly include projection header --- include/mapnik/metawriter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mapnik/metawriter.hpp b/include/mapnik/metawriter.hpp index 738137c31..693a9059a 100644 --- a/include/mapnik/metawriter.hpp +++ b/include/mapnik/metawriter.hpp @@ -26,6 +26,7 @@ // mapnik #include #include +#include // boost #include From 46c2d1c710e53224d5139c13e4763f31cee54c4a Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Tue, 6 Mar 2012 18:12:45 +0100 Subject: [PATCH 07/17] add operators for computing the envelope of a transformed box2d (cherry picked from commit 9ad342cbed150948561c08e98957bc014dedc7f3) --- include/mapnik/box2d.hpp | 17 +++++++++++++--- src/box2d.cpp | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/include/mapnik/box2d.hpp b/include/mapnik/box2d.hpp index 2f2c88127..fa52573fb 100644 --- a/include/mapnik/box2d.hpp +++ b/include/mapnik/box2d.hpp @@ -33,6 +33,12 @@ // stl #include +// agg +// forward declare so that apps using mapnik do not need agg headers +namespace agg { +struct trans_affine; +} + namespace mapnik { /*! @@ -56,6 +62,7 @@ public: box2d(T minx,T miny,T maxx,T maxy); box2d(const coord& c0,const coord& c1); box2d(const box2d_type& rhs); + box2d(const box2d_type& rhs, const agg::trans_affine& tr); T minx() const; T miny() const; T maxx() const; @@ -88,6 +95,10 @@ public: box2d_type& operator*=(T); box2d_type& operator/=(T); T operator[](int index) const; + + // compute the bounding box of this one transformed + box2d_type operator* (agg::trans_affine const& tr) const; + box2d_type& operator*=(agg::trans_affine const& tr); }; template @@ -98,9 +109,9 @@ operator << (std::basic_ostream& out, std::basic_ostringstream s; s.copyfmt(out); s.width(0); - s <<"box2d(" << std::setprecision(16) - << e.minx() << "," << e.miny() <<"," - << e.maxx() << "," << e.maxy() <<")"; + s << "box2d(" << std::setprecision(16) + << e.minx() << ',' << e.miny() << ',' + << e.maxx() << ',' << e.maxy() << ')'; out << s.str(); return out; } diff --git a/src/box2d.cpp b/src/box2d.cpp index b7dcc2b5b..faa2ef4c9 100644 --- a/src/box2d.cpp +++ b/src/box2d.cpp @@ -31,6 +31,9 @@ #include #include +// agg +#include "agg_trans_affine.h" + namespace mapnik { template @@ -61,6 +64,22 @@ box2d::box2d(const box2d &rhs) init(rhs.minx_,rhs.miny_,rhs.maxx_,rhs.maxy_); }*/ +template +box2d::box2d(const box2d_type &rhs, const agg::trans_affine& tr) +{ + double x0 = rhs.minx_, y0 = rhs.miny_; + double x1 = rhs.maxx_, y1 = rhs.miny_; + double x2 = rhs.maxx_, y2 = rhs.maxy_; + double x3 = rhs.minx_, y3 = rhs.maxy_; + tr.transform(&x0, &y0); + tr.transform(&x1, &y1); + tr.transform(&x2, &y2); + tr.transform(&x3, &y3); + init(x0, y0, x2, y2); + expand_to_include(x1, y1); + expand_to_include(x3, y3); +} + template #if !defined(__SUNPRO_CC) inline @@ -437,6 +456,29 @@ T box2d::operator[] (int index) const } } +template +box2d box2d::operator*(agg::trans_affine const& tr) const +{ + return box2d(*this, tr); +} + +template +box2d& box2d::operator*=(agg::trans_affine const& tr) +{ + double x0 = minx_, y0 = miny_; + double x1 = maxx_, y1 = miny_; + double x2 = maxx_, y2 = maxy_; + double x3 = minx_, y3 = maxy_; + tr.transform(&x0, &y0); + tr.transform(&x1, &y1); + tr.transform(&x2, &y2); + tr.transform(&x3, &y3); + init(x0, y0, x2, y2); + expand_to_include(x1, y1); + expand_to_include(x3, y3); + return *this; +} + template class box2d; template class box2d; } From d346c57e17618df168811f453aa6c0cfe098018d Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Sun, 27 May 2012 08:56:52 +0200 Subject: [PATCH 08/17] agg::trans_affine: add static const `identity`, make mul/div operators const (cherry picked from commit db47a6c9bad5828fe62b5c1c05661118e23ad218) --- deps/agg/include/agg_trans_affine.h | 9 +++++---- deps/agg/src/agg_trans_affine.cpp | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/deps/agg/include/agg_trans_affine.h b/deps/agg/include/agg_trans_affine.h index cbed7c86d..2269b1d9b 100644 --- a/deps/agg/include/agg_trans_affine.h +++ b/deps/agg/include/agg_trans_affine.h @@ -86,6 +86,7 @@ namespace agg //---------------------------------------------------------------------- struct trans_affine { + static const trans_affine identity; double sx, shy, shx, sy, tx, ty; //------------------------------------------ Construction @@ -210,15 +211,15 @@ namespace agg } // Multiply the matrix by another one and return - // the result in a separete matrix. - trans_affine operator * (const trans_affine& m) + // the result in a separate matrix. + trans_affine operator * (const trans_affine& m) const { return trans_affine(*this).multiply(m); } // Multiply the matrix by inverse of another one - // and return the result in a separete matrix. - trans_affine operator / (const trans_affine& m) + // and return the result in a separate matrix. + trans_affine operator / (const trans_affine& m) const { return trans_affine(*this).multiply_inv(m); } diff --git a/deps/agg/src/agg_trans_affine.cpp b/deps/agg/src/agg_trans_affine.cpp index 99febc953..84a1f9c1e 100644 --- a/deps/agg/src/agg_trans_affine.cpp +++ b/deps/agg/src/agg_trans_affine.cpp @@ -22,6 +22,7 @@ namespace agg { + const trans_affine trans_affine::identity; //------------------------------------------------------------------------ const trans_affine& trans_affine::parl_to_parl(const double* src, From dad0bdacfce34b7464a15252ef492defcafaa1c0 Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Sun, 27 May 2012 18:14:54 +0200 Subject: [PATCH 09/17] add value_null operators, improve is_null, move mapnik::value definition into separate namespace (cherry picked from commit 653bca6bea1abb2e45c66e76fd5e4fe7dc10a91a) --- include/mapnik/feature_kv_iterator.hpp | 16 +----- include/mapnik/value.hpp | 71 +++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/include/mapnik/feature_kv_iterator.hpp b/include/mapnik/feature_kv_iterator.hpp index 7c2f2a495..13d57eaa3 100644 --- a/include/mapnik/feature_kv_iterator.hpp +++ b/include/mapnik/feature_kv_iterator.hpp @@ -64,25 +64,11 @@ private: }; -struct is_null : public boost::static_visitor -{ - bool operator() (value_null const& val) const - { - return true; - } - - template - bool operator() (T val) const - { - return false; - } -}; - struct value_not_null { bool operator() (feature_kv_iterator::value_type const& kv) const { - return !boost::apply_visitor(is_null(),boost::get<1>(kv).base()); + return !boost::apply_visitor(is_null, boost::get<1>(kv).base()); } }; diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index 06b1bdc30..185539d3e 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -68,11 +68,28 @@ inline void to_utf8(UnicodeString const& input, std::string & target) } } -struct value_null {}; +struct value_null +{ + template + value_null operator+ (T const& other) const { return *this; } + + template + value_null operator- (T const& other) const { return *this; } + + template + value_null operator* (T const& other) const { return *this; } + + template + value_null operator/ (T const& other) const { return *this; } + + template + value_null operator% (T const& other) const { return *this; } +}; typedef boost::variant value_base; namespace impl { + struct equals : public boost::static_visitor { @@ -738,7 +755,9 @@ struct to_int : public boost::static_visitor } }; -} +} // namespace impl + +namespace value_adl_barrier { class value { @@ -796,6 +815,8 @@ public: return base_; } + bool is_null() const; + bool to_bool() const { return boost::apply_visitor(impl::to_bool(),base_); @@ -866,6 +887,52 @@ operator << (std::basic_ostream& out, out << v.to_string(); return out; } + +} // namespace value_adl_barrier + +using value_adl_barrier::value; +using value_adl_barrier::operator<<; + +namespace impl { + +struct is_null : public boost::static_visitor +{ + bool operator() (value const& val) const + { + return val.is_null(); + } + + bool operator() (value_null const& val) const + { + boost::ignore_unused_variable_warning(val); + return true; + } + + template + bool operator() (T const& val) const + { + boost::ignore_unused_variable_warning(val); + return false; + } + + template + bool operator() (boost::variant const& val) + const + { + return boost::apply_visitor(*this, val); + } +}; + +} // namespace impl + +// constant visitor instance substitutes overloaded function +impl::is_null const is_null = impl::is_null(); + +inline bool value::is_null() const +{ + return boost::apply_visitor(impl::is_null(), base_); } +} // namespace mapnik + #endif // MAPNIK_VALUE_HPP From bd9609c370dd8aed62f088e6470dd3f4b3390190 Mon Sep 17 00:00:00 2001 From: Mickey Rose Date: Sun, 27 May 2012 23:50:09 +0200 Subject: [PATCH 10/17] new feature: transform expressions are now dynamic (cherry picked from commit 173c402b5c142310087246b0ea54dbec54edcac8) Conflicts: include/mapnik/vertex_converters.hpp src/agg/process_markers_symbolizer.cpp src/agg/process_point_symbolizer.cpp src/agg/process_polygon_pattern_symbolizer.cpp src/load_map.cpp --- bindings/python/mapnik_svg.hpp | 10 +- include/mapnik/agg_renderer.hpp | 7 + include/mapnik/attribute_collector.hpp | 48 +++- include/mapnik/marker.hpp | 15 ++ include/mapnik/parse_transform.hpp | 243 ++++++++++++++++++ include/mapnik/symbolizer.hpp | 6 +- include/mapnik/symbolizer_helpers.hpp | 15 ++ include/mapnik/transform_expression.hpp | 181 +++++++++++++ .../mapnik/transform_expression_grammar.hpp | 121 +++++++++ include/mapnik/vertex_converters.hpp | 38 +-- include/mapnik/xml_tree.hpp | 2 + src/agg/agg_renderer.cpp | 62 ++++- src/agg/process_line_pattern_symbolizer.cpp | 8 +- src/agg/process_line_symbolizer.cpp | 13 +- src/agg/process_markers_symbolizer.cpp | 40 ++- src/agg/process_point_symbolizer.cpp | 33 +-- .../process_polygon_pattern_symbolizer.cpp | 8 +- src/agg/process_polygon_symbolizer.cpp | 8 +- src/agg/process_shield_symbolizer.cpp | 10 +- src/build.py | 2 + src/cairo_renderer.cpp | 34 ++- src/grid/process_markers_symbolizer.cpp | 3 +- src/grid/process_point_symbolizer.cpp | 7 +- src/load_map.cpp | 33 +-- src/parse_transform.cpp | 46 ++++ src/save_map.cpp | 30 ++- src/symbolizer.cpp | 61 +++-- src/symbolizer_helpers.cpp | 3 +- src/transform_expression.cpp | 144 +++++++++++ src/xml_tree.cpp | 3 +- 30 files changed, 1071 insertions(+), 163 deletions(-) create mode 100644 include/mapnik/parse_transform.hpp create mode 100644 include/mapnik/transform_expression.hpp create mode 100644 include/mapnik/transform_expression_grammar.hpp create mode 100644 src/parse_transform.cpp create mode 100644 src/transform_expression.cpp diff --git a/bindings/python/mapnik_svg.hpp b/bindings/python/mapnik_svg.hpp index 123abed19..b380bf39b 100644 --- a/bindings/python/mapnik_svg.hpp +++ b/bindings/python/mapnik_svg.hpp @@ -23,10 +23,14 @@ #define MAPNIK_PYTHON_BINDING_SVG_INCLUDED // mapnik +#include #include #include #include +// boost +#include + // agg #include "agg_trans_affine.h" @@ -51,9 +55,9 @@ void set_svg_transform(T& symbolizer, std::string const& transform_wkt) << "', expected SVG transform attribute"; throw mapnik::value_error(ss.str()); } - mapnik::transform_type matrix; - tr.store_to(&matrix[0]); - symbolizer.set_image_transform(matrix); + transform_list_ptr trans = boost::make_shared(); + trans->push_back(matrix_node(tr)); + symbolizer.set_image_transform(trans); } } // end of namespace mapnik diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 3fc78e961..c7a718341 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -115,6 +115,13 @@ public: void painted(bool painted); +protected: + template + void debug_draw_box(R& buf, box2d const& extent, + double x, double y, double angle = 0.0); + void debug_draw_box(box2d const& extent, + double x, double y, double angle = 0.0); + private: buffer_type & pixmap_; boost::shared_ptr internal_buffer_; diff --git a/include/mapnik/attribute_collector.hpp b/include/mapnik/attribute_collector.hpp index ce0f16a08..694765841 100644 --- a/include/mapnik/attribute_collector.hpp +++ b/include/mapnik/attribute_collector.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include // boost #include #include @@ -35,9 +36,10 @@ namespace mapnik { +template struct expression_attributes : boost::static_visitor { - explicit expression_attributes(std::set & names) + explicit expression_attributes(Container& names) : names_(names) {} void operator() (value_type const& x) const @@ -53,35 +55,35 @@ struct expression_attributes : boost::static_visitor template void operator() (binary_node const& x) const { - boost::apply_visitor(expression_attributes(names_),x.left); - boost::apply_visitor(expression_attributes(names_),x.right); + boost::apply_visitor(*this, x.left); + boost::apply_visitor(*this, x.right); } template void operator() (unary_node const& x) const { - boost::apply_visitor(expression_attributes(names_),x.expr); + boost::apply_visitor(*this, x.expr); } void operator() (regex_match_node const& x) const { - boost::apply_visitor(expression_attributes(names_),x.expr); + boost::apply_visitor(*this, x.expr); } void operator() (regex_replace_node const& x) const { - boost::apply_visitor(expression_attributes(names_),x.expr); + boost::apply_visitor(*this, x.expr); } private: - std::set& names_; + Container& names_; }; struct symbolizer_attributes : public boost::static_visitor<> { symbolizer_attributes(std::set& names) - : names_(names) {} + : names_(names), f_attr(names) {} template void operator () (T const&) const {} @@ -91,12 +93,12 @@ struct symbolizer_attributes : public boost::static_visitor<> expression_set::const_iterator it; expression_set expressions; sym.get_placement_options()->add_expressions(expressions); - expression_attributes f_attr(names_); for (it=expressions.begin(); it != expressions.end(); it++) { if (*it) boost::apply_visitor(f_attr, **it); } collect_metawriter(sym); + collect_transform(sym.get_transform()); } void operator () (point_symbolizer const& sym) @@ -107,12 +109,14 @@ struct symbolizer_attributes : public boost::static_visitor<> path_processor_type::collect_attributes(*filename_expr,names_); } collect_metawriter(sym); - + collect_transform(sym.get_image_transform()); + collect_transform(sym.get_transform()); } void operator () (line_symbolizer const& sym) { collect_metawriter(sym); + collect_transform(sym.get_transform()); } void operator () (line_pattern_symbolizer const& sym) @@ -123,11 +127,14 @@ struct symbolizer_attributes : public boost::static_visitor<> path_processor_type::collect_attributes(*filename_expr,names_); } collect_metawriter(sym); + collect_transform(sym.get_image_transform()); + collect_transform(sym.get_transform()); } void operator () (polygon_symbolizer const& sym) { collect_metawriter(sym); + collect_transform(sym.get_transform()); } void operator () (polygon_pattern_symbolizer const& sym) @@ -138,6 +145,8 @@ struct symbolizer_attributes : public boost::static_visitor<> path_processor_type::collect_attributes(*filename_expr,names_); } collect_metawriter(sym); + collect_transform(sym.get_image_transform()); + collect_transform(sym.get_transform()); } void operator () (shield_symbolizer const& sym) @@ -145,7 +154,6 @@ struct symbolizer_attributes : public boost::static_visitor<> expression_set::const_iterator it; expression_set expressions; sym.get_placement_options()->add_expressions(expressions); - expression_attributes f_attr(names_); for (it=expressions.begin(); it != expressions.end(); it++) { if (*it) boost::apply_visitor(f_attr, **it); @@ -157,11 +165,15 @@ struct symbolizer_attributes : public boost::static_visitor<> path_processor_type::collect_attributes(*filename_expr,names_); } collect_metawriter(sym); + collect_transform(sym.get_image_transform()); + collect_transform(sym.get_transform()); } void operator () (markers_symbolizer const& sym) { collect_metawriter(sym); + collect_transform(sym.get_image_transform()); + collect_transform(sym.get_transform()); } void operator () (building_symbolizer const& sym) @@ -169,20 +181,28 @@ struct symbolizer_attributes : public boost::static_visitor<> expression_ptr const& height_expr = sym.height(); if (height_expr) { - expression_attributes f_attr(names_); boost::apply_visitor(f_attr,*height_expr); } collect_metawriter(sym); + collect_transform(sym.get_transform()); } // TODO - support remaining syms private: std::set& names_; + expression_attributes > f_attr; void collect_metawriter(symbolizer_base const& sym) { metawriter_properties const& properties = sym.get_metawriter_properties(); names_.insert(properties.begin(), properties.end()); } + void collect_transform(transform_list_ptr const& trans_expr) + { + if (trans_expr) + { + transform_processor_type::collect_attributes(names_, *trans_expr); + } + } }; @@ -190,10 +210,11 @@ class attribute_collector : public boost::noncopyable { private: std::set& names_; + expression_attributes > f_attr; public: attribute_collector(std::set& names) - : names_(names) {} + : names_(names), f_attr(names) {} template void operator() (RuleType const& r) @@ -207,7 +228,6 @@ public: } expression_ptr const& expr = r.get_filter(); - expression_attributes f_attr(names_); boost::apply_visitor(f_attr,*expr); } }; diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index 0f6d316e2..d8b181ad7 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -79,6 +79,21 @@ public: { } + 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(); + } + inline double width() const { if (is_bitmap()) diff --git a/include/mapnik/parse_transform.hpp b/include/mapnik/parse_transform.hpp new file mode 100644 index 000000000..363ecc8fd --- /dev/null +++ b/include/mapnik/parse_transform.hpp @@ -0,0 +1,243 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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_PARSE_TRANSFORM_HPP +#define MAPNIK_PARSE_TRANSFORM_HPP + +// mapnik +#include +#include +#include +#include +#include +#include +#include + +// boost +#include +#include +#include +#include + +// agg +#include + +namespace mapnik { + +template struct expression_attributes; +template struct transform_expression_grammar; + +MAPNIK_DECL transform_list_ptr parse_transform(std::string const & str); +MAPNIK_DECL bool parse_transform(transform_list& list, + std::string const & str, + transform_expression_grammar const& g); + + +template +struct transform_processor +{ + typedef T feature_type; + typedef agg::trans_affine transform_type; + + template + struct attribute_collector : boost::static_visitor + { + expression_attributes collect_; + + attribute_collector(Container& names) + : collect_(names) {} + + void operator() (identity_node const& node) const + { + boost::ignore_unused_variable_warning(node); + } + + void operator() (matrix_node const& node) const + { + boost::apply_visitor(collect_, node.a_); + boost::apply_visitor(collect_, node.b_); + boost::apply_visitor(collect_, node.c_); + boost::apply_visitor(collect_, node.d_); + boost::apply_visitor(collect_, node.e_); + boost::apply_visitor(collect_, node.f_); + } + + void operator() (translate_node const& node) const + { + boost::apply_visitor(collect_, node.tx_); + boost::apply_visitor(collect_, node.ty_); + } + + void operator() (scale_node const& node) const + { + boost::apply_visitor(collect_, node.sx_); + boost::apply_visitor(collect_, node.sy_); + } + + void operator() (rotate_node const& node) const + { + boost::apply_visitor(collect_, node.angle_); + boost::apply_visitor(collect_, node.cx_); + boost::apply_visitor(collect_, node.cy_); + } + + void operator() (skewX_node const& node) const + { + boost::apply_visitor(collect_, node.angle_); + } + + void operator() (skewY_node const& node) const + { + boost::apply_visitor(collect_, node.angle_); + } + }; + + struct node_evaluator : boost::static_visitor + { + node_evaluator(transform_type& tr, feature_type const& feat) + : transform_(tr), feature_(feat) {} + + void operator() (identity_node const& node) + { + boost::ignore_unused_variable_warning(node); + } + + void operator() (matrix_node const& node) + { + double a = eval(node.a_); + double b = eval(node.b_); + double c = eval(node.c_); + double d = eval(node.d_); + double e = eval(node.e_); + double f = eval(node.f_); + transform_.multiply(agg::trans_affine(a, b, c, d, e, f)); + } + + void operator() (translate_node const& node) + { + double tx = eval(node.tx_); + double ty = eval(node.ty_, 0.0); + transform_.translate(tx, ty); + } + + void operator() (scale_node const& node) + { + double sx = eval(node.sx_); + double sy = eval(node.sy_, sx); + transform_.scale(sx, sy); + } + + void operator() (rotate_node const& node) + { + double angle = deg2rad(eval(node.angle_)); + double cx = eval(node.cx_, 0.0); + double cy = eval(node.cy_, 0.0); + transform_.translate(-cx, -cy); + transform_.rotate(angle); + transform_.translate(cx, cy); + } + + void operator() (skewX_node const& node) + { + double angle = deg2rad(eval(node.angle_)); + transform_.multiply(agg::trans_affine_skewing(angle, 0.0)); + } + + void operator() (skewY_node const& node) + { + double angle = deg2rad(eval(node.angle_)); + transform_.multiply(agg::trans_affine_skewing(0.0, angle)); + } + + private: + + static double deg2rad(double d) + { + return d * M_PI / 180.0; + } + + double eval(expr_node const& x) const + { + mapnik::evaluate e(feature_); + return boost::apply_visitor(e, x).to_double(); + } + + double eval(expr_node const& x, double def) const + { + return is_null(x) ? def : eval(x); + } + + transform_type& transform_; + feature_type const& feature_; + }; + + template + static void collect_attributes(Container& names, + transform_list const& list) + { + attribute_collector collect(names); + + BOOST_FOREACH (transform_node const& node, list) + { + boost::apply_visitor(collect, *node); + } + } + + static void evaluate(transform_type& tr, feature_type const& feat, + transform_list const& list) + { + node_evaluator eval(tr, feat); + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: begin with " << to_string(matrix_node(tr)); + #endif + + BOOST_REVERSE_FOREACH (transform_node const& node, list) + { + boost::apply_visitor(eval, *node); + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: apply " << to_string(*node); + MAPNIK_LOG_DEBUG(transform) << "transform: result " << to_string(matrix_node(tr)); + #endif + } + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: end"; + #endif + } + + static std::string to_string(transform_node const& node) + { + return to_expression_string(node); + } + + static std::string to_string(transform_list const& list) + { + return to_expression_string(list); + } +}; + +typedef mapnik::transform_processor transform_processor_type; + +} // namespace mapnik + +#endif // MAPNIK_PARSE_TRANSFORM_HPP diff --git a/include/mapnik/symbolizer.hpp b/include/mapnik/symbolizer.hpp index 08aab02b4..2141d4833 100644 --- a/include/mapnik/symbolizer.hpp +++ b/include/mapnik/symbolizer.hpp @@ -28,6 +28,7 @@ #include #include #include +#include // boost #include @@ -36,7 +37,10 @@ namespace mapnik { -typedef boost::array transform_type; +typedef transform_list_ptr transform_type; + +MAPNIK_DECL void evaluate_transform(agg::trans_affine& tr, Feature const& feature, + transform_type const& trans_expr); class Map; diff --git a/include/mapnik/symbolizer_helpers.hpp b/include/mapnik/symbolizer_helpers.hpp index 1f5980dfb..aafb8864b 100644 --- a/include/mapnik/symbolizer_helpers.hpp +++ b/include/mapnik/symbolizer_helpers.hpp @@ -150,6 +150,21 @@ public: init_marker(); } + box2d const& get_marker_extent() const + { + return marker_ext_; + } + + double get_marker_height() const + { + return marker_h_; + } + + double get_marker_width() const + { + return marker_w_; + } + bool next(); pixel_position get_marker_position(text_path const& p); marker & get_marker() const; diff --git a/include/mapnik/transform_expression.hpp b/include/mapnik/transform_expression.hpp new file mode 100644 index 000000000..b55a872ba --- /dev/null +++ b/include/mapnik/transform_expression.hpp @@ -0,0 +1,181 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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_TRANSFORM_EXPRESSION_HPP +#define MAPNIK_TRANSFORM_EXPRESSION_HPP + +// mapnik +#include + +// boost +#include +#include +#include + +// agg +#include + +// stl +#include + +namespace mapnik { + +struct identity_node {}; + +struct matrix_node +{ + expr_node a_; + expr_node b_; + expr_node c_; + expr_node d_; + expr_node e_; + expr_node f_; + + explicit matrix_node(double const* m) + : a_(m[0]), b_(m[1]), c_(m[2]), d_(m[3]), e_(m[4]), f_(m[5]) {} + + explicit matrix_node(agg::trans_affine const& m) + : a_(m.sx), b_(m.shy), c_(m.shx), d_(m.sy), e_(m.tx), f_(m.ty) {} + + matrix_node(expr_node const& a, expr_node const& b, expr_node const& c, + expr_node const& d, expr_node const& e, expr_node const& f) + : a_(a), b_(b), c_(c), d_(d), e_(e), f_(f) {} +}; + +struct translate_node +{ + expr_node tx_; + expr_node ty_; + + translate_node(expr_node const& tx, + boost::optional const& ty) + : tx_(tx) + , ty_(ty ? *ty : value_null()) {} +}; + +struct scale_node +{ + expr_node sx_; + expr_node sy_; + + scale_node(expr_node const& sx, + boost::optional const& sy) + : sx_(sx) + , sy_(sy ? *sy : value_null()) {} +}; + +struct rotate_node +{ + expr_node angle_; + expr_node cx_; + expr_node cy_; + + rotate_node(expr_node const& angle, + boost::optional const& cx, + boost::optional const& cy) + : angle_(angle) + , cx_(cx ? *cx : value_null()) + , cy_(cy ? *cy : value_null()) {} +}; + +struct skewX_node +{ + expr_node angle_; + + explicit skewX_node(expr_node const& angle) + : angle_(angle) {} +}; + +struct skewY_node +{ + expr_node angle_; + + explicit skewY_node(expr_node const& angle) + : angle_(angle) {} +}; + +namespace detail { + + // boost::spirit::traits::clear(T& val) [with T = boost::variant<...>] + // attempts to assign to the variant's current value a default-constructed + // value ot the same type, which not only requires that each value-type is + // default-constructible, but also makes little sense with our variant of + // transform nodes... + + typedef boost::variant< identity_node + , matrix_node + , translate_node + , scale_node + , rotate_node + , skewX_node + , skewY_node + > transform_variant; + + // ... thus we wrap the variant-type in a distinct type and provide + // a custom clear overload, which resets the value to identity_node + + struct transform_node + { + transform_variant base_; + + transform_node() + : base_() {} + + template + transform_node(T const& val) + : base_(val) {} + + template + transform_node& operator= (T const& val) + { + base_ = val; + return *this; + } + + transform_variant const& operator* () const + { + return base_; + } + + transform_variant& operator* () + { + return base_; + } + }; + + inline void clear(transform_node& val) + { + val.base_ = identity_node(); + } + +} // namespace detail + +typedef detail::transform_node transform_node; +typedef std::vector transform_list; +typedef boost::shared_ptr transform_list_ptr; + +MAPNIK_DECL std::string to_expression_string(transform_node const& node); +MAPNIK_DECL std::string to_expression_string(transform_list const& list); + +} // namespace mapnik + +#endif // MAPNIK_TRANSFORM_EXPRESSION_HPP diff --git a/include/mapnik/transform_expression_grammar.hpp b/include/mapnik/transform_expression_grammar.hpp new file mode 100644 index 000000000..fe09f4e5c --- /dev/null +++ b/include/mapnik/transform_expression_grammar.hpp @@ -0,0 +1,121 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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_TRANSFORM_EXPRESSION_GRAMMAR_HPP +#define MAPNIK_TRANSFORM_EXPRESSION_GRAMMAR_HPP + +// mapnik +#include +#include + +// spirit +#include +#include + +namespace mapnik { + + namespace qi = boost::spirit::qi; + + template + struct transform_expression_grammar + : qi::grammar + { + explicit transform_expression_grammar(expression_grammar const& g) + : transform_expression_grammar::base_type(start) + { + using boost::phoenix::construct; + using qi::_a; using qi::_1; using qi::_4; + using qi::_b; using qi::_2; using qi::_5; + using qi::_c; using qi::_3; using qi::_6; + using qi::_val; + using qi::char_; + using qi::lit; + using qi::no_case; + using qi::no_skip; + + start = transform_ % no_skip[char_(", ")] ; + + transform_ = matrix | translate | scale | rotate | skewX | skewY ; + + matrix = no_case[lit("matrix")] + >> (lit('(') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> lit(')')) + [ _val = construct(_1,_2,_3,_4,_5,_6) ]; + + translate = no_case[lit("translate")] + >> (lit('(') + >> expr >> -lit(',') + >> -expr >> lit(')')) + [ _val = construct(_1,_2) ]; + + scale = no_case[lit("scale")] + >> (lit('(') + >> expr >> -lit(',') + >> -expr >> lit(')')) + [ _val = construct(_1,_2) ]; + + rotate = no_case[lit("rotate")] + >> lit('(') + >> expr[_a = _1] >> -lit(',') + >> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1]) + >> lit(')') + [ _val = construct(_a,_b,_c) ]; + + skewX = no_case[lit("skewX")] + >> lit('(') + >> expr [ _val = construct(_1) ] + >> lit(')'); + + skewY = no_case[lit("skewY")] + >> lit('(') + >> expr [ _val = construct(_1) ] + >> lit(')'); + + expr = g.expr.alias(); + } + + typedef qi::locals, + boost::optional + > rotate_locals; + typedef qi::rule node_rule; + typedef qi::rule list_rule; + + // rules + typename expression_grammar::rule_type expr; + qi::rule start; + qi::rule transform_; + qi::rule matrix; + qi::rule translate; + qi::rule scale; + qi::rule rotate; + qi::rule skewX; + qi::rule skewY; + }; + +} // namespace mapnik + +#endif // MAPNIK_TRANSFORM_EXPRESSION_GRAMMAR_HPP diff --git a/include/mapnik/vertex_converters.hpp b/include/mapnik/vertex_converters.hpp index 9a6aaa420..ed57a5a03 100644 --- a/include/mapnik/vertex_converters.hpp +++ b/include/mapnik/vertex_converters.hpp @@ -120,9 +120,8 @@ struct converter_traits template static void setup(geometry_type & geom, Args const& args) { - typename boost::mpl::at >::type sym = boost::fusion::at_c<2>(args); - double scale_factor = boost::fusion::at_c<5>(args); + double scale_factor = boost::fusion::at_c<6>(args); stroke const& stroke_ = sym.get_stroke(); dash_array const& d = stroke_.get_dash_array(); dash_array::const_iterator itr = d.begin(); @@ -149,7 +148,7 @@ struct converter_traits stroke const& stroke_ = sym.get_stroke(); set_join_caps(stroke_,geom); geom.generator().miter_limit(stroke_.get_miterlimit()); - double scale_factor = boost::fusion::at_c<5>(args); + double scale_factor = boost::fusion::at_c<6>(args); geom.generator().width(stroke_.get_width() * scale_factor); } }; @@ -179,10 +178,8 @@ struct converter_traits template static void setup(geometry_type & geom, Args const& args) { - typename boost::mpl::at >::type tr = boost::fusion::at_c<3>(args); - typename boost::mpl::at >::type prj_trans = boost::fusion::at_c<4>(args); - geom.set_proj_trans(prj_trans); - geom.set_trans(tr); + geom.set_proj_trans(boost::fusion::at_c<4>(args)); + geom.set_trans(boost::fusion::at_c<3>(args)); } }; @@ -191,21 +188,19 @@ template struct converter_traits { typedef T geometry_type; + typedef agg::conv_transform + conv_base_type; - struct conv_type : public agg::conv_transform + struct conv_type : public conv_base_type { - agg::trans_affine trans_; - conv_type(geometry_type& geom) - : agg::conv_transform(geom, trans_) {} + : conv_base_type(geom, agg::trans_affine::identity) {} }; template static void setup(geometry_type & geom, Args & args) { - typename boost::mpl::at >::type sym = boost::fusion::at_c<2>(args); - boost::array const& m = sym.get_transform(); - geom.trans_.load_from(&m[0]); + geom.transformer(boost::fusion::at_c<5>(args)); } }; @@ -303,15 +298,16 @@ struct dispatcher -template +template struct vertex_converter : private boost::noncopyable { typedef C conv_types; typedef B bbox_type; typedef R rasterizer_type; typedef S symbolizer_type; - typedef P proj_trans_type; typedef T trans_type; + typedef P proj_trans_type; + typedef A affine_trans_type; typedef typename boost::fusion::vector < bbox_type const&, @@ -319,16 +315,20 @@ struct vertex_converter : private boost::noncopyable symbolizer_type const&, trans_type const&, proj_trans_type const&, + affine_trans_type const&, double //scale-factor > args_type; vertex_converter(bbox_type const& b, rasterizer_type & ras, symbolizer_type const& sym, trans_type & tr, proj_trans_type const& prj_trans, + affine_trans_type const& affine_trans, double scale_factor) - : disp_(args_type(boost::cref(b),boost::ref(ras), - boost::cref(sym),boost::cref(tr), - boost::cref(prj_trans),scale_factor)) {} + : disp_(args_type(boost::cref(b), boost::ref(ras), + boost::cref(sym), boost::cref(tr), + boost::cref(prj_trans), + boost::cref(affine_trans), + scale_factor)) {} template void apply(Geometry & geom) diff --git a/include/mapnik/xml_tree.hpp b/include/mapnik/xml_tree.hpp index d5beb9614..72dfd2c5b 100644 --- a/include/mapnik/xml_tree.hpp +++ b/include/mapnik/xml_tree.hpp @@ -26,6 +26,7 @@ #include #include #include +#include // boost #include @@ -57,6 +58,7 @@ public: mapnik::css_color_grammar color_grammar; mapnik::expression_grammar expr_grammar; path_expression_grammar path_expr_grammar; + transform_expression_grammar transform_expr_grammar; }; } //ns mapnik diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index f2bf6f0d4..0b16b3e46 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -277,7 +277,7 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar mtx *= tr; mtx *= agg::trans_affine_scaling(scale_factor_); // render the marker at the center of the marker box - mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height()); + mtx.translate(pos.x, pos.y); using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); svg_path_adapter svg_path(stl_storage); @@ -291,10 +291,12 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar } else { + double cx = 0.5 * (*marker.get_bitmap_data())->width(); + double cy = 0.5 * (*marker.get_bitmap_data())->height(); composite(current_buffer_->data(), **marker.get_bitmap_data(), comp_op, opacity, - boost::math::iround(pos.x), - boost::math::iround(pos.y), + boost::math::iround(pos.x - cx), + boost::math::iround(pos.y - cy), false, false); } } @@ -305,5 +307,57 @@ void agg_renderer::painted(bool painted) pixmap_.painted(painted); } -template class agg_renderer; +template +void agg_renderer::debug_draw_box(box2d const& box, + double x, double y, double angle) +{ + agg::rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_ * 4); + debug_draw_box(buf, box, x, y, angle); +} + +template template +void agg_renderer::debug_draw_box(R& buf, box2d const& box, + double x, double y, double angle) +{ + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + + agg::scanline_p8 sl_line; + pixfmt pixf(buf); + renderer_base renb(pixf); + renderer_type ren(renb); + + // compute tranformation matrix + agg::trans_affine_rotation tr(angle); + tr.translate(x, y); + + // prepare path + agg::path_storage pbox; + pbox.start_new_path(); + pbox.move_to(box.minx(), box.miny()); + pbox.line_to(box.maxx(), box.miny()); + pbox.line_to(box.maxx(), box.maxy()); + pbox.line_to(box.minx(), box.maxy()); + pbox.line_to(box.minx(), box.miny()); + + // prepare stroke with applied transformation + typedef agg::conv_transform conv_transform; + typedef agg::conv_stroke conv_stroke; + conv_transform tbox(pbox, tr); + conv_stroke sbox(tbox); + sbox.generator().width(1.0 * scale_factor_); + + // render the outline + ras_ptr->reset(); + ras_ptr->add_path(sbox); + ren.color(agg::rgba8(0x33, 0x33, 0xff, 0xcc)); // blue is fine + agg::render_scanlines(*ras_ptr, sl_line, ren); +} + +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_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index c33cedb02..72ad65bd1 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -94,9 +94,13 @@ void agg_renderer::process(line_pattern_symbolizer const& sym, renderer_type ren(ren_base, pattern); rasterizer_type ras(ren); + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); + typedef boost::mpl::vector conv_types; - vertex_converter,rasterizer_type,line_pattern_symbolizer, proj_transform, CoordTransform, conv_types> - converter(ext,ras,sym,t_,prj_trans,scale_factor_); + vertex_converter, rasterizer_type, line_pattern_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(ext,ras,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 32924a998..4966d4907 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -76,6 +76,9 @@ void agg_renderer::process(line_symbolizer const& sym, pixfmt_comp_type pixf(buf); renderer_base renb(pixf); + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); + if (sym.get_rasterizer() == RASTERIZER_FAST) { typedef agg::renderer_outline_aa renderer_type; @@ -89,8 +92,9 @@ void agg_renderer::process(line_symbolizer const& sym, set_join_caps_aa(stroke_,ras); typedef boost::mpl::vector conv_types; - vertex_converter,rasterizer_type,line_symbolizer, proj_transform, CoordTransform,conv_types> - converter(query_extent_,ras,sym,t_,prj_trans,scaled); + vertex_converter, rasterizer_type, line_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_,ras,sym,t_,prj_trans,tr,scaled); if (sym.clip()) converter.set(); // optional clip (default: true) converter.set(); // always transform @@ -111,8 +115,9 @@ void agg_renderer::process(line_symbolizer const& sym, else { typedef boost::mpl::vector conv_types; - vertex_converter,rasterizer,line_symbolizer, proj_transform, CoordTransform,conv_types> - converter(query_extent_,*ras_ptr,sym,t_,prj_trans,scale_factor_); + vertex_converter, rasterizer, line_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); // optional clip (default: true) converter.set(); // always transform diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index df498436c..cd23e8431 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -73,8 +73,7 @@ void agg_renderer::process(markers_symbolizer const& sym, renderer_base renb(pixf); renderer_type ren(renb); agg::trans_affine tr; - boost::array const& m = sym.get_image_transform(); - tr.load_from(&m[0]); + evaluate_transform(tr, *feature, sym.get_image_transform()); tr = agg::trans_affine_scaling(scale_factor_) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature); marker_placement_e placement_method = sym.get_marker_placement(); @@ -94,17 +93,12 @@ void agg_renderer::process(markers_symbolizer const& sym, } boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); - double x1 = bbox.minx(); - double y1 = bbox.miny(); - double x2 = bbox.maxx(); - double y2 = bbox.maxy(); - double w = (*mark)->width(); - double h = (*mark)->height(); + coord2d const center = bbox.center(); + + agg::trans_affine_translation const recenter(-center.x, -center.y); + agg::trans_affine const recenter_tr = recenter * tr; + box2d extent = bbox * recenter_tr; - agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2)); - tr.transform(&x1,&y1); - tr.transform(&x2,&y2); - box2d extent(x1,y1,x2,y2); using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker)->source()); svg_path_adapter svg_path(stl_storage); @@ -132,7 +126,11 @@ void agg_renderer::process(markers_symbolizer const& sym, detector_->has_placement(extent)) { - render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, sym.get_opacity(), sym.comp_op()); + render_marker(pixel_position(x, y), **mark, tr, sym.get_opacity(), sym.comp_op()); + + if (/* DEBUG */ 0) { + debug_draw_box(buf, extent, 0, 0, 0.0); + } // TODO - impl this for markers? //if (!sym.get_ignore_placement()) @@ -154,8 +152,22 @@ void agg_renderer::process(markers_symbolizer const& sym, while (placement.get_point(&x, &y, &angle)) { - agg::trans_affine matrix = recenter * tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y); + agg::trans_affine matrix = recenter_tr; + matrix.rotate(angle); + matrix.translate(x, y); svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(),bbox); + + if (/* DEBUG */ 0) { + agg::trans_affine_rotation r(angle); + debug_draw_box(buf, extent * r, x, y, 0.0); + // note: debug_draw_box(buf, extent, x, y, angle) + // would draw a rotated box showing the proper + // bounds of the marker, while the above will + // draw the box used for collision detection, + // which embraces the rotated extent but isn't + // rotated itself + } + if (writer.first) { //writer.first->add_box(label_ext, feature, t_, writer.second); diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 6d545e214..28acacc44 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -63,26 +63,15 @@ void agg_renderer::process(point_symbolizer const& sym, if (marker) { - double w = (*marker)->width(); - double h = (*marker)->height(); + box2d const& bbox = (*marker)->bounding_box(); + coord2d const center = bbox.center(); + agg::trans_affine tr; - boost::array const& m = sym.get_image_transform(); - tr.load_from(&m[0]); - double px0 = - 0.5 * w; - double py0 = - 0.5 * h; - double px1 = 0.5 * w; - double py1 = 0.5 * h; - double px2 = px1; - double py2 = py0; - double px3 = px0; - double py3 = py1; - tr.transform(&px0,&py0); - tr.transform(&px1,&py1); - tr.transform(&px2,&py2); - tr.transform(&px3,&py3); - box2d label_ext (px0, py0, px1, py1); - label_ext.expand_to_include(px2, py2); - label_ext.expand_to_include(px3, py3); + evaluate_transform(tr, *feature, sym.get_image_transform()); + + agg::trans_affine_translation const recenter(-center.x, -center.y); + agg::trans_affine const recenter_tr = recenter * tr; + box2d label_ext = bbox * recenter_tr; for (unsigned i=0; inum_geometries(); ++i) { @@ -103,7 +92,11 @@ void agg_renderer::process(point_symbolizer const& sym, detector_->has_placement(label_ext)) { - render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**marker,tr, sym.get_opacity(), sym.comp_op()); + render_marker(pixel_position(x, y), **marker, tr, sym.get_opacity(), sym.comp_op()); + + if (/* DEBUG */ 0) { + debug_draw_box(label_ext, 0, 0, 0.0); + } if (!sym.get_ignore_placement()) detector_->insert(label_ext); diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 62a382174..6833c1aa3 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -136,10 +136,14 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, agg::span_allocator sa; renderer_type rp(renb,sa, sg); + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); + box2d inflated_extent = query_extent_ * 1.0; typedef boost::mpl::vector conv_types; - vertex_converter,rasterizer,polygon_pattern_symbolizer, proj_transform, CoordTransform,conv_types> - converter(inflated_extent,*ras_ptr,sym,t_,prj_trans, scale_factor_); + vertex_converter, rasterizer, polygon_pattern_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index 7e7c92c95..9998cecae 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -50,9 +50,13 @@ void agg_renderer::process(polygon_symbolizer const& sym, box2d inflated_extent = query_extent_ * 1.0; + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); + typedef boost::mpl::vector conv_types; - vertex_converter,rasterizer,polygon_symbolizer, proj_transform, CoordTransform,conv_types> - converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,scale_factor_); + vertex_converter, rasterizer, polygon_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index db38b5778..a8d8ccf46 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -52,7 +52,15 @@ void agg_renderer::process(shield_symbolizer const& sym, placements_type &placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - render_marker(helper.get_marker_position(placements[ii]), + // get_marker_position returns (minx,miny) corner position, + // while (currently only) agg_renderer::render_marker newly + // expects center position; + // until all renderers and shield_symbolizer_helper are + // modified accordingly, we must adjust the position here + pixel_position pos = helper.get_marker_position(placements[ii]); + pos.x += 0.5 * helper.get_marker_width(); + pos.y += 0.5 * helper.get_marker_height(); + render_marker(pos, helper.get_marker(), helper.get_image_transform(), sym.get_opacity(), diff --git a/src/build.py b/src/build.py index a75c0bc13..2e0e8183f 100644 --- a/src/build.py +++ b/src/build.py @@ -110,6 +110,7 @@ source = Split( deepcopy.cpp expression_string.cpp expression.cpp + transform_expression.cpp feature_kv_iterator.cpp feature_type_style.cpp font_engine_freetype.cpp @@ -126,6 +127,7 @@ source = Split( load_map.cpp memory.cpp parse_path.cpp + parse_transform.cpp palette.cpp placement_finder.cpp plugin.cpp diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 1c8e87536..958faa4ee 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -833,9 +833,13 @@ void cairo_renderer_base::start_map_processing(Map const& map) context.set_operator(sym.comp_op()); context.set_color(sym.get_fill(), sym.get_opacity()); + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); + typedef boost::mpl::vector conv_types; - vertex_converter,cairo_context,polygon_symbolizer, proj_transform, CoordTransform, conv_types> - converter(query_extent_,context,sym,t_,prj_trans,1.0); + vertex_converter, cairo_context, polygon_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_,context,sym,t_,prj_trans,tr,1.0); if (sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform @@ -980,10 +984,13 @@ void cairo_renderer_base::start_map_processing(Map const& map) context.set_dash(stroke_.get_dash_array()); } + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); typedef boost::mpl::vector conv_types; - vertex_converter,cairo_context,line_symbolizer, proj_transform, CoordTransform,conv_types> - converter(query_extent_,context ,sym,t_,prj_trans,1.0); + vertex_converter, cairo_context, line_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_,context,sym,t_,prj_trans,tr,1.0); if (sym.clip()) converter.set(); // optional clip (default: true) converter.set(); // always transform @@ -1131,6 +1138,9 @@ void cairo_renderer_base::start_map_processing(Map const& map) marker.reset(boost::make_shared()); } + agg::trans_affine mtx; + evaluate_transform(mtx, *feature, sym.get_image_transform()); + if (marker) { for (unsigned i = 0; i < feature->num_geometries(); ++i) @@ -1157,10 +1167,6 @@ void cairo_renderer_base::start_map_processing(Map const& map) if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { - agg::trans_affine mtx; - boost::array const& m = sym.get_image_transform(); - mtx.load_from(&m[0]); - render_marker(pixel_position(px,py),**marker, mtx, sym.get_opacity()); if (!sym.get_ignore_placement()) @@ -1293,9 +1299,13 @@ void cairo_renderer_base::start_map_processing(Map const& map) context.set_pattern(pattern); + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_transform()); + typedef boost::mpl::vector conv_types; - vertex_converter,cairo_context,polygon_pattern_symbolizer, proj_transform, CoordTransform, conv_types> - converter(query_extent_,context,sym,t_,prj_trans,1.0); + vertex_converter, cairo_context, polygon_pattern_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_,context,sym,t_,prj_trans,tr,1.0); if (sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform @@ -1371,8 +1381,8 @@ void cairo_renderer_base::start_map_processing(Map const& map) typedef coord_transform path_type; agg::trans_affine tr; - boost::array const& m = sym.get_image_transform(); - tr.load_from(&m[0]); + evaluate_transform(tr, *feature, sym.get_image_transform()); + // TODO - use this? //tr = agg::trans_affine_scaling(scale_factor_) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature); diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 4d83e521a..b41bfc1c1 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -69,8 +69,7 @@ void grid_renderer::process(markers_symbolizer const& sym, ras_ptr->reset(); agg::trans_affine tr; - boost::array const& m = sym.get_image_transform(); - tr.load_from(&m[0]); + evaluate_transform(tr, *feature, sym.get_image_transform()); unsigned int res = pixmap_.get_resolution(); tr = agg::trans_affine_scaling(scale_factor_*(1.0/res)) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), *feature); diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index b5667469e..a17a86842 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -55,6 +55,9 @@ void grid_renderer::process(point_symbolizer const& sym, if (marker) { + agg::trans_affine tr; + evaluate_transform(tr, *feature, sym.get_image_transform()); + for (unsigned i=0; inum_geometries(); ++i) { geometry_type const& geom = feature->get_geometry(i); @@ -78,10 +81,6 @@ void grid_renderer::process(point_symbolizer const& sym, if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { - agg::trans_affine tr; - boost::array const& m = sym.get_image_transform(); - tr.load_from(&m[0]); - render_marker(feature, pixmap_.get_resolution(), pixel_position(px, py), **marker, tr, diff --git a/src/load_map.cpp b/src/load_map.cpp index 27f1ea84c..bc9a1e5f3 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include @@ -838,8 +839,8 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) optional transform_wkt = pt.get_opt_attr("transform"); if (transform_wkt) { - agg::trans_affine tr; - if (!mapnik::svg::parse_transform((*transform_wkt).c_str(),tr)) + mapnik::transform_list_ptr tl = boost::make_shared(); + if (!mapnik::parse_transform(*tl, *transform_wkt, pt.get_tree().transform_expr_grammar)) { std::stringstream ss; ss << "Could not parse transform from '" << transform_wkt << "', expected SVG transform attribute"; @@ -848,9 +849,7 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) else std::clog << "### WARNING: " << ss.str() << endl; } - boost::array matrix; - tr.store_to(&matrix[0]); - sym.set_transform(matrix); + sym.set_transform(tl); } optional clip = pt.get_opt_attr("clip"); @@ -919,8 +918,8 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) optional image_transform_wkt = sym.get_opt_attr("image-transform"); if (image_transform_wkt) { - agg::trans_affine tr; - if (!mapnik::svg::parse_transform((*image_transform_wkt).c_str(),tr)) + mapnik::transform_list_ptr tl = boost::make_shared(); + if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) { std::stringstream ss; ss << "Could not parse transform from '" << *image_transform_wkt @@ -934,9 +933,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; } } - boost::array matrix; - tr.store_to(&matrix[0]); - symbol.set_image_transform(matrix); + symbol.set_image_transform(tl); } } catch (image_reader_exception const & ex) @@ -1014,8 +1011,8 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) optional image_transform_wkt = sym.get_opt_attr("image-transform"); if (image_transform_wkt) { - agg::trans_affine tr; - if (!mapnik::svg::parse_transform((*image_transform_wkt).c_str(),tr)) + mapnik::transform_list_ptr tl = boost::make_shared(); + if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) { std::stringstream ss; ss << "Could not parse transform from '" << *image_transform_wkt @@ -1029,9 +1026,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; } } - boost::array matrix; - tr.store_to(&matrix[0]); - symbol.set_image_transform(matrix); + symbol.set_image_transform(tl); } optional c = sym.get_opt_attr("fill"); @@ -1257,8 +1252,8 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) optional image_transform_wkt = sym.get_opt_attr("image-transform"); if (image_transform_wkt) { - agg::trans_affine tr; - if (!mapnik::svg::parse_transform((*image_transform_wkt).c_str(),tr)) + mapnik::transform_list_ptr tl = boost::make_shared(); + if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) { std::stringstream ss; ss << "Could not parse transform from '" << *image_transform_wkt @@ -1272,9 +1267,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; } } - boost::array matrix; - tr.store_to(&matrix[0]); - shield_symbol.set_image_transform(matrix); + shield_symbol.set_image_transform(tl); } // shield displacement diff --git a/src/parse_transform.cpp b/src/parse_transform.cpp new file mode 100644 index 000000000..3b4ede837 --- /dev/null +++ b/src/parse_transform.cpp @@ -0,0 +1,46 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 { + +bool parse_transform(transform_list& transform, + std::string const & str, + transform_expression_grammar const& g) +{ + std::string::const_iterator itr = str.begin(); + std::string::const_iterator end = str.end(); + bool r = qi::phrase_parse(itr, end, g, space_type(), transform); + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(load_map) << "map_parser: Parsed transform [ " + << transform_processor_type::to_string(transform) << " ]"; + #endif + + return (r && itr==end); +} + +} diff --git a/src/save_map.cpp b/src/save_map.cpp index 6b30aa03d..15e9cf127 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -244,8 +244,10 @@ public: { set_attr( sym_node, "fill-opacity", sym.get_opacity() ); } - - set_attr( sym_node, "height", to_expression_string(*sym.height()) ); + if (sym.height()) + { + set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) ); + } add_metawriter_attributes(sym_node, sym); } @@ -255,8 +257,9 @@ public: ptree & sym_node = rule_.push_back( ptree::value_type("MarkersSymbolizer", ptree()))->second; markers_symbolizer dfl(parse_path("")); //TODO: Parameter? - std::string const& filename = path_processor_type::to_string( *sym.get_filename()); - if ( ! filename.empty() ) { + if (sym.get_filename()) + { + std::string filename = path_processor_type::to_string(*sym.get_filename()); set_attr( sym_node, "file", filename ); } if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_) @@ -299,9 +302,9 @@ public: { set_attr( sym_node, "placement", sym.get_marker_placement() ); } - std::string tr_str = sym.get_image_transform_string(); - if (tr_str != "matrix(1, 0, 0, 1, 0, 0)" || explicit_defaults_ ) + if (sym.get_image_transform()) { + std::string tr_str = sym.get_image_transform_string(); set_attr( sym_node, "image-transform", tr_str ); } @@ -349,8 +352,9 @@ private: void add_image_attributes(ptree & node, const symbolizer_with_image & sym) { - std::string const& filename = path_processor_type::to_string( *sym.get_filename()); - if ( ! filename.empty() ) { + if (sym.get_filename()) + { + std::string filename = path_processor_type::to_string( *sym.get_filename()); set_attr( node, "file", filename ); } if (sym.get_opacity() != 1.0 || explicit_defaults_ ) @@ -358,6 +362,7 @@ private: set_attr( node, "opacity", sym.get_opacity() ); } } + void add_font_attributes(ptree & node, const text_symbolizer & sym) { text_placements_ptr p = sym.get_placement_options(); @@ -386,7 +391,6 @@ private: } } - void add_stroke_attributes(ptree & node, const stroke & strk) { @@ -434,8 +438,8 @@ private: } set_attr( node, "stroke-dasharray", os.str() ); } - } + void add_metawriter_attributes(ptree & node, symbolizer_base const& sym) { if (!sym.get_metawriter_name().empty() || explicit_defaults_) { @@ -444,13 +448,11 @@ private: if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) { set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string()); } - - std::string tr_str = sym.get_transform_string(); - if (tr_str != "matrix(1, 0, 0, 1, 0, 0)" || explicit_defaults_ ) // FIXME !! + if (sym.get_transform()) { + std::string tr_str = sym.get_transform_string(); set_attr( node, "transform", tr_str ); } - } ptree & rule_; diff --git a/src/symbolizer.cpp b/src/symbolizer.cpp index 3245001aa..d23b85e09 100644 --- a/src/symbolizer.cpp +++ b/src/symbolizer.cpp @@ -23,9 +23,26 @@ //mapnik #include #include +#include namespace mapnik { +void evaluate_transform(agg::trans_affine& tr, Feature const& feature, + transform_list_ptr const& trans_expr) +{ + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(transform) << "transform: evaluate " + << (trans_expr + ? transform_processor_type::to_string(*trans_expr) + : std::string("null")); + #endif + + if (trans_expr) + { + transform_processor_type::evaluate(tr, feature, *trans_expr); + } +} + // default ctor symbolizer_base::symbolizer_base() : properties_(), @@ -36,12 +53,6 @@ symbolizer_base::symbolizer_base() clip_(true), smooth_value_(0.0) { - affine_transform_[0] = 1.0; - affine_transform_[1] = 0.0; - affine_transform_[2] = 0.0; - affine_transform_[3] = 1.0; - affine_transform_[4] = 0.0; - affine_transform_[5] = 0.0; } // copy ctor @@ -107,6 +118,13 @@ composite_mode_e symbolizer_base::comp_op() const void symbolizer_base::set_transform(transform_type const& affine_transform) { affine_transform_ = affine_transform; + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(load_map) << "map_parser: set_transform: " + << (affine_transform_ + ? transform_processor_type::to_string(*affine_transform_) + : std::string("null")); + #endif } transform_type const& symbolizer_base::get_transform() const @@ -116,11 +134,10 @@ transform_type const& symbolizer_base::get_transform() const std::string symbolizer_base::get_transform_string() const { - std::stringstream ss; - ss << "matrix(" << affine_transform_[0] << ", " << affine_transform_[1] << ", " - << affine_transform_[2] << ", " << affine_transform_[3] << ", " - << affine_transform_[4] << ", " << affine_transform_[5] << ")"; - return ss.str(); + if (affine_transform_) + return transform_processor_type::to_string(*affine_transform_); + else + return std::string(); } void symbolizer_base::set_clip(bool clip) @@ -149,12 +166,6 @@ symbolizer_with_image::symbolizer_with_image(path_expression_ptr file) : image_filename_( file ), image_opacity_(1.0f) { - image_transform_[0] = 1.0; - image_transform_[1] = 0.0; - image_transform_[2] = 0.0; - image_transform_[3] = 1.0; - image_transform_[4] = 0.0; - image_transform_[5] = 0.0; } symbolizer_with_image::symbolizer_with_image( symbolizer_with_image const& rhs) @@ -187,6 +198,13 @@ float symbolizer_with_image::get_opacity() const void symbolizer_with_image::set_image_transform(transform_type const& tr) { image_transform_ = tr; + + #ifdef MAPNIK_LOG + MAPNIK_LOG_DEBUG(load_map) << "map_parser: set_image_transform: " + << (image_transform_ + ? transform_processor_type::to_string(*image_transform_) + : std::string("null")); + #endif } transform_type const& symbolizer_with_image::get_image_transform() const @@ -196,11 +214,10 @@ transform_type const& symbolizer_with_image::get_image_transform() const std::string symbolizer_with_image::get_image_transform_string() const { - std::stringstream ss; - ss << "matrix(" << image_transform_[0] << ", " << image_transform_[1] << ", " - << image_transform_[2] << ", " << image_transform_[3] << ", " - << image_transform_[4] << ", " << image_transform_[5] << ")"; - return ss.str(); + if (image_transform_) + return transform_processor_type::to_string(*image_transform_); + else + return std::string(); } } // end of namespace mapnik diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index f2a3f2be0..695325cb9 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -350,8 +350,7 @@ template void shield_symbolizer_helper::init_marker() { std::string filename = path_processor_type::evaluate(*sym_.get_filename(), this->feature_); - boost::array const& m = sym_.get_image_transform(); - image_transform_.load_from(&m[0]); + evaluate_transform(image_transform_, feature_, sym_.get_image_transform()); marker_.reset(); if (!filename.empty()) { diff --git a/src/transform_expression.cpp b/src/transform_expression.cpp new file mode 100644 index 000000000..157dee202 --- /dev/null +++ b/src/transform_expression.cpp @@ -0,0 +1,144 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + +// boost +#include + +// stl +#include + +namespace mapnik { + + +struct transform_node_to_expression_string + : public boost::static_visitor +{ + std::ostringstream& os_; + + transform_node_to_expression_string(std::ostringstream& os) + : os_(os) {} + + void operator() (identity_node const& node) const + { + boost::ignore_unused_variable_warning(node); + } + + void operator() (matrix_node const& node) + { + os_ << "matrix(" + << to_expression_string(node.a_) << ", " + << to_expression_string(node.b_) << ", " + << to_expression_string(node.c_) << ", " + << to_expression_string(node.d_) << ", " + << to_expression_string(node.e_) << ", " + << to_expression_string(node.f_) << ")"; + } + + void operator() (translate_node const& node) + { + if (is_null(node.ty_)) + { + os_ << "translate(" + << to_expression_string(node.tx_) << ")"; + } + else + { + os_ << "translate(" + << to_expression_string(node.tx_) << ", " + << to_expression_string(node.ty_) << ")"; + } + } + + void operator() (scale_node const& node) + { + if (is_null(node.sy_)) + { + os_ << "scale(" + << to_expression_string(node.sx_) << ")"; + } + else + { + os_ << "scale(" + << to_expression_string(node.sx_) << ", " + << to_expression_string(node.sy_) << ")"; + } + } + + void operator() (rotate_node const& node) + { + if (is_null(node.cy_) || is_null(node.cy_)) + { + os_ << "rotate(" + << to_expression_string(node.angle_) << ")"; + } + else + { + os_ << "rotate(" + << to_expression_string(node.angle_) << ", " + << to_expression_string(node.cx_) << ", " + << to_expression_string(node.cy_) << ")"; + } + } + + void operator() (skewX_node const& node) + { + os_ << "skewX(" + << to_expression_string(node.angle_) << ")"; + } + + void operator() (skewY_node const& node) + { + os_ << "skewY(" + << to_expression_string(node.angle_) << ")"; + } +}; + + +std::string to_expression_string(transform_node const& node) +{ + std::ostringstream os; // FIXME set precision? + transform_node_to_expression_string to_string(os); + boost::apply_visitor(to_string, *node); + return os.str(); +} + + +std::string to_expression_string(transform_list const& list) +{ + std::ostringstream os; // FIXME set precision? + std::streamsize first = 1; + transform_node_to_expression_string to_string(os); + + BOOST_FOREACH (transform_node const& node, list) + { + os.write(" ", first ? (first = 0) : 1); + boost::apply_visitor(to_string, *node); + } + return os.str(); +} + + +} // namespace mapnik diff --git a/src/xml_tree.cpp b/src/xml_tree.cpp index 4d4593681..b8aaff9b3 100644 --- a/src/xml_tree.cpp +++ b/src/xml_tree.cpp @@ -172,7 +172,8 @@ xml_tree::xml_tree(std::string const& encoding) tr_(encoding), color_grammar(), expr_grammar(tr_), - path_expr_grammar() + path_expr_grammar(), + transform_expr_grammar(expr_grammar) { node_.set_processed(true); //root node is always processed } From cd7ad3e15eed5b9b582c2b92175a68b77c1f5547 Mon Sep 17 00:00:00 2001 From: Carl Simonson Date: Mon, 4 Jun 2012 16:19:00 -0500 Subject: [PATCH 11/17] Catch and throw PNG exceptions - fixes #1213 The png library uses setjmp/longjmp to throw exceptions when reading. If this is not set up, the png library calls abort(). This change handles the errors and throws a C++ exception instead. This issue was found by testing images from pngsuite at http://www.schaik.com/pngsuite/. These images are included and a unit test was added to test both images that should be successful and images that should throw an exception. --- src/png_reader.cpp | 14 +++++++++++ tests/data/pngsuite/PngSuite.LICENSE | 9 +++++++ tests/data/pngsuite/PngSuite.README | 25 +++++++++++++++++++ tests/data/pngsuite/PngSuite.png | Bin 0 -> 2262 bytes tests/data/pngsuite/basi0g01.png | Bin 0 -> 217 bytes tests/data/pngsuite/basi0g02.png | Bin 0 -> 154 bytes tests/data/pngsuite/basi0g04.png | Bin 0 -> 247 bytes tests/data/pngsuite/basi0g08.png | Bin 0 -> 254 bytes tests/data/pngsuite/basi0g16.png | Bin 0 -> 299 bytes tests/data/pngsuite/basi2c08.png | Bin 0 -> 315 bytes tests/data/pngsuite/basi2c16.png | Bin 0 -> 595 bytes tests/data/pngsuite/basi3p01.png | Bin 0 -> 132 bytes tests/data/pngsuite/basi3p02.png | Bin 0 -> 193 bytes tests/data/pngsuite/basi3p04.png | Bin 0 -> 327 bytes tests/data/pngsuite/basi3p08.png | Bin 0 -> 1527 bytes tests/data/pngsuite/basi4a08.png | Bin 0 -> 214 bytes tests/data/pngsuite/basi4a16.png | Bin 0 -> 2855 bytes tests/data/pngsuite/basi6a08.png | Bin 0 -> 361 bytes tests/data/pngsuite/basi6a16.png | Bin 0 -> 4180 bytes tests/data/pngsuite/basn0g01.png | Bin 0 -> 164 bytes tests/data/pngsuite/basn0g02.png | Bin 0 -> 104 bytes tests/data/pngsuite/basn0g04.png | Bin 0 -> 145 bytes tests/data/pngsuite/basn0g08.png | Bin 0 -> 138 bytes tests/data/pngsuite/basn0g16.png | Bin 0 -> 167 bytes tests/data/pngsuite/basn2c08.png | Bin 0 -> 145 bytes tests/data/pngsuite/basn2c16.png | Bin 0 -> 302 bytes tests/data/pngsuite/basn3p01.png | Bin 0 -> 112 bytes tests/data/pngsuite/basn3p02.png | Bin 0 -> 146 bytes tests/data/pngsuite/basn3p04.png | Bin 0 -> 216 bytes tests/data/pngsuite/basn3p08.png | Bin 0 -> 1286 bytes tests/data/pngsuite/basn4a08.png | Bin 0 -> 126 bytes tests/data/pngsuite/basn4a16.png | Bin 0 -> 2206 bytes tests/data/pngsuite/basn6a08.png | Bin 0 -> 184 bytes tests/data/pngsuite/basn6a16.png | Bin 0 -> 3435 bytes tests/data/pngsuite/bgai4a08.png | Bin 0 -> 214 bytes tests/data/pngsuite/bgai4a16.png | Bin 0 -> 2855 bytes tests/data/pngsuite/bgan6a08.png | Bin 0 -> 184 bytes tests/data/pngsuite/bgan6a16.png | Bin 0 -> 3435 bytes tests/data/pngsuite/bgbn4a08.png | Bin 0 -> 140 bytes tests/data/pngsuite/bggn4a16.png | Bin 0 -> 2220 bytes tests/data/pngsuite/bgwn6a08.png | Bin 0 -> 202 bytes tests/data/pngsuite/bgyn6a16.png | Bin 0 -> 3453 bytes tests/data/pngsuite/ccwn2c08.png | Bin 0 -> 1514 bytes tests/data/pngsuite/ccwn3p08.png | Bin 0 -> 1554 bytes tests/data/pngsuite/cdfn2c08.png | Bin 0 -> 404 bytes tests/data/pngsuite/cdhn2c08.png | Bin 0 -> 344 bytes tests/data/pngsuite/cdsn2c08.png | Bin 0 -> 232 bytes tests/data/pngsuite/cdun2c08.png | Bin 0 -> 724 bytes tests/data/pngsuite/ch1n3p04.png | Bin 0 -> 258 bytes tests/data/pngsuite/ch2n3p08.png | Bin 0 -> 1810 bytes tests/data/pngsuite/cm0n0g04.png | Bin 0 -> 292 bytes tests/data/pngsuite/cm7n0g04.png | Bin 0 -> 292 bytes tests/data/pngsuite/cm9n0g04.png | Bin 0 -> 292 bytes tests/data/pngsuite/cs3n2c16.png | Bin 0 -> 214 bytes tests/data/pngsuite/cs3n3p08.png | Bin 0 -> 259 bytes tests/data/pngsuite/cs5n2c08.png | Bin 0 -> 186 bytes tests/data/pngsuite/cs5n3p08.png | Bin 0 -> 271 bytes tests/data/pngsuite/cs8n2c08.png | Bin 0 -> 149 bytes tests/data/pngsuite/cs8n3p08.png | Bin 0 -> 256 bytes tests/data/pngsuite/ct0n0g04.png | Bin 0 -> 273 bytes tests/data/pngsuite/ct1n0g04.png | Bin 0 -> 792 bytes tests/data/pngsuite/cten0g04.png | Bin 0 -> 748 bytes tests/data/pngsuite/ctfn0g04.png | Bin 0 -> 722 bytes tests/data/pngsuite/ctgn0g04.png | Bin 0 -> 1188 bytes tests/data/pngsuite/cthn0g04.png | Bin 0 -> 1275 bytes tests/data/pngsuite/ctjn0g04.png | Bin 0 -> 947 bytes tests/data/pngsuite/ctzn0g04.png | Bin 0 -> 753 bytes tests/data/pngsuite/f00n0g08.png | Bin 0 -> 319 bytes tests/data/pngsuite/f00n2c08.png | Bin 0 -> 2475 bytes tests/data/pngsuite/f01n0g08.png | Bin 0 -> 321 bytes tests/data/pngsuite/f01n2c08.png | Bin 0 -> 1180 bytes tests/data/pngsuite/f02n0g08.png | Bin 0 -> 355 bytes tests/data/pngsuite/f02n2c08.png | Bin 0 -> 1729 bytes tests/data/pngsuite/f03n0g08.png | Bin 0 -> 389 bytes tests/data/pngsuite/f03n2c08.png | Bin 0 -> 1291 bytes tests/data/pngsuite/f04n0g08.png | Bin 0 -> 269 bytes tests/data/pngsuite/f04n2c08.png | Bin 0 -> 985 bytes tests/data/pngsuite/f99n0g04.png | Bin 0 -> 426 bytes tests/data/pngsuite/g03n0g16.png | Bin 0 -> 345 bytes tests/data/pngsuite/g03n2c08.png | Bin 0 -> 370 bytes tests/data/pngsuite/g03n3p04.png | Bin 0 -> 214 bytes tests/data/pngsuite/g04n0g16.png | Bin 0 -> 363 bytes tests/data/pngsuite/g04n2c08.png | Bin 0 -> 377 bytes tests/data/pngsuite/g04n3p04.png | Bin 0 -> 219 bytes tests/data/pngsuite/g05n0g16.png | Bin 0 -> 339 bytes tests/data/pngsuite/g05n2c08.png | Bin 0 -> 350 bytes tests/data/pngsuite/g05n3p04.png | Bin 0 -> 206 bytes tests/data/pngsuite/g07n0g16.png | Bin 0 -> 321 bytes tests/data/pngsuite/g07n2c08.png | Bin 0 -> 340 bytes tests/data/pngsuite/g07n3p04.png | Bin 0 -> 207 bytes tests/data/pngsuite/g10n0g16.png | Bin 0 -> 262 bytes tests/data/pngsuite/g10n2c08.png | Bin 0 -> 285 bytes tests/data/pngsuite/g10n3p04.png | Bin 0 -> 214 bytes tests/data/pngsuite/g25n0g16.png | Bin 0 -> 383 bytes tests/data/pngsuite/g25n2c08.png | Bin 0 -> 405 bytes tests/data/pngsuite/g25n3p04.png | Bin 0 -> 215 bytes tests/data/pngsuite/oi1n0g16.png | Bin 0 -> 167 bytes tests/data/pngsuite/oi1n2c16.png | Bin 0 -> 302 bytes tests/data/pngsuite/oi2n0g16.png | Bin 0 -> 179 bytes tests/data/pngsuite/oi2n2c16.png | Bin 0 -> 314 bytes tests/data/pngsuite/oi4n0g16.png | Bin 0 -> 203 bytes tests/data/pngsuite/oi4n2c16.png | Bin 0 -> 338 bytes tests/data/pngsuite/oi9n0g16.png | Bin 0 -> 1283 bytes tests/data/pngsuite/oi9n2c16.png | Bin 0 -> 3038 bytes tests/data/pngsuite/pp0n2c16.png | Bin 0 -> 962 bytes tests/data/pngsuite/pp0n6a08.png | Bin 0 -> 818 bytes tests/data/pngsuite/ps1n0g08.png | Bin 0 -> 1456 bytes tests/data/pngsuite/ps1n2c16.png | Bin 0 -> 1620 bytes tests/data/pngsuite/ps2n0g08.png | Bin 0 -> 2320 bytes tests/data/pngsuite/ps2n2c16.png | Bin 0 -> 2484 bytes tests/data/pngsuite/s01i3p01.png | Bin 0 -> 113 bytes tests/data/pngsuite/s01n3p01.png | Bin 0 -> 113 bytes tests/data/pngsuite/s02i3p01.png | Bin 0 -> 114 bytes tests/data/pngsuite/s02n3p01.png | Bin 0 -> 115 bytes tests/data/pngsuite/s03i3p01.png | Bin 0 -> 118 bytes tests/data/pngsuite/s03n3p01.png | Bin 0 -> 120 bytes tests/data/pngsuite/s04i3p01.png | Bin 0 -> 126 bytes tests/data/pngsuite/s04n3p01.png | Bin 0 -> 121 bytes tests/data/pngsuite/s05i3p02.png | Bin 0 -> 134 bytes tests/data/pngsuite/s05n3p02.png | Bin 0 -> 129 bytes tests/data/pngsuite/s06i3p02.png | Bin 0 -> 143 bytes tests/data/pngsuite/s06n3p02.png | Bin 0 -> 131 bytes tests/data/pngsuite/s07i3p02.png | Bin 0 -> 149 bytes tests/data/pngsuite/s07n3p02.png | Bin 0 -> 138 bytes tests/data/pngsuite/s08i3p02.png | Bin 0 -> 149 bytes tests/data/pngsuite/s08n3p02.png | Bin 0 -> 139 bytes tests/data/pngsuite/s09i3p02.png | Bin 0 -> 147 bytes tests/data/pngsuite/s09n3p02.png | Bin 0 -> 143 bytes tests/data/pngsuite/s32i3p04.png | Bin 0 -> 355 bytes tests/data/pngsuite/s32n3p04.png | Bin 0 -> 263 bytes tests/data/pngsuite/s33i3p04.png | Bin 0 -> 385 bytes tests/data/pngsuite/s33n3p04.png | Bin 0 -> 329 bytes tests/data/pngsuite/s34i3p04.png | Bin 0 -> 349 bytes tests/data/pngsuite/s34n3p04.png | Bin 0 -> 248 bytes tests/data/pngsuite/s35i3p04.png | Bin 0 -> 399 bytes tests/data/pngsuite/s35n3p04.png | Bin 0 -> 338 bytes tests/data/pngsuite/s36i3p04.png | Bin 0 -> 356 bytes tests/data/pngsuite/s36n3p04.png | Bin 0 -> 258 bytes tests/data/pngsuite/s37i3p04.png | Bin 0 -> 393 bytes tests/data/pngsuite/s37n3p04.png | Bin 0 -> 336 bytes tests/data/pngsuite/s38i3p04.png | Bin 0 -> 357 bytes tests/data/pngsuite/s38n3p04.png | Bin 0 -> 245 bytes tests/data/pngsuite/s39i3p04.png | Bin 0 -> 420 bytes tests/data/pngsuite/s39n3p04.png | Bin 0 -> 352 bytes tests/data/pngsuite/s40i3p04.png | Bin 0 -> 357 bytes tests/data/pngsuite/s40n3p04.png | Bin 0 -> 256 bytes tests/data/pngsuite/tbbn0g04.png | Bin 0 -> 429 bytes tests/data/pngsuite/tbbn2c16.png | Bin 0 -> 2041 bytes tests/data/pngsuite/tbbn3p08.png | Bin 0 -> 1499 bytes tests/data/pngsuite/tbgn2c16.png | Bin 0 -> 2041 bytes tests/data/pngsuite/tbgn3p08.png | Bin 0 -> 1499 bytes tests/data/pngsuite/tbrn2c08.png | Bin 0 -> 1633 bytes tests/data/pngsuite/tbwn0g16.png | Bin 0 -> 1313 bytes tests/data/pngsuite/tbwn3p08.png | Bin 0 -> 1496 bytes tests/data/pngsuite/tbyn3p08.png | Bin 0 -> 1499 bytes tests/data/pngsuite/tp0n0g08.png | Bin 0 -> 719 bytes tests/data/pngsuite/tp0n2c08.png | Bin 0 -> 1594 bytes tests/data/pngsuite/tp0n3p08.png | Bin 0 -> 1476 bytes tests/data/pngsuite/tp1n3p08.png | Bin 0 -> 1483 bytes tests/data/pngsuite/xc1n0g08.png | Bin 0 -> 138 bytes tests/data/pngsuite/xc9n2c08.png | Bin 0 -> 145 bytes tests/data/pngsuite/xcrn0g04.png | Bin 0 -> 145 bytes tests/data/pngsuite/xcsn0g01.png | Bin 0 -> 164 bytes tests/data/pngsuite/xd0n2c08.png | Bin 0 -> 145 bytes tests/data/pngsuite/xd3n2c08.png | Bin 0 -> 145 bytes tests/data/pngsuite/xd9n2c08.png | Bin 0 -> 145 bytes tests/data/pngsuite/xdtn0g01.png | Bin 0 -> 61 bytes tests/data/pngsuite/xhdn0g08.png | Bin 0 -> 138 bytes tests/data/pngsuite/xlfn0g04.png | Bin 0 -> 145 bytes tests/data/pngsuite/xs1n0g01.png | Bin 0 -> 164 bytes tests/data/pngsuite/xs2n0g01.png | Bin 0 -> 164 bytes tests/data/pngsuite/xs4n0g01.png | Bin 0 -> 164 bytes tests/data/pngsuite/xs7n0g01.png | Bin 0 -> 164 bytes tests/data/pngsuite/z00n2c08.png | Bin 0 -> 3172 bytes tests/data/pngsuite/z03n2c08.png | Bin 0 -> 232 bytes tests/data/pngsuite/z06n2c08.png | Bin 0 -> 224 bytes tests/data/pngsuite/z09n2c08.png | Bin 0 -> 224 bytes tests/python_tests/pngsuite_test.py | 35 +++++++++++++++++++++++++++ 178 files changed, 83 insertions(+) create mode 100644 tests/data/pngsuite/PngSuite.LICENSE create mode 100644 tests/data/pngsuite/PngSuite.README create mode 100644 tests/data/pngsuite/PngSuite.png create mode 100644 tests/data/pngsuite/basi0g01.png create mode 100644 tests/data/pngsuite/basi0g02.png create mode 100644 tests/data/pngsuite/basi0g04.png create mode 100644 tests/data/pngsuite/basi0g08.png create mode 100644 tests/data/pngsuite/basi0g16.png create mode 100644 tests/data/pngsuite/basi2c08.png create mode 100644 tests/data/pngsuite/basi2c16.png create mode 100644 tests/data/pngsuite/basi3p01.png create mode 100644 tests/data/pngsuite/basi3p02.png create mode 100644 tests/data/pngsuite/basi3p04.png create mode 100644 tests/data/pngsuite/basi3p08.png create mode 100644 tests/data/pngsuite/basi4a08.png create mode 100644 tests/data/pngsuite/basi4a16.png create mode 100644 tests/data/pngsuite/basi6a08.png create mode 100644 tests/data/pngsuite/basi6a16.png create mode 100644 tests/data/pngsuite/basn0g01.png create mode 100644 tests/data/pngsuite/basn0g02.png create mode 100644 tests/data/pngsuite/basn0g04.png create mode 100644 tests/data/pngsuite/basn0g08.png create mode 100644 tests/data/pngsuite/basn0g16.png create mode 100644 tests/data/pngsuite/basn2c08.png create mode 100644 tests/data/pngsuite/basn2c16.png create mode 100644 tests/data/pngsuite/basn3p01.png create mode 100644 tests/data/pngsuite/basn3p02.png create mode 100644 tests/data/pngsuite/basn3p04.png create mode 100644 tests/data/pngsuite/basn3p08.png create mode 100644 tests/data/pngsuite/basn4a08.png create mode 100644 tests/data/pngsuite/basn4a16.png create mode 100644 tests/data/pngsuite/basn6a08.png create mode 100644 tests/data/pngsuite/basn6a16.png create mode 100644 tests/data/pngsuite/bgai4a08.png create mode 100644 tests/data/pngsuite/bgai4a16.png create mode 100644 tests/data/pngsuite/bgan6a08.png create mode 100644 tests/data/pngsuite/bgan6a16.png create mode 100644 tests/data/pngsuite/bgbn4a08.png create mode 100644 tests/data/pngsuite/bggn4a16.png create mode 100644 tests/data/pngsuite/bgwn6a08.png create mode 100644 tests/data/pngsuite/bgyn6a16.png create mode 100644 tests/data/pngsuite/ccwn2c08.png create mode 100644 tests/data/pngsuite/ccwn3p08.png create mode 100644 tests/data/pngsuite/cdfn2c08.png create mode 100644 tests/data/pngsuite/cdhn2c08.png create mode 100644 tests/data/pngsuite/cdsn2c08.png create mode 100644 tests/data/pngsuite/cdun2c08.png create mode 100644 tests/data/pngsuite/ch1n3p04.png create mode 100644 tests/data/pngsuite/ch2n3p08.png create mode 100644 tests/data/pngsuite/cm0n0g04.png create mode 100644 tests/data/pngsuite/cm7n0g04.png create mode 100644 tests/data/pngsuite/cm9n0g04.png create mode 100644 tests/data/pngsuite/cs3n2c16.png create mode 100644 tests/data/pngsuite/cs3n3p08.png create mode 100644 tests/data/pngsuite/cs5n2c08.png create mode 100644 tests/data/pngsuite/cs5n3p08.png create mode 100644 tests/data/pngsuite/cs8n2c08.png create mode 100644 tests/data/pngsuite/cs8n3p08.png create mode 100644 tests/data/pngsuite/ct0n0g04.png create mode 100644 tests/data/pngsuite/ct1n0g04.png create mode 100644 tests/data/pngsuite/cten0g04.png create mode 100644 tests/data/pngsuite/ctfn0g04.png create mode 100644 tests/data/pngsuite/ctgn0g04.png create mode 100644 tests/data/pngsuite/cthn0g04.png create mode 100644 tests/data/pngsuite/ctjn0g04.png create mode 100644 tests/data/pngsuite/ctzn0g04.png create mode 100644 tests/data/pngsuite/f00n0g08.png create mode 100644 tests/data/pngsuite/f00n2c08.png create mode 100644 tests/data/pngsuite/f01n0g08.png create mode 100644 tests/data/pngsuite/f01n2c08.png create mode 100644 tests/data/pngsuite/f02n0g08.png create mode 100644 tests/data/pngsuite/f02n2c08.png create mode 100644 tests/data/pngsuite/f03n0g08.png create mode 100644 tests/data/pngsuite/f03n2c08.png create mode 100644 tests/data/pngsuite/f04n0g08.png create mode 100644 tests/data/pngsuite/f04n2c08.png create mode 100644 tests/data/pngsuite/f99n0g04.png create mode 100644 tests/data/pngsuite/g03n0g16.png create mode 100644 tests/data/pngsuite/g03n2c08.png create mode 100644 tests/data/pngsuite/g03n3p04.png create mode 100644 tests/data/pngsuite/g04n0g16.png create mode 100644 tests/data/pngsuite/g04n2c08.png create mode 100644 tests/data/pngsuite/g04n3p04.png create mode 100644 tests/data/pngsuite/g05n0g16.png create mode 100644 tests/data/pngsuite/g05n2c08.png create mode 100644 tests/data/pngsuite/g05n3p04.png create mode 100644 tests/data/pngsuite/g07n0g16.png create mode 100644 tests/data/pngsuite/g07n2c08.png create mode 100644 tests/data/pngsuite/g07n3p04.png create mode 100644 tests/data/pngsuite/g10n0g16.png create mode 100644 tests/data/pngsuite/g10n2c08.png create mode 100644 tests/data/pngsuite/g10n3p04.png create mode 100644 tests/data/pngsuite/g25n0g16.png create mode 100644 tests/data/pngsuite/g25n2c08.png create mode 100644 tests/data/pngsuite/g25n3p04.png create mode 100644 tests/data/pngsuite/oi1n0g16.png create mode 100644 tests/data/pngsuite/oi1n2c16.png create mode 100644 tests/data/pngsuite/oi2n0g16.png create mode 100644 tests/data/pngsuite/oi2n2c16.png create mode 100644 tests/data/pngsuite/oi4n0g16.png create mode 100644 tests/data/pngsuite/oi4n2c16.png create mode 100644 tests/data/pngsuite/oi9n0g16.png create mode 100644 tests/data/pngsuite/oi9n2c16.png create mode 100644 tests/data/pngsuite/pp0n2c16.png create mode 100644 tests/data/pngsuite/pp0n6a08.png create mode 100644 tests/data/pngsuite/ps1n0g08.png create mode 100644 tests/data/pngsuite/ps1n2c16.png create mode 100644 tests/data/pngsuite/ps2n0g08.png create mode 100644 tests/data/pngsuite/ps2n2c16.png create mode 100644 tests/data/pngsuite/s01i3p01.png create mode 100644 tests/data/pngsuite/s01n3p01.png create mode 100644 tests/data/pngsuite/s02i3p01.png create mode 100644 tests/data/pngsuite/s02n3p01.png create mode 100644 tests/data/pngsuite/s03i3p01.png create mode 100644 tests/data/pngsuite/s03n3p01.png create mode 100644 tests/data/pngsuite/s04i3p01.png create mode 100644 tests/data/pngsuite/s04n3p01.png create mode 100644 tests/data/pngsuite/s05i3p02.png create mode 100644 tests/data/pngsuite/s05n3p02.png create mode 100644 tests/data/pngsuite/s06i3p02.png create mode 100644 tests/data/pngsuite/s06n3p02.png create mode 100644 tests/data/pngsuite/s07i3p02.png create mode 100644 tests/data/pngsuite/s07n3p02.png create mode 100644 tests/data/pngsuite/s08i3p02.png create mode 100644 tests/data/pngsuite/s08n3p02.png create mode 100644 tests/data/pngsuite/s09i3p02.png create mode 100644 tests/data/pngsuite/s09n3p02.png create mode 100644 tests/data/pngsuite/s32i3p04.png create mode 100644 tests/data/pngsuite/s32n3p04.png create mode 100644 tests/data/pngsuite/s33i3p04.png create mode 100644 tests/data/pngsuite/s33n3p04.png create mode 100644 tests/data/pngsuite/s34i3p04.png create mode 100644 tests/data/pngsuite/s34n3p04.png create mode 100644 tests/data/pngsuite/s35i3p04.png create mode 100644 tests/data/pngsuite/s35n3p04.png create mode 100644 tests/data/pngsuite/s36i3p04.png create mode 100644 tests/data/pngsuite/s36n3p04.png create mode 100644 tests/data/pngsuite/s37i3p04.png create mode 100644 tests/data/pngsuite/s37n3p04.png create mode 100644 tests/data/pngsuite/s38i3p04.png create mode 100644 tests/data/pngsuite/s38n3p04.png create mode 100644 tests/data/pngsuite/s39i3p04.png create mode 100644 tests/data/pngsuite/s39n3p04.png create mode 100644 tests/data/pngsuite/s40i3p04.png create mode 100644 tests/data/pngsuite/s40n3p04.png create mode 100644 tests/data/pngsuite/tbbn0g04.png create mode 100644 tests/data/pngsuite/tbbn2c16.png create mode 100644 tests/data/pngsuite/tbbn3p08.png create mode 100644 tests/data/pngsuite/tbgn2c16.png create mode 100644 tests/data/pngsuite/tbgn3p08.png create mode 100644 tests/data/pngsuite/tbrn2c08.png create mode 100644 tests/data/pngsuite/tbwn0g16.png create mode 100644 tests/data/pngsuite/tbwn3p08.png create mode 100644 tests/data/pngsuite/tbyn3p08.png create mode 100644 tests/data/pngsuite/tp0n0g08.png create mode 100644 tests/data/pngsuite/tp0n2c08.png create mode 100644 tests/data/pngsuite/tp0n3p08.png create mode 100644 tests/data/pngsuite/tp1n3p08.png create mode 100644 tests/data/pngsuite/xc1n0g08.png create mode 100644 tests/data/pngsuite/xc9n2c08.png create mode 100644 tests/data/pngsuite/xcrn0g04.png create mode 100644 tests/data/pngsuite/xcsn0g01.png create mode 100644 tests/data/pngsuite/xd0n2c08.png create mode 100644 tests/data/pngsuite/xd3n2c08.png create mode 100644 tests/data/pngsuite/xd9n2c08.png create mode 100644 tests/data/pngsuite/xdtn0g01.png create mode 100644 tests/data/pngsuite/xhdn0g08.png create mode 100644 tests/data/pngsuite/xlfn0g04.png create mode 100644 tests/data/pngsuite/xs1n0g01.png create mode 100644 tests/data/pngsuite/xs2n0g01.png create mode 100644 tests/data/pngsuite/xs4n0g01.png create mode 100644 tests/data/pngsuite/xs7n0g01.png create mode 100644 tests/data/pngsuite/z00n2c08.png create mode 100644 tests/data/pngsuite/z03n2c08.png create mode 100644 tests/data/pngsuite/z06n2c08.png create mode 100644 tests/data/pngsuite/z09n2c08.png create mode 100644 tests/python_tests/pngsuite_test.py diff --git a/src/png_reader.cpp b/src/png_reader.cpp index 02a4f010d..8b993c7e3 100644 --- a/src/png_reader.cpp +++ b/src/png_reader.cpp @@ -119,6 +119,13 @@ void png_reader::init() throw image_reader_exception("failed to create info_ptr"); } + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr,0,0); + fclose(fp); + throw image_reader_exception("failed to read"); + } + png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_set_sig_bytes(png_ptr,8); @@ -168,6 +175,13 @@ void png_reader::read(unsigned x0, unsigned y0,image_data_32& image) throw image_reader_exception("failed to create info_ptr"); } + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr,0,0); + fclose(fp); + throw image_reader_exception("failed to read"); + } + png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data); png_read_info(png_ptr, info_ptr); diff --git a/tests/data/pngsuite/PngSuite.LICENSE b/tests/data/pngsuite/PngSuite.LICENSE new file mode 100644 index 000000000..8d4d1d077 --- /dev/null +++ b/tests/data/pngsuite/PngSuite.LICENSE @@ -0,0 +1,9 @@ +PngSuite +-------- + +Permission to use, copy, modify and distribute these images for any +purpose and without fee is hereby granted. + + +(c) Willem van Schaik, 1996, 2011 + diff --git a/tests/data/pngsuite/PngSuite.README b/tests/data/pngsuite/PngSuite.README new file mode 100644 index 000000000..3ef8f24db --- /dev/null +++ b/tests/data/pngsuite/PngSuite.README @@ -0,0 +1,25 @@ + PNGSUITE +---------------- + + testset for PNG-(de)coders + created by Willem van Schaik +------------------------------------ + +This is a collection of graphics images created to test the png applications +like viewers, converters and editors. All (as far as that is possible) +formats supported by the PNG standard are represented. + +The suite consists of the following files: + +- PngSuite.README - this file +- PngSuite.LICENSE - the PngSuite is freeware +- PngSuite.png - image with PngSuite logo +- PngSuite.tgz - archive of all PNG testfiles +- PngSuite.zip - same in .zip format for PCs + + +-------- + (c) Willem van Schaik + willem@schaik.com + Calgary, April 2011 + diff --git a/tests/data/pngsuite/PngSuite.png b/tests/data/pngsuite/PngSuite.png new file mode 100644 index 0000000000000000000000000000000000000000..205460d8287a90ab9c9b7372354d8b7a8b5317da GIT binary patch literal 2262 zcmeHJ>rYd682+8Zt)**0D(iv+w`s(Qqq+>OC~Z{+5(6%qnTmzN6wwJ3B(&vn+9ME% z$;M2`oUxX6SvJ{LZgE(pYfl$48L3>BAs`jn!dzvgE%XY#oUZ#H_GJlQ-sgFrym>!7 z@AKik@j*c@IW{R406@+=k^Lb6P?$o10Egj^c-DRZ2-3Xlqo;*;t@HZ@Q#r5Yl#aH? zcE9=U==N90iDYu(+rMppQbYQFsblv$Nrwz&Z;_X1Hft0A(#HlHQ$;yYdhUs6aav;X z-bC;No^_L%t}~Xe%LYci5FyMPF*k#OSdaiRgy~HAe zCb&BR>_i_C(SISV!M7z~cNjM1O;7%#K>YBkw$h9r<_w6V=0!*Dt`5zOS(dj9se7u_ zsunB3c%dG@nu%G3g$UedZ$ekMn9>-}Y%ry7;=VwjWQA5z0q@?K$$WETg$jQT4*nGU zGgaGwCo8B3(lzkhTHhNWtG$_;Lc+8_!l314O@l<_Ij0f>AfzeJ9R{ zTWz{~_T|7y=(%Co^Vh;c$}}b}tYr1t3qaY#S7xrb9&=?aI-$?-L)y{QDOm(({#QV; z`1u5opnXb|pQEFhkgJEru2liwgV04VT^HKQJ3o_Hk)}R2r`J0rq}c^44~elfPH<=V zM^$2dU*8$J&IEgvDK=YCJ)SdTaFH#g&6mW8ATC=cp`EsGxLoPmvc9f6Rk+60xRNJ> z`it#OQ@+FHyS0z<@VwZ^YaJ9QZ(%F$7yTO1NlQ^^k~roWzkJ-;oau*JPVvfN#xAr= z^d3-4L&)L+uTzEfFb8o5M&(2ZUw+zvU17Rgiz)IV(T4aF0-C^{@eFKpfQpGO=}>!a zbcvq7q_7y=K2Pc|?QXkLGm;Bv2Lsd+muyFy7*#kulRE{W_X;!@&#Do8VHna)UK>y9a*B)r?OBPV{brqmKchudQ4-Y;0=gviU=PM rY~5@&J@{YdK%svyris3PB}g(vec36=rM?^fS3utT1=+pFN}B%xoVVtB literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi0g01.png b/tests/data/pngsuite/basi0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..556fa72704084920c07066054bb57adc5a250b27 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk~Bp7wr%FhF7mUKs7M+U~W1%@xC#RK^hJY5_^ zD(2|+8uA@7;Bmcwtm%lTL>0plJ;|yaa?KmnAMk`(G6*LxZMYGklX_CXw8pz)!~XsE z{R_l;B%iO@S+Mxi#d|k1W1jAhOum0pYrW6>o9eGz=B2dXkDg=peCAH+`yAT7-d7m? zpD=neuC5Ya_iW0gUZXDEgTe~DWM4fgQ!vM literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi0g02.png b/tests/data/pngsuite/basi0g02.png new file mode 100644 index 0000000000000000000000000000000000000000..ce09821ef101b65b2aa653931416c72923ccab09 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk`Bp9=o@yY{fmUKs7M+U~W1%@xC#RK_)o-U3d z6?2jUl3pY*JS=M4oiJze;et03Q>IK~Gc?O{N#DFKJ@&l7SH)M%%o7ftVn}g$DCX>; zkRs^i5p-N&*DHI8!;%tAJO+*|%*(hAE|_G=Fej+Nw{_diTA<+!p00i_>zopr0NF1v AeE`KLv!pxvIx;Y}EiimBEgr~U=jq}Y zQZXmBFHrE1fq;v+j0h02$h25#lnT63xZ-%g@gNW$aGWTh62d&wbH=%|b$8yp-97vE z;Z29Oxt6;AKCTefnOkLOe zceV31xk&buuP3aOvK_8v?mNu>)5yI*ti8x;zv2JpMH=2qx2(%fUX!Y@wwPzh+iJE; se9X+5d(#!(S{O|*V`01GC)_Bn-uQauWnXqNpvxINUHx3vIVCg!0H8fu|I&j2dyvG3;`TGSdQ=U^x!+b$IgQ- z%948O0A52IVpokMw|y20kXn4P1fk&um!5HR4i(o|AwZ6~LzrfePT$2C@a*GO>pzD`W+JMY+o{~OMQc&lm=3iqj(vZoAg56v)&@pF xpiv;U26q|-VrxJe1@ZNXf_(7)M8WX7;00Eg?uiut|NZ~~002ovPDHLkV1i{YdSU?-TFZBK`N@L-n zZIKuYb8U;nSX9Mrl^A36r{K12&k3mj^Z%lhjX;s*Jg960iexztW-CxinU-MA*#;OZ zngOW30HtIErtRT^u_8M_CF3kj<3j{vMRtJ6I<2P3n{$R*t1rNmk`0g=AU|E-;g=04 zMQ4L1&-<_M{L=v}5QRU_7&y#fp@D&gr9M`8f1y92FoiBVSa`IsurPtS ze{e7d3sdH>SD>hoE4z_nx$z0??7UgMea|aJNhAr@Zvg8Z*gUmKePu;z>y8jWkvlsq z1W-(qZPlsA;>PQ-xbb>e=+HyjR`72RpJL@9duyYiw{L8ondoV1Dstk)`yNe2E|Tn) zQn&|5Z4$O-o8S$zjgb_v!ImC3RAHrGc4#Vv!)L8;XfO3ToGLXjk#F*79m4!RxgIe_tfnTuJcqEWy)4g2yKb%DDu0za_YxN$~Sgf+CmT>X!ubOoF_W z03=B5#`sg62L3e6{2RJyFI>13c>MtF{pl)#xkJ@t(o7&`wRIOmYhI*_#{U5rtXn@HNfb7oz6Bu5!i$}Tx-z(a!?=gYPiFWah6BvhR7Y~@g_(Z#S%LK+P h+Qpp-{6C^y{2ine-m~8mME3vy002ovPDHLkV1lO|5~BbB literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi3p01.png b/tests/data/pngsuite/basi3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..00a7cea6c2d3c36627718a502eb14c812b0b7c46 GIT binary patch literal 132 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL%)r2CxA}%5ki(Mh=>-dBi{f3 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi3p02.png b/tests/data/pngsuite/basi3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..bb16b44b30907b832b678a3b441278df340edb9f GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH%)r1{DZJ<-ki(Mh=EaktF(C3l8oA>Me*wxTz-(}y$c;d$?hLjJF#hg79QUtv`g1+0Ah)O6+%y3%0 kK!=4{>!bX^1(PfpwnWvwlrMbmdKI;Vst08#Hgh5!Hn literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi3p04.png b/tests/data/pngsuite/basi3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..b4e888e2477d4fbaa3c8ed16a8007d40e58cd52c GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF%)r3-EjT<7$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Hz$e62iQzxP|Nk8f|CRnTFwFe_KaJro!~b%i7*N6gnRh{q-T!wp zFt`9&E|)fV?gff(^K@|xshE@eVr8<$zX=QdragS9+NR;%b~IQ*M^<9l2E!vd+h?C( zII@q&;mi?+BR6^0F7JwWQfc53?9iD|$he5*L_qV3*BrK+SKaw>*N06*_XNYzScwH+ zV%a3lGAx}cv7khXdCI+B1NO@fK9ddC9@xTtImqX>;oQaofA@?RGmTe=O`R?+y}#PL zSZx`DR(OCwFvHZ>kD4?aPVKE04`%2+-2h~U1|1S{c)Dz9BG-bV^7qFC7#KE}y~^Mz Rxc~|Y22WQ%mvv4FO#pr5f6M>? literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi3p08.png b/tests/data/pngsuite/basi3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..50a6d1cac7a111d53cd3aec0d35dc4d09311baab GIT binary patch literal 1527 zcmWkt4Nw$y6n}dd;vwQ8DFIG$3@GI2c^hLQV*{=V2t>jrDk_FvDg&7$%b-@G;h|=k zpdN>Gek8Jdh#y$4REHQNu9O-n$@*~yld0Q~CgKPCdUtQ`_P_uC|GnSGdsmv8GRH?B zs0RR_gm`WqJ;%AfULF7pdq_&9mmwd-CdUF(;+S%8&r$#nNKHzgW#r%qssai!qCpSQ z0vL_7LIcnOu#UGNg#{Tj`hkLY32hvQ!1G1`Sw@Zn9(h>?HW2Wkq9XR7jEce`M@cLI zX9QKH0)U4(L{U}UX&T}n(htKT%SQskpw)^XiVOoBfYl1vBTI|Gh(?PU5N)D}JkUAF z*+A4fQ52$qu$3IJkUnIraqtk890gF3fMr1iHJ=i#wnVy*0swAiP?EIuK(HVK+H9oK zO8az3*a`*`R}fi5uu;&5F%xGAi8P7`R6^54fJ7UmSdgp%+jcbYbn0eLh5#4{O2a|z zFlncK3j#}*c@!wwN`=4x0@Wv9Pz46?iR#Xv1EQkRnl2%Lup5n_C@hN_Xp)3BL=u!O zgCs#6RU@v*uGicWd7h||*~k+*SQG^)HX|blsFAzW2%aZ!O(VrJ31D;t3x3pAg5Wqi zve-$Qc$9#ED~5p_E`A&DTySs_gXBPgvEi4GHiIsCXqG@a(*{? zqG+gzY2=omW89DcEUHMQNrOtO^VViET%@j9XuK5ipN55EJB^!6bHJ02)DH{^ z28HH;T8~zS28YEnJAZp0KzA^Ki%l=ATyc3-rZ)t5_Dwa^e3e*sHMuT3A|j#p=*X*F z#y0Vd=-McX6_VY&k>*>Z%e|vX1^&KXtnjHm_kp z{Oz$(O(8S=UuD^|XKQO8JeWScy}iAy&FQ@UT~n0V9QLiaO{Ytot3K50Bj4!g*tp@* zcGj*hPH>pOmLs;xabA)>UnI5F|W2|vHO`X8G8{qNq5UvQ>+yva2AorH*qN%N=1 zRO-F+*Y4O692_0}_3qrW zV_8*GU40<7^H$aV#hJ=gqrL3swI3}rKihD;tJ~gc@LGOoZ}}hHIjh6Ni;61tbzVDC zEf)+M(cfo^N={x^khe0+l%Bp^o)#S#*w$83a{u1Ivl?+Wcj0ty-sn>0W|&`1nH z58GA$jXh^Y`JN;7H@hZGKGv`#E%e2gv6o*jI5)Y=Gw4px%OQatp)Q!Xsl()5;fH&w40HKUbx zj4}D7oEu&UXI&wcy60YxT`|F*cQ@)MIhQzY_v!Om7VgvKXAK=bq{#ES%PVuszm5L= z&bJ*WO#!E!Apy*TI{`1@hW^84hM29NG>%Pa9pm_Xjc<61X<)<)m$})aVkqnKe7Wgq z-l@|1T-)pTTjSfo?;6Ga8{R(IDkmelNXRj)ZH9oA|PM{kg$m&gMT07S3iqx$gt>#1~b*D~%?ISJ;?`E{!%Qxx!#mpQpGpa(A8H z_iZ|MVh@5=q!mUuvSsYMxvKp95>weV2Kff8ej5&Q`t30L(azh))$_*RmQyw|G#2PE N22WQ%mvv4FO#oeUP~QLm literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi4a16.png b/tests/data/pngsuite/basi4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..51192e731106e77cec52a3acda3d0c3cd54a16d5 GIT binary patch literal 2855 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 FV1na*GhqM# literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi6a08.png b/tests/data/pngsuite/basi6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..aecb32e0d9e347ccdcab5d7fdad2dde7aef9da8a GIT binary patch literal 361 zcmV-v0ha!WP)!N7@Xl>n0JWRT0P1ZZ0~F7IAF8qd>UAgssMo0sP&xyjf=W~LX-;!O00000NkvXX Hu0mjfr8|%> literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basi6a16.png b/tests/data/pngsuite/basi6a16.png new file mode 100644 index 0000000000000000000000000000000000000000..4181533ad81b739fb7b4f3b024f632cd7baa85c5 GIT binary patch literal 4180 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 e|1a9-z<&T43-3ulno0000c;6;z7cmE{-7; zb9B#azopr0C;FL=l}o! literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn0g02.png b/tests/data/pngsuite/basn0g02.png new file mode 100644 index 0000000000000000000000000000000000000000..508332418fa86637d39e95268ec1d3658d120cae GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk`Bp75C+I9jdmUKs7M+U~W1%@xC#RK{Bo-U3d z6?2jkIAXub_k1+y2sp$L+}6)%%qgEdVJADoUeEf*ZqCk?AR|0o{an^LB{Ts5miHSU literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn0g04.png b/tests/data/pngsuite/basn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..0bf3687863d8a1f53bef0aa24b841b21b0e04d9e GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk^Bp4c;6;(>fePZ!6K ziaE(C2`UUC949vOu(I~>b7=nfE^nVuX&@tFa7u7Oddi~87#=p(p8gM~{{27yqy1T- hp#)Io!PL|g7KVVQ{|ZeX-G~HP;_2$=vd$@?2>|oDDeM3M literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn0g16.png b/tests/data/pngsuite/basn0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c82f78eb954be5be51c35bd287e00018c69d82 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq>1BpBEle`W(ImUKs7M+U~W1%@xC#RK_qo-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qG9=taAD!(1y)T7vK%uR?lygM zIK}cp><*ign#1-5wiApPcd>47oWOZOH-mqPPlA0u`y2l+k{0Ld8N_aQ--utQJ^wn$ N1)i>cF6*2UngAzTID!BG literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn2c08.png b/tests/data/pngsuite/basn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..db5ad15865f56e48e4bae5b43661d2dbc4e847e3 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^zg78t&m77yfmc)B=- zRLpsM^&lsM0S}Wy>zj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibtrx; literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn2c16.png b/tests/data/pngsuite/basn2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..50c1cb91a0171e9f34991b079fe932f5f0bb16d6 GIT binary patch literal 302 zcmV+}0nz@6P)NTxus~-YE?|ew94KIo9tHTv?hhRR zwrA%J^h9UxCeRmyPjW#d?oxNFL9(uFDZ1gBle+D$rIj`J+5;}Xa zfF63WfGT3xy1iYa$zve>zUI)9x>;M1&07*qoM6N<$g8PGj A5dZ)H literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn3p01.png b/tests/data/pngsuite/basn3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..b145c2b8eff1f4298e540bfae5c1351d015a3592 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;SkfJR9T^zg78t&m77ygJ1^9%x zzWcAFl=eSI>XI5zMAXy8F{ENn@&k4zHj_up0tD0@h%3W?AY}Lt#0>va?X`CSX(dk=$B>FS$v@Vz>816FsF9(VN75txh7sS~8e>Vez z3y|e3}y1F=z>r=LEEca@LnZf*~BA0ROZ5~$d#4)lIa>n+tGAx#s~NCh;!h=Q?&7t5~~Lk>mL*|1x+L`Ivp6mn?kJ^kK$c6a~%|NrOteLPR)ru^*4 zh?oc>ipx)wHw!xP<||VqG2mh2yNQ1IZKr30Xr(I7PBXU z(o_;ftk^?X5O*qmM)+A^aUR*s!>r3PlcI=3mc_D63M-aHQVj83+hHDKi)~wG8A%eb zMRFVzAa0kL4aW(lxy(-(A3@r7{KRdCcI^9^ zBwSWlMY4uMp(p@%T`0C7K$rnonuoRmLY9xP#5bTx(RKJi zCYfG^*s^*-{Ro^e4Kgw{Dlmv)JpjQ5bKwF@CLI|%59=nhA>e#HJh5GNjRLr(&Jco- zL=roU($L^w70~)&xPh+uFV&-K!K0w3W-9Hy@g@HWXL3ML4|%5ULen8 zlT@|D2@;VI*iada4446_ptp_#Sul*Cx7Y6>PlSiq8TyN-q=y}cXZX&@20)p=ihIP{CfA$Z*4W@ zEr$zzJ<~t_(0G1&!T9U{_Iz>DPFy@Dgq4(i*+1}U*ZiG1m)32#<4sRFJ5!AP>yZ}L zzdq~5lB&|C6*=qgy?nj!is#SN$*Gwo6M?qJgKJtd1_tvb_xS3qJuRh&eH)f1f0J@< z)4uq(Z_li{H~+s=+3L-xjU7X)ZvEUC-CLA+t^7d7$jI)tsK~;c&XdnBOC5Txp}1)@ zusm-vWl2G`{dnN}K>pDE=;yi{rVB@Y3B-HrtGOePxNz#}j}FD`z3|nlwikX+ZZ56= zAY&lKTUG9w&2^VN89D}o5=^>%~&6ID5>`0fk%7K&zZcY&F#znJTW|E zB5&cFwM~ly35&;HdZq5*>W9rM<&V4Wr%mNt{B`@CxYpR8I;^7!?Tc=wu6t&Du2Ec< zKIiz-xXN3dttqGahAW20Qo6MzgSk7e_{!(?CKyw`*?j|NY=7wG%F`JaWZ(VOm8CUr z$$no_)1uMK%W6)nN!IrL6EB>puUj#i+1xg}<&qUPnY6#j4&NW^MpZNn{t+Cq+^l@L JEAySt{s-!kV`~5a literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn4a08.png b/tests/data/pngsuite/basn4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..3e13052201c9f8b90172ea2491b18d6d121c2786 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtq=#3k+XOiwE*eJzX3_ zD&{2rIe*{)W9ys@6GNprI`<_tn04&i_AxF_G>~EoF-$NKa6jCj#n!|2C_^IPFayJV XErr@6uUk(54Pfwe^>bP0l+XkK+-D@M literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/basn4a16.png b/tests/data/pngsuite/basn4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..8243644d0743ebd1fdacb7923069fefbb01dab0e GIT binary patch literal 2206 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 AY5)KL literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bgai4a08.png b/tests/data/pngsuite/bgai4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..398132be5faadf83e159ac59c212213bcd43a894 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE!oa||uB7QDki(Mh=l@|1T-)pTTjSfo?;6Ga8{R(IDkmelNXRj)ZH9oA|PM{kg$m&gMT07S3iqx$gt>#1~b*D~%?ISJ;?`E{!%Qxx!#mpQpGpa(A8H z_iZ|MVh@5=q!mUuvSsYMxvKp95>weV2Kff8ej5&Q`t30L(azh))$_*RmQyw|G#2PE N22WQ%mvv4FO#oeUP~QLm literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bgai4a16.png b/tests/data/pngsuite/bgai4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..51192e731106e77cec52a3acda3d0c3cd54a16d5 GIT binary patch literal 2855 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 FV1na*GhqM# literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bgan6a08.png b/tests/data/pngsuite/bgan6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..e6087387639b9cefaaafb696e29a8bd910ee0680 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK{Io-U3d z6?5KRGvsP8;BkAXo|56e@Vk8|OTXfgyGLCsWP@G=X#A1))wtQkXb@LjH|PH@<7U}X zR(Ix8Y%6~9Ml4|WGnG@SZHQ?Kc`Uubi9hC!9z&%<$E5#{7BHGEsCHnVVk5wElR+}T f%%Pr9`U69dg47%_{vAF*s~J39{an^LB{Ts5$SFGl literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bgan6a16.png b/tests/data/pngsuite/bgan6a16.png new file mode 100644 index 0000000000000000000000000000000000000000..984a99525f5246cbc5d7083dd79006c7efa0ab0b GIT binary patch literal 3435 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 AY5)KL literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bgbn4a08.png b/tests/data/pngsuite/bgbn4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbefc3bff08a9d91666d6b0f8b5cb1c896b7987 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtq=#3k+XOiwE+VlDyqr z7#LRdDjNZLrk*a2Ar*6y|C~Q?fU$K>hKZrl9G&};8q7NOZTlD(CmKkxg%~E72)G|^ k&|>Rhdz2v&aF~JNzLrAmk=Ly!fCeyly85}Sb4q9e08Xzba{vGU literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bggn4a16.png b/tests/data/pngsuite/bggn4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..13fd85ba193369dbd84a0dc07f73d3340485fa6a GIT binary patch literal 2220 zcmV;d2vhfoP))?Z7@1GU()&K|^FGh>0bpfeScg5Q zVAO&a&cd+)IQ~b-4#C+!!^K_j-evgc3Haw<;qG2ozb?Ob_sZEvPslSDcgg=`hvYMk z4ajGXTJjykx_l>qW@VvfTe+?o@D-uE0$LFQyCHB0^d^MfhURr>7s1nDV+1ouL#<%toKz$mb>Sfw9$NoD zuRm}G@SOqQg}(RtLucx>YCvShv8{A1qgh$$yvv2EVP$$}{d$u=YBv+<<$> zz}W)TgRndc{U;qe;zHjHm@&lxtq9sLq;uaKEX`V3-=m=IgJ2Bwy%W850@T-__AjWmVEHyI&BE5vnjOu6RR!~1=)I3XU^n=GCa`N` z;CmDn3z4kv4ER5Q;0hQe2%muUIyBz`Zv{55N&()8oUQv|^#s&Q;Jg6KM`6i?#R3eZ z9lJjPkqnrxK)47!^9q5$AqbRZ=Ke3GbKe=Lm{wMcLvRp`K?o0mH3*GCXzzi}pcK$9 zL8Am~C8+-$oDwXT;6Ej(lp$8H*;_w@XaM?lK=@nenE~T33IV+d`W_*ieo zO65pa(?Hjuw-+o6To+m`=yarjR!h$6b*NThX$dM7D3xI_?${64p??Cb3WR?RJ!vqC z5Sms9gx-eGE@69UQDz=okTDWGOUB@SPF0`qa$JzcYho`!)75RHPl z0=;Pn{Q>l6Aovdm6v2NV0Z)VWYa%kO4`tQX>q0oo64?7{V3c7l9?3=$Fr0u!LJC;C z2LHYdbGKn{*|B#%3EM1)rol9!rw*Ys=wlH0IryIke-SiKA+Rw58`nhPywkGh&9{W@ zt}8R&vQ0XVB;e|8D;wVrKRqf1e0~nDz7GcyHG5YXVy7T_7s5ke7@&U#!B@e55VYf< z-GuHL=)R>8=sXJ@L*#Yiu!xMeBCFPF3E|vPfqggu@%?b_d?Y(QE(M%B4==yu*pHWC zpbXYD7_*=+Kp+7A1<=yay<3UhFGc=+?4Mpnn7YQ=m5Rv)f6IrzbiJJX*S!NE>`GEvny$wzr zcK+&nYq$+UdC*^jKvS(@O0A(|ON?rTRG9FTrJfLDsa8c^7d{q|*;{t(U5f4cH&VdB zKIzm|r1R#46x<$$Mgv?E+`KZQHzT}wcx9w z?OlokT3+@%loz&}1(|uXAf0#8(okm}W>PYu^r);W8@8JR^Rt9T!*Y8c_vY7KIBmWzUV9!uD`ZX5KDJ=baoZPeI3qP6{?` z`0=l1jx86($c$r0QtHO?uFCB*D!mpZ!v%_xWV+QwwyP)w_>!XS{*)+OFe!U(B!%s* zl+4^qO6Qw1;G|$Pt2kg~YZ)socQrF6H=--;jDE40000rKjw}eL#0B;r2mf= uFq$o>c3_`kBfxT#K{CM1p`KCt14EF4)EqJX9X>#-89ZJ6T-G@yGywoV#zE8o literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/bgyn6a16.png b/tests/data/pngsuite/bgyn6a16.png new file mode 100644 index 0000000000000000000000000000000000000000..ae3e9be58a823cf7c6535b1cadd96c45f15cca8b GIT binary patch literal 3453 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 TFaLS`e*&EE@`;w61 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ccwn2c08.png b/tests/data/pngsuite/ccwn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..47c24817b79c1e2df8eb3f4fe43798f249a063d6 GIT binary patch literal 1514 zcmV004R>004l5008;`004mK004C`008P>0026e000+ooVrmw000Gb zNkl1!`#jIX%gn1pggd$P9Zd(E8@>1o|NOaq`y>7F!|ZsTJzwK126G#Ly6%XM z@b-^5>QWhU%dqD1!_57RBTumVe+8~Hq9eTb8gGRJAwh?*OV}a2z_~^C|CZMU`+s$C zf=f^GMjIPqJ*EzYFsfNGT)Lap?PPm7_!7VJ=-g%pukx;sAJU$c-=j0zF+ofa5q!)a ze#6rhquT+FvGf6bpLReH((V#=343&VbR#+uVMHe)7;@qr4%Ccq1-RxEz0QX|?KUbv zg-D3?a5PfW@#w_lF{X>|p$bm?jc2~d`wI6~f#a;6WITuOqXKjXI#{2ULDi%_otUzR z>7gTt5je5J^Sd~Dle2ye@C#0R_#V2AZlgm~2OH2hsG43tH)a~4d#D*O2R?ta&G)tW z>8Ar@roZFTCSclIO*Ag1ArI+AG!Z7+1hzr17QOyU)Mwc7+NS`==$DuP*T?vqO>|IQ ztcPnUI`m>BLib<}*@i@om~~+l){c| zVM7=SBVi=G`3mjN^Uzb*0scX@ir!A!MZ4%0+DG}A03D)xh@t5bN9Y)dtvG|t!e{A2 zVJr-VH(rqM{a!t^`;)+*NnHXL-9oj{tt~?bm>$Z7h&)1VrgJrYXc=0@ma%1G8KuoD z&+_AUoChDj1~`crIu6P~xu_ZAq5Z4pRfm`!Wn^(jTpi2MGMYsT(bw1_m z-{DWcW?RoW2Sx1%q6`?p5#3d|Bp`vxK|FMT+rjJ7PN`Fx6q_I^ zHsSO@o_kdt`-!tWMURz18H)xjXp0u5EYvg!dKD%@(vVc71xZelk*1^>Sw>ormt<42 zhFmB#g+t{FiXi4}-?><#$4U#@DlI4r4PvoVssT2+X;jvbP04Gr zio7B#DN2fhGApO!Ash15FNBNxItO+uXX|?4s1n(L1}xIhR7?x<%j`IhKSXD!3`rZZ zhRl*T6jO>R>MU|4RaMv=y0F$9} zR4$TPn>VItC~Z@fNxj~;XU>`>Z{Pj*Eq?Q{1ADY{!yAorm%^@LYwChBA?vgK9NhuV zEWJQVYm2(9vPpCPqMTgf?}Pc|ffx6F>Cg}2g?nz4y9M0qW3N!>6l2^z@iOrMH$#`G zQl@pW(kx$*<@%1VVyS645OM(au{s2+Lb!Cm*v-(Kz~fjhVU4fw3PM64Z& QC;$Ke07*qoM6N<$g6Hha`2YX_ literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ccwn3p08.png b/tests/data/pngsuite/ccwn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..8bb2c10981594a83b7a8981436225d0b2241d27b GIT binary patch literal 1554 zcmWkudo+{@9Q~wiYbxpxyQH*PvQk+jg_3M0kMUetMjk0^ibC6FT8+ng>|mu<;>-?$ zm5gBE76za z`V2rL-V2)_s6XvdI|05qg3CyUFdEKU;xM`LGPZ>qA>#tN;_w)^vQv<0j}{EP(no$i z`mo0!AQSgK>Bh#O1Uo1c%9qgC08SDbT*Rc~7NA^cjuaHHr)sr@p!{AFnbKlF+h0Dke2lZ=BJFa3_1Pd-&6R(7q2>7?e`@` z2+zSi67nJu@aa}f)U3dTH8`j}NbZC|_wRhnwqpDkdIZnq^Mw#AAXh1rk|hC1a$`e# zV-YlQO+>2x#2+~ArqX?p(+hMM6oVzgAuTW+d5|lVcJnG(%P3BD)?#ZSHf%!Zby(CP zbrt$P!C~!psuiF|p!y)PNs5DXbQ*5lJ!*k+RpmZhEtn@Gs0a|;pZ zu~mOaE5qA45~jygEACV%-f(amkFH*arp)TM<_{!(td=Z&Rf=QC&qd6qVjPAfD<3nC zh_J^_V+ezxPwstYijw1t$B&EU&4{COWt zVR8e2Z{dXU?a)tyb#R1Iirg-^pTWKhiHJp<1{^AoqaTColG2eP?A-^hB^piMsr0bp zJVwAA0PXX=m^&{c!SpeNZ7$J;AsYN{&O*xN0eV#q7~bv=)=g+*8hLJE5TG$3=Ore@ zlDBF%NJ@Yi>YMI%3XnaBS#bVnhFOQ!p^C+C=TZ+i`hL#|-?g9Ev8Jly(eTN>(I6qk zs-@Z6yPEsqewkrTVN==Wzva^UFWypuE-|9M5ejGMwBbk&+nr}rsz)C=6Mg;7!p`W{ z*3~{qezB>k(KS802c-H%MJtOML$`!vXDrv4dA&B^?EA>Laq)wJ`AA9-`)?bXpnYtZ z**8#nC9r6}lYe*V7X^NmwdatS!q&aTv2GK}t$pbuI?lXOqlte1o8O&f1YZsfs{L&1 zZoz%=oa51tY^i+zB#M=_j$sXzMB?(7N*Xj(?)<=@b}om6+jNTRdt1f!@iLHfQk z`Im$Q_8Q769>r)~P>^hRDA_iy_5h*$Kk5ptj>x+)kf| zUCti|wcqQxc@1b(iexLF45xdH9&YI{Rtz*|(b+mwZY$GfOU5Nji;Hn)EvInIyw&H6VI7pV{6m$_g05>{kkUx-_69w3hFaYQorBj zDX_=;D|R(DV{iZR3fwcX5XUT6UNQ*_n^{<5*q_TfRA5^dnUj}yFa2X1o3rN@lnb*< z!|vRg*cA5kc1HTa*M$`o>FG@i|HPJ@sFVg?HagxLeoW@3zx4@sz5b)(>a_fdH;*5O z)i?OfjnGg^KQwW7n2!*3?6#5{%QaA_=g+OQ^R1n-BcAPeo8I7%7X;;=;1%j1i zZ)bCl8v&97rVft|P_iC!Ccs>)Nfzav-)4vs=ljCt>^(xPQBFB!f~}2 z33c`L-70SCvR3s|4U=$oHH9TFzjO1%!~RfY+0z-VM(^3 zbZpsM^d4*^09(kX9^w*ZmI5XJmB^)Ql!H<7e6ZY) zc`+QeUEqwtD6lI*MoSDvI5{}WC480&PtuOH*-2AVaV?E<`JCD_tpv-j#9PIaBFEN! ya5NvsJwe(+v{{WEX}38N*-?K$b^NQk+{YgmGj*nOAn>;U0000d_tM6?Z=$-SxY}-ICRK&4y|1 zVwc#f!dHA1xV88oBj*}@g$RWy_hMZ-KIm-D*-?;qSET3(i^4(8Km2Jkn4dfq@Se&3 zTKj@moXkY~bFu#0PPnZ(e1e0$_)enlnWhXC=IqbUUkI-WEMadnm^fjTNZTC0CDs-P zO1_Hd{`ll}k%^K0x`I<0XS2iy+u$b!SFTK5^fGI1n`4Un+K*`hy-NEv><+L^T&{2S kcJ9aK_IoSqvM<+joQ+wPvG4a1ptl)3UHx3vIVCg!05sc)VE_OC literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cdsn2c08.png b/tests/data/pngsuite/cdsn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..076c32cc082066dc870e1282b97c15ec22192407 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^mUKs7M+U~W1%@xC#RK`w#ZI0f zEG#VLKejFgaybh;B8!1EBN+Ru9=Qf&RC~HOhE&XPJr~G($U(&AVsKMqdZO+XCv8UV z2nJ4tMy~^h!kDxdYA>9+p~j^3=S&}?ojYTl4JO=Jai&15=FGw*d!IX*;+1!`qwm#r zn`WQ%3^IuS{KD+pZL<&+b@wcnUV-Cw0nJZSYySkqa&Hnkl_)Oke>c9oU4*NKQEP+# V1@X9R>wwN+@O1TaS?83{1OP3BOWptg literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cdun2c08.png b/tests/data/pngsuite/cdun2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..846033be6b4fdec08cc010aa0abb35428b6659d0 GIT binary patch literal 724 zcmV;_0xSKAP)9p$>iIc zM9BG}R?-GyZPG$D`^%XGf`^qAr06IYS+9p{fK&k*ZoATR1wD8|WCM=~607$j`vY7L zV8zwkB3t?J3uaPidN3!<*KK9Z0BA!^-Kg`Xnb*QIyQ{+A355#ayA z0cpp|nK|8N%npZU=nH)H(bhrG@~;!&M3?XV2(`}^e@baTp03|x0oH!)@bHo=j4KQ0 zuY|$dbUuo5Y|+T(H30UBc@<4A(dF}I3{b5$!14M1g8c&!K-bPLY`YQw0000Vz>816FsF9(VN75txh7sS~8e>Vez z3y|esg8)MVP)qc0!95k9*}y}5sLX|@B3D-GMbkBlwnNjonHwIy z9EcJJF%{78L==oIJhA+`7;;cFolQHd7RYGxEQK6edY*pw@2LCip7ZW~-{<*#JkP!5 zYYTEB!lT29C?YRceiiRU!SD1?JmuDki+F_~O=B_)K_Hn((}+hbb3KVH`hCQ#8wM+c zbFwxPsNG;gO(S62+sIEOu%KnpUADK`#I{M2L=HJ6NYwOv+-H@D_X=#9?oI+MS;V>y zl^XVO2yC09!Icb&nREm`f)AWc25B~!P{MT$qI?}Geug!qSF%UJX^=e(A@Tsq&y_e(IV5N zc2ombmUg;9iHZVhFq;*ili#)pv6lr^Wf$(E5sCtE*M(vW0)!C2(rmO95VCxjCB6Yo zimt;CGRgER#Fo_!>WATkX^@enQK3N$>j4Nhm?Bc~Cc@4FTut;EC7;Rd?q$9UQBAH#yE#JE|Q0|h>!DU_)gvGGGRzl1C&lfZjR|WWg|k-fq8#JmDTaBI#^STUG9+W$DsWo438O zx%khhimTsDdcDtYX^8l8`@k~2aals#tw5h$TvR^EzC~aJtyXxM{*Nd)reoq~rm{KwpXnEYf zqB*0lzd&-2CvWIFQhLa@dP&k(Dd*Pij(dA}O2xf7|D4KEZ$_?Z8(4n($A+lx;)H8u z)fq!W+gl8UebBY<#K*_xetq?5tDJr_srucF zRWSz=YaUiV+I4>B_%&@-PtL)FX`y5J^WLm!j19!cj=uCt?f&G4P0QquI_{@U+1wXV|N8?-P52vntW^|UZqc(l!@kKG^x7(XjPW24#8yrdL)E4&VZN1_vo8296 zO!#K>^qsN&VVBEKXIzkd_mj&@tKO3RzQo4)w=OTPI2+x=IZaHg(y>8-4$mKjGb gSyRUo_cYqm_AGEC_tp3R7W~7>%Px>RvflahUvG13wg3PC literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cm0n0g04.png b/tests/data/pngsuite/cm0n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..9fba5db3b82ca7725816efca47adfb44d61292f0 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk^Bp4a_!xt_BxxKPq}K;y)F)+dv$%Po8B#%=u~U{}NXebp5O&tsV_+x6KC z`n6Ov-e|q7d~>yV!S#P~w_ZMf;qcvgkAe_q@|8lddEI`uLzP=J4Gp*J^)`wY2|W3b o#w`BCU_;}R^bC!qjU|5>nikk@kH_`o5%P%0-tcHxz2242t zZVAjc7P#3?WtxA)Gw_j&*7KvKZ>J=PsTO88@_NksIICmj$1M%HOyBFza{Sr);QoBh zi@mlwB0JLF_+GF!ImvlsMh zsc5{>dRh7AYV(5Y|Kx7HeE!1WyYn6eA`4jdmiWEU!L;8G5Gbb{58QQCkh zC%`R%`Nje_+o??Rk9Y_%RXc^_wWto*p8A(!cU{aKDbTOZt? z&v~)eR!3w<+8cjwuIKCvE|l~g&^Ym)^~t2`a?9Sjaa+F#*wwIpUv)*n^H^rfc767O zek~P^H(D<%-&}28aQ&a$t(VVVIDB{BqaehYe5FuqUbo-vP~{d)L&NQQy^W$p0#81q oF^fMj*wFYSJwsz@W656zxtoVvfBf&v2KtG?)78&qol`;+0Fu^nQ~&?~ literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cs3n2c16.png b/tests/data/pngsuite/cs3n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..bf5fd20a20445fb7c9cf5d38a6ac4cd0fb28de29 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq@N1SHpV7(M_}Ea{HEjtq=#3k+XOiwE+Vi=8|} zczJm*nD-t8a_c-@978JRyq$iK_lN@rGdt(YQy#z8YiT}?Tf!kXZS7nxn;(ocNRJS_ct9{9$oSsu1^4G$9qOxF^ITqWf!_v|1&zuJmL90#Z}{$h z;X$oW3rB}@4oBt#ju#pq{&7g{v2S8~pRDBMFgMZFh1uQVB)dVdT4qdrSvt@q44$rj JF6*2UngG#&N@f56 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cs3n3p08.png b/tests/data/pngsuite/cs3n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a66237bfb3a113b7874d569367932762cd0ba8 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtq=#3k+XOiwE+Vi=8|} zn3vvNsN)kh^hn zQh3OQxBHhXtGq91lkmGBUgcb!!F~1uvkcz_zD4pSt$G)@WaeGq$X&o%(w=ugNaorF hmc0uYt(@e4Fe^D2KP>;UP7P=dgQu&X%Q~loCIF6>U!?#5 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cs5n2c08.png b/tests/data/pngsuite/cs5n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..40f947c33e477af3d4c13e3a56efcf32e6871be2 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^zg78t&m77yez7dv@| zu(GmBsNHi0a+5q=978JRyq&sHu)%@n@Dyu(NA}wKUA0-b10Ep zFS_6slkGtcsjSnkCm!EZ->w_6&B5QGsqfG`#!m_?Kf_rn1^#&$H05(u3N+bpIQ|n& cya`qx_w<}dzJS2a44`ccp00i_>zopr06uR!@c;k- literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cs5n3p08.png b/tests/data/pngsuite/cs5n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..dfd6e6e6ecfcf1d0be69730fb34292c8b6561376 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtq=#3k+XOiwE+Vi=8|} zSXo&m)b2S0xd{P2A+G-=8Jzwz9R1J0@V}bj|6Ydw{~3U6Ab;uq|M!3d14Huv|8p1^ z6#xH^0;;k4Zv_-!cm`I*@IOisq;U=dQ0cS(K&=cd|AA%zO#~X&0+Nz+*Khp_w9DJm z#WAE}PU}Hd#sdrt4F>Ptz55$&$0R-3;cHXa2ac?Rsv0cq2_h{`K_9r-92Fv1Rz46e wX^Ir!40F`E!P1!^p3)Rkz@>FiH{%HZu|hk>x7R-I1{%xY>FVdQ&MBb@0QH?@PXGV_ literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cs8n2c08.png b/tests/data/pngsuite/cs8n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..8e01d3294ff71ea83918aa7f99589c7f88da81c4 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^zg78t&m77yh6c)B=- zRLpsM)sdIMfX69t)`R5F>$8F{b!Pm_R9NudWu=&O_QeBy0tqv+c5v)_Q~Q&J!@#%m wUE>4C4G-c4A22Uq;csH)Zz^SCk$A@V`i@Ax+rlTSfaWrIy85}Sb4q9e0Oq;wP*-)CT0@c;jQ z2B6XdAldyud4`1l|LYkT9R35fGAR598n(G{b288_Z%-G;kcv622U!^p0CgC=d-v{d zv>lW5Rt15YCienPzJp3LSeh3I<}^i2;MQ`~516SSqSE9Pz!h~+uY+af0^y#f$PHY6 d2X!ls@@qb_WBltft&4Aruj!a10Ts~ zJwICdc1nVnYGHOGugAQPvpQCO+|rQC^u7Kp$Dgea?$77E*lVjJvLo${zc<%&_5~M8 z`VMHEc+dJ|(sj9IZ{4`9Uj*!GSii5jqTqQfvt_$JdqKaJipCqQmz8g>HZQpTPwv*s z=Pw+-JMU2t;!M6$C^oO#?{=tii>9IBcD>$4(ISB-AJUk`pBQXte3G7_v9z(|FN568 VL#{vmcV>h9>gnp|vd$@?2>`oyZOi}w literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ct1n0g04.png b/tests/data/pngsuite/ct1n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba110aa764ff4e5ee642b7c0788229a4924d383 GIT binary patch literal 792 zcmYL_OH30%7{`}afYlm95ECCT0X3y5D?Mmv3<;G|C`zfeL@oq|?R0nSc4yh0QW_6Z zB`Pss;_F}x)Pp8ol!HcNj8URV4;m%W;Nzf@CWQndoG|e@TZkTZXTJH*|M$)JANBiM zE&Mi~<2Z}A&3%-u!2Al?kGu3WUCWk2$<^WF^3J3j^H+OWy@|GT(;%h_;{2)(`~)QFCN!|B{t=iEQyFKl3pA11?%3{l4##YE*?fOXKY0?i7L zFo3{7)ZE}Gl#l^L9YKmhfD%BFK>?K!KL~Y9VoW0n(d%eJWA~VYNr1%#!bFckDgdu4 zDzOmrLLKq_3KS!I;xY@vzGk!o4JwE-xE;hXl>t;V83H!9sv>3WjHfzO4UGX*F|iId z1mIE>(2r?d2x(L{m{B2dvyUheJ;X-m&DXNm7#b4I?m*L#fmAAVlv*Mz2B#TAfP`tB ziCpvgh%5jIe5gBU(6u;n^MRPbh@e_iqm*c>R4p7Y3ndt&JeMUlL>pcHB)>|a4ucs$lG3@ulPNE1@BXy#w+=g z&%HGh>bR@`vHY&O>~* zIQ52(KeeX66=g2YR^D3jY&bCQe>8me$%!E?+f(2?ySG@oVB2L~v@IkS-pGsyV*?Kcce{q!`rdz)M R88w6Bye&TWor8U+{sI?(Ab literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cten0g04.png b/tests/data/pngsuite/cten0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..2f2d0c811d19a7cc050d76d9b4689b9695cbb745 GIT binary patch literal 748 zcmZWnL1+^}6rErYTN>=SQur+>38sq?FM>$6iQ0u4tBKe{piU=~-Jz42WoKfD2M?lx z9uz554@ImV1rHWM@S>OEMZJlK78NY$S&$wI`ZpU|!NczS_y2$I&wsnOXDVkhgCm24 zkc>A~zJMphPa0oj@!Pu`9%yp&1$AuqDbBISoZPwO=l^g+ABnfAfUu_G^N%r%# z!&o>Tce!mF=qPFH$CreZyaiXNf+`EBSb%J&mnxbbbeL}C$e!&lb)-$kA|)MmBjE=& z(bWcpDRP)|(zi+;C+b^7Q@O0J<<08&lOy+d=8Xl^s;-Z;XCWsPNgE zv57mqb)jwI0pp=+Ssf~W+#%CXSp5AD_RJQBNh(^r{|}UR@#%>3c$`C?Wquw&!n9X* zYuWp3YyaN0HOE<55n^+5s4Mzp6>l?2>E{~lfZ*N|`Yg1%n_1F1}pN>61UE-apl%G#tzWx`=#QlB% literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ctfn0g04.png b/tests/data/pngsuite/ctfn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..ddac7f446d4781ec126a7c41d937fcfdfb33a406 GIT binary patch literal 722 zcmZXRL1+^}6ow}dghY$rQ7nwbLn6uAcvCzyHflp`EH-FwI%cQI>&)(~J2M*=FWQ4p zJctN-k!m2`MDbP-L5M_AkX}3rDi%C=u?JBQ^lf4V5q5TXJMVq}{{O7Z)lZCNcV`J9 zW7V0;Y20bD()c1bKfKK2mTr}2%OrL6Ug`6#b6D?z#)4^pksOOfAg7E5ArzVOTk{qS zC-1&yF5=PQq_1pETZN;>1{bi@?~$`0CHH8=d^+E3GY~Y_8Gf45!_sLgFHiP;yHv-y zYC@S-K^#J>ZT#M z5wn^IB@~w)qf5#PM={HyXO*k8W)7XT z0);68Jc~mSlR|;d{laLlKm#VZG2AUsCWAIBChZZ!DpKHC^p#9*(P|iz0D1vTQO8jn zyIgCO^iTw2)J#e+#xkk{-b^$XdIIQalgP9?tQ)uQRJaO?KkOK29f zQHGoxdaUz>M&c548T~5iOa#7XRN%KJ9P(o25kr&w z+1po+q|%+Y`#00;Yi@?FJ?Y#%G`&ieUz1dCJ0U;9&GN4G=TDJIs>kY;heyvZ{|4QX B0XP5v literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ctgn0g04.png b/tests/data/pngsuite/ctgn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..baceb0cc83d6e0c0337c9202e7148a7af515e047 GIT binary patch literal 1188 zcma)5O-Per9DgQCpjlKT;px!`G<0Opp+n$uViJkvAP+^3^*Udi+iq9lZyz{retbJBhDc^C}JFW0A3!BVUm@{oD$N8h*3t2Qih8lf*zLUR$wYA7hnJe zy~EC`6v(ku98p@47qi$-;&PmesKQXmAbt@Op&aNvHA%ykx>1i|42l$CG)I`m5JJh~ z98F{82r_3a1TcKEuDA!mQ#uklos zHz^{(Q$=L-_#brxT}1lNcfejkyiMzL1PrHaDis`TM^rhpkb;yEqzWBjRQtVshR^SH zS6kWk)ZAOBva7z-11^tK@6!r@!g2XjJzr38E6^oIWqD+dGBw$jf9bZe$&=SE1MhmP z-R7tnpCQ{JR<*xrvuCZSVlh}!*Y%=evAwLbv8-b0!_24e=hk-*Ofi1(bt3V3{mGFc z`=h(l`olqkE=od@#*&W-#rHN(`vDW4` Jd;EM?_z!DujxGQI literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/cthn0g04.png b/tests/data/pngsuite/cthn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..11580f8ae71d1ae586776f08d57cc6bf1ec0f91e GIT binary patch literal 1275 zcmZuwO-NKx6u!n#P)R|HwADihm1Ib9m5ZF5$e~inp8bQ^BBe$ZO&#!0DMugEX_^ic)zZ4wclc2V@L-{Xd znNo4Oyj-CRJRt~R8h=)QWZ)NL``Rd}(;HKxT13~vp-kGRg0BjWe^T%nnT>V{lqQkn zl9Dll3Y3Ns6d@9VkO6{q!?GJ{!p+MI06|~^P6Q)tEcY@<(tT+nm@ZkUss0SCPclU; zA`s_sNfJ~Sg>e^fFcAcnLF}-s$ZkyTVW-@PMHLA<+{-faf~1(T!pSR39X2_w2tFtA z;$?`i=+hR(_nE1YL&BLV@;GH7xxfxZ za`Q53f(e>hI_H$03q(}`a~>*U2jzf3LW~hJVvlTnI7<--aTZdT88BSbXs|}NZc7-e zE$|Rp)&s%7Y89rq=~)oQfZ!8y0^%@RBG_5g_+xr>4{72W!)}uqD&|+%9qXoU$H;r;LqMIX0$n-8u%I2W%vbMAP6C3M*Yjrst?ve-U?{rJU zR=QJFkB@C`E-h_G_or;b!#nBT8&zl4jt{$d23#!Ua9<5xG2o&RNlb`FL@>faLZpc-NT4aTJSZ(`AE04jXU6hv z<^PKn$|n>k76cQ%1s8^}F|OU1nA=y{rHKhHM7;9~Zd|;1b7$^7=iGCryQ2Kj#gxnx zLdeCk(vm0m*NRVr3mN);n2SG+x#)2bN$Bw9MMrBez9#9bWW6L?Oc*p62(W!%bHKZR z2S|n0T-hSYCUQ4v_yq3@L~>D!TyL|-v!erJQKySMl`IxhleX1h)m9qo4N{{vr%gS& z?@&XX(bkkp9Jf7%Sf&>s#kS@bcF9~X$8jRw<;Z9!&`pAf;gC17un24(*evj6;6C6V zfK3Bm2etuxRtRJ(;H1C;zNcAsCyU1U3k~1K5_ZfKCAG1v&+c0u2aVUHw2ufVtH} zvPwFJ+*Ki=qnXA2y`Xp?2C-QR<`jl2po|Y z1t6b1hw`gk&fqZATco4H0PYbdY%tC|84*U&fU-9PbXGJ@af3N%0%CeZUm|}B!O7Ln zZ`0B6Ix&Mv+cUY%VE^~9LZSt9RSeb-Y=&etTbpECv(=o1t%O7SN5f~#<)$jVLpF%% z;cUX2J^#6nl%g5(^HTL!|X|lhZV4mHV@Ob9I*Ar-kl2j_U=9 z+N9Id&dkHrhV+8O`sxdIO~3ckYWwj-emME#rZ(w|cdLEuazaMivDG)5@hy~HOi205 VA6u!VqxX=Ilszmj2|lQ0e*wx&$Z`J6 zNzb#P8s2AuIsDFfoH=tXkmKALZ-1Q=`d*<1Teg^7-D<+j(4EM?Bq(Z%5YVvQAj4cz zi<65o3raHc^FYSw_HE=lWWeL{z3!;5&(i+~S|SAYC&V}_-LdfE3H>h@z9Dj7b$L0{ z?V!z*(zQ3RbHvuze{%AF`9ST7(P3V_yAM6v__yY~zu>c0ws!SHZY7mF>(Xu3=spqF zYyE1=?(N&QTWCLD_9?x`{4#-_N0n=i%(89VqQ<1I<@)8j^q#<%rc7M<{~y>rT+&tj z?Xk|)VE%yIyVWz+p51BFUYon-WoSjdd+w#BKfbWae+pyylvLFL^o9e-8^QT$CFO}l zso)^d^YYd4^bI_5KG-AVgLf~7rkwsp-f`cTpI5{UVGdHyeY?`*0udct2*HvZ)!BFOeE9Eakt zF(>xoL0({Ru?EO%IdFX7kX@*}flE2$(Fs;VMri}4oB+23<{Jy#Y^O5KKjInqNJi`V z(bBh562w#svm1Fm=6#&ivGU`VhFqra^=CQ$Y<+NlKIg?=TOE-dX>a_!xt_BxxKPq} zK;y)F)+dv$%Po8B#%=u~U{}NXebp5O&tsV_+x6KC`n6Ov-e|q7d~>yV!S#P~w_ZMf z;qcvgkAe_q@|8lddEI`uLzP=J4Gp*J^)`wY2|W3b#w`BCU_;}R^bC!qjU|5>N8=ISR z4CLwk<95#Vg>&ou?4IBK-OKf4I=h+Q-Yu4^`-jJ;=a<*F_w~o;*Jiu>-k0SMV?!`9 z1Vck`We6?}!N3q)7=l6z!b$|W5>ORnBHWgrk_!4FAm#v-gL4rOlDZRAQhFl5C-ouJ zT{shgf4PuS-IlHh@Hud2s6Ob305=7HTh$nC5#jVOMRm%l2)`fuP_1(!!tE!01i`Tg zNcxC^mI$IC_VFh;N<~=u^=Vc`@;_)KBFl?^KZrv^P&WiMLvUaSEP*Ak#4p5s%2-gQ R&b9ym002ovPDHLkV1h+qhR^^2 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f00n2c08.png b/tests/data/pngsuite/f00n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a1ffff62eb0f1f1dcdb4ba2b1d30473d3adacd GIT binary patch literal 2475 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 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f01n0g08.png b/tests/data/pngsuite/f01n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..4a1107b4637642335b8ec7b8e1856dc0ba7dab70 GIT binary patch literal 321 zcmV-H0lxl;P)}T4b;N0E z3!a!0=lJ%5$Eg%oz?c7nM_Pz6fDfO-!!(E~0KEA*c%UmW2WDfu_({31E3v>N-{Hyc z!o4_%Y@;b2{kGgyCmt~K_ux)+Vvc)%F>XgE7N{D;Epg%*RfD)GPQ0RO5I3R|@2DEY z_29%Oss?dQ2JwUcSEewBLHsU3nZgtbQQmYZ7(-i7*cJ?I3zBU?bOg~6L`VDql~F8% T6Mw4;00000NkvXXu0mjfmy?8r literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f01n2c08.png b/tests/data/pngsuite/f01n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..26fee958ce7e62a59843205ad34f86a525718595 GIT binary patch literal 1180 zcmV;N1Y`S&P)Qj4`pI zFjkU)u{F?Akfo*B!a}174J9nsV(#3X+5PQ?pp&O~&o{|^n{V!Obi%NV*_mQj=dbpv zm_B(tFHYo4wlii|=dbiix4xT4UZ{eGTtw$J**>tSy6N}n|vqif78L&$byRK9f1$SzrLzUf{!*^r3k$774rXm_7!8f1Q2+ z=C=8j8BA;b>93ttmB!R4Gqr2#)Il4ngL#p|9QHl^o9+4V^!;`CWzciKaJiBz*2s-A z%Q~e~hNeLo)I~S+8N27*(|0^}KLTZc)b*DYt70WpQX@6;tlY_+JY<94KKc3jyKkHx zc~$=bes_90V0+^67$}#lCtg&T@Kv!ADxnb@aaQcaP8xdm`scunQ;gUj^(pYH(^C;! zNn5y!L|KC#`k`FGPq->y@fF|j4L>V%d?yTrfgi+0@98t($EU{=wvxAS)ubd$_PkV3 z!A+>5imOt?H8kTouFDPFK!bmL?KbeO)596d+rNC?VU*+1#52gCK!FJ=R8*lsgBd#N zFko=|Nq}~GkP6E2D88M@l8GXUm_!xTsfy-kVs>rq&*Z3{>ZqRPX`b1u2fF{_*^dDC$unBQ(Ew)&lzW^YzR^hz^JI^CidP9to*K@y zNDItSJ$~`R-vM{)Cyb~i-{XO3q;i~yCk82yJm$&k5=WK56seJ#sF9XvnK_+adK+*z zf5tFI)>7;!5IcJyUb1-f+PNSFERrJ@DN!XcC2FQ7s?jpdPCtJOaPPm$D2$0wv{X9^ zWaZ)t@yIozCq+^qMJ$rnCC-%0l&Qw=-{Go9xBkqiT4p;6#CFmU*E%r}BWWdJiJY-a zF^Vx6Z~f)!f}4M1bjGY@*ij%CA&7a#dtxL;QaWQsUcZ|{DNGZ!QmbmEH8z2;34}4U zEce==fUtrOcu$DLNKC}F#?F@|D_EgSluD^gm7PG?1j0Nt7TXI1ibI5i_qeUYM`9wZ zHAc+m{muoO$dyvD%1$6`0-+Ag%UwbcF5n#U_<-~Hh>wJXPsDV-gPixfkS9{*C=fP* zFb&F3UG{zuavL5Oa2^-&5ueTk!)M~U--S34D@TE_2?QJDp|V`eAXY9N+By{R372qb zf6pNl!i29J1;Qo}(jX4E_qp%Fz4^!GobzySIy|o?)B5V>_Wt4V>G|dL?fv8P>$@@5`4A$18fipC zj4{?)>#TR)dmloGF-Am6L9i(ZNIDP1wql`V1IXeb3GF@N^}7L$OLT?eW035 z>s-(z0SrY%YCz?nO#+xF1yoYnBznj5E`aJnr^KQQpxV+di7ue_plgdhP^rb}TH<8U z-_)#002ovPDHLkV1l$} BmFfTh literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f02n2c08.png b/tests/data/pngsuite/f02n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..e590f1234816946731c677d0b353e2db5a08d71b GIT binary patch literal 1729 zcmV;y20r-x*}n2M`}#}vjc?j3 z-?s05&wlVj`|(fh7r(S$|JMHaC;Q7^?O*?~d&{=IVSD>_5?Nc!ER3!g3n}x;oHDCS zE7M9tnNlW|No7L0po}Y{%BV7;)RZA*NEuWHlu$uIF{MyCN=M0+Oi>NpMWV~bQp%#T zpv)_?%8W9jOe<4Ly-ylf#ww|%3|Gvc5-LF-)9o>#n>V*ev}9aNS<tNOUgyIH` zG-q7aJ|<;Bs%p}n(NLyR>cV6>o0KtOR2fOBDK%kO8B8li!+3&t(p()kWp0LO#<-$= zOvf4WkAB#DDgP)1#^?QNplUNhH+K4K#)MH}M8lng?S#!1>#?oI+;=QHd&_Y* zvQ2ag-A04p0Z)8E@cI#Yj2@#AdWt&Kp)E8)6V#)Eh6mnu6Sfn!T5QC&9<$>3pR;Ah zn~`mxSA%AGv*B#jvEq6SSw}a}hv?(JmFIitK6;2Y(MP>%q^zct!qYa9w`0$dr1uwhW0Zhu#4`YC3A2lof%qhmB?1mex?MvA0uiC*F<|9wjtewjbMGY&*`j zoNYQ=i;4%x3bKm)ELbUlhe-cy&Q~LkkWkfBOvHTK5^pVU&KE8zqNF%!6-RN=jJt=f zyYIStuDcy|)=2IKN9FDBuxB>$Tlj7K4t|&RE`A?>fIq}HX*X$yq{F5)WCR(dJ%%60 zUobyOQYUH9nkJsLcn-IKTf$xH1ii7(+IyZFAaXuHLUf39$aL7GW-`)eOjt5$$&|Gk z7SC8bXKudx>~4AcfL#|Bg#}?=m=$J(8L0w9n3UeL9uLU|&_U86bQr0b)M$_5M@xoe zf}~Ds%Hl?G{lDey;l^hyT6)`NFITQS5g;L1KsJC5kPe`O$dJh}?HYch$0Xw<6ZZU{ zd$-?t0XK_VuxLS_2oUXUsK?Ay2?S&T8dk=j$q?;fe2=lO{-L*jZof!e$2D-%xH*gF z^n8Gvsp5t2h@l@X8zXow7$3|f20{E)r!yT=R8p8tOF$?p``zg4{drQ+FJ#q^ho zXy)BBQMAcvVzRW z3^h_v5Ric9p5w+1ZrERCgI8Y-UVAOLeLHyLjo{85+yt&}QC+$AHbz)d7DMt5 zd6zUtb0njk;WJuFoZ^&7I1!H8G(892_Pp&Rww>5!%hqFCjqSd(WoK`>;%;>AP46PR z$UY&RE}af}mn)!IyrepUKyIwR{8>j(~{{02>UU6F*}Ye$EIT~(g*w> XLp~IzS7kjt00000NkvXXu0mjfY;#J> literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f03n0g08.png b/tests/data/pngsuite/f03n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..ed01e2923c92fd8b8786524c6d6841365a44b9de GIT binary patch literal 389 zcmV;00eb$4P)4Zd45D^U_MS@TiGz2aVLCXUNp&Fi;&<&!6t`aRYNwm-e(L$HR7llUs_2v2Lp?04i2#w>5 zCjFHgoS}>OqWhKs;-;4%0XoyCYd;H{ChLTAkL z`Nnmc1cXl84@#vy84@~$6^JKJlZ=Ubk`d9uF>y~YB0kwMamU0Lt#&uLFSbqGG0ztr z+6kZrX%qLj_#)n+{rCF=MU%cN0ReDq=R?P^VtFOGwjP)u6|4v*CxG_LFwq4OLVH6N jD*7N)_#jLSK#2GUV`p4Ky#5P000000NkvXXu0mjfx;dtp literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f03n2c08.png b/tests/data/pngsuite/f03n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..758115059d78260f7485521b83a864d4a930be84 GIT binary patch literal 1291 zcmV+m1@!ufP)=&S9{TIAi*MDSax9$V&z4Gt?ul6?wozPIOm-?GqbzHVVL0@-rxKGKhOL8k5O_q zSFpv3t*o}I*V_9Zvg_8{M;@~qp0pb`*{3(#=eF8yFWQ%0wy%ua*LT{9H|_38yXP&t z_Z_?MUHjhq_P_`B;30eDsQu(qd+fM9al)Sb+AZ}0v>o^z(58vARqwd=u@6n@Pmke1XD_3x{N{!lS^S@Mz)_} zdJOa7^M*h)z+aJKlpUap>FUU*babUGt;6i!o}sK%&_Ml_0}Q1o&Mu`O$?Cq66Q@JT z3RxIYM!*w1@Du|XA%l7Q)eI$}3>DD;e|4H6l$4TCgo02|@B=KrQ z@Wkm5Gr226kv_(nB^X7=$b&B_9m1$G>KKWRgkdJ$$Rs9|g_2{8Ez5|#T1H2TVa9h$ z(j;+7%SwO->aXp@3<>@U&;J{qzZIUl8J_zyJbOJn`+IoiYIx>K`1Q0sy`|S$qy4Ql z0v=}L_DlonP=h(73bQba+*O)>Gz;H^EtdX#W}j_9D|OAoJhWjRA~5T>Ndu`v9p<2x zV$3LYKl;cP4%*<5UG=dYJ8U03Vjuo4ycMs0P50HI0S#zE(=pl(GY{sz&C+xa)e;>z z1~aNPzjM$1t-?9LR-*64P#mG-1*D8@fZ(*yqnYop#)_J&`RW&@^-8p-T}(?iQxc|RDc*( z<`4s3eE1|ejyabvT}B)cWe8L&9Y4_UCg9tx=>U_B7``SQ&NPmDBN;&XQlhP3n_*jascABYwWa1geh;>x-+i4(U_Y8$pQBrmp@_v#) zgF2F8aQOzn)E_eOLYJ|y`CQzx3-$nmLD=V&A(sP5g05dja_!i}_ zgIDirr|I{mZhX~}7YtBA6@@6ph=h6QI6&Kt{O(YUr$lPFM|Gd{aIa#L7cd2c1x1(E z(Q=Gs10<^TF-)&&>U0cv)zz`6SBo;LJ%(}H?`NdF>L`))0fxOAVsvH`hUsg)nABw~ zucMi=tL~(v8Fzi|4FCoh!(J`gSItz-2XxH%{{y9tm%W$Hmi_<$002ovPDHLkV1gMt BbC>`C literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f04n0g08.png b/tests/data/pngsuite/f04n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..663fdae3e7d906df7379d92621a7a951313705cc GIT binary patch literal 269 zcmV+o0rLKdP){e2x4DAd1)!+NJ)f5B{T9psOdMM) z%F+|8FY)0+3~^>3vs1_&)hG|SqQp{zQhWvt^p*^yfsjOBNTM$!(HFu%2m|o|7A8yw TA(>!-00000NkvXXu0mjf-K%M) literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f04n2c08.png b/tests/data/pngsuite/f04n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..3c8b5116e72a63a3de8e0c1892c147071d0269e7 GIT binary patch literal 985 zcmV;~119{5P)hvyJ!8utT1VEc>UN*1Tj!qJPN}IY>N=sRACLdrt)_N=Jy&nmRP0foi1T3q z1vs!^NS8tnTiC(|3Cm|k`D(`N4+4W;;{3xH5HR3=UuuoS4K!$rOa`(R z?R*&X`GvfR1n&u#ACUWVNrjF@+CUA>kh2DD{mP;k>FRtL8*-Oa0-8az@Zi?_D?6u0xgjeiedR*>(yJr`MN%ucekr3 zWi?2)HMNKXi#p_|&$f}^7s7eRdN|{jt0Vw}4uOnAlX>OyYx{;(h32S_hezhCE(Fab znDm|v`WGp9zt{od@3wLWe5y}twl%v9eNEpS4jt=K5jm_s#Yobzz%^iBf5O6mQ4IVB z1gSS#SEq}Q@Y^iry7D|7u$1$9vV7%>V~{k^6C{`$4zP=FjwZm`$rGS zvDv1V?}l%U4QyZyYY4D{53qy=jUGER5T*mg4DDFWy$X8(2FG?szK8L%=^pMOKo~6M z$j~Pc+wCNgX-nw*aZjf2VMtF87IxrAsgQ{`|D+q<6)@}&$53fBJv+1hHpj`E}Y00000NkvXX Hu0mjft5eU! literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/f99n0g04.png b/tests/data/pngsuite/f99n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..0b521c1d56ac6ba14d82547eea5c87dae391cfba GIT binary patch literal 426 zcmV;b0agBqP)R*H$WiHScT#vd?>UqJiKVd^cv0p+pyQ zGH|gKM+__s5&6}tHkZ;`DS5Y9+rZhQ zwP@N_D-FoTR{3vHO$x#=5Cz~@tXf4-D8*gDQ#65;*9uNSx9chJUE%)%R{#^#^^XN{toLo}DWI?N<>C;~ z04ksXP5}*|#RS)@U%=Ob*$h}N)l>-ed1V5+W2XZEdA?ey6A(g5buxi@h4uQqlhPtM zpG^V)m`*nvwSYxHS5VI&O?NvOiV039lVCCd(iGV5g^==n1tvHiO#xM<`sZb@9~=`L r4yJ(5#RO&P7r+GDZJ=PW2opR2brp<;D@5J500000NkvXXu0mjfFu#U? literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g03n2c08.png b/tests/data/pngsuite/g03n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..a9354dbee6f36cf88f7b6277d3fd43b6cabfd84a GIT binary patch literal 370 zcmV-&0ge8NP)yO^U)m5Jsyp{zL>36n8GX#CQmg>mm9SE(8}cf*52*XGY_~ zh{+_6px=OtfYFFnf&gIz^!p-! z4E~_M*AoG%LANUc)ER`K2v7|=9TA|;pxqV$s(}np4O%S`KnAq|RD)(y1iYU?5QqRW z_=SEnxIkSs2+80F>Z$=A5dp}6`d>Z+8Ssq3bn47(xy-IHGcz-PeHq)$ literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g03n3p04.png b/tests/data/pngsuite/g03n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..60396c95af19fc5f14aff9f83d391331a32b3dab GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzD9ea;@ZUFM-0(?ST zfi%Pa|Nj~OGn_cFb}hr*yC5EjfA|0Ywf_xwDRcl8Bzw9zhE&W+)?jB+RWM*uY zOI4Q~40T|+ae#?Kl#?gtjDxO+)}>1i-Z_XV1hX;(T`t)BOm^#Pkb^v3{an^LB{Ts5 DR8dIo literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g04n0g16.png b/tests/data/pngsuite/g04n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..32395b76c9c0e1cb962743e8a9c8c41f319a26bd GIT binary patch literal 363 zcmV-x0hIoUP)k zMP!AUF&SCLg{ApYo}a%I2W<;z1p%J5#`A86=diAEu-(Goq6aWQ91jDiarl1YV72lz zSS}q6C}6R0GJYI*6ZWZ>;Ot> zZFbS1yTa-8J$*mz%z(DscaWy%bDwwTTMVko4oH&Ag@0}_C`%l49mFv}k^p3xQd%q3 z*T@Wt!e(&2nptb1gFLri;n!jYw;K*dqhSCu$TClZ{oV~g4L&I}i72HGV}Jkv002ov JPDHLkV1oB;ijV*R literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g04n2c08.png b/tests/data/pngsuite/g04n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..a652b0ce87ed2824e2320154aeeb92915dab7be4 GIT binary patch literal 377 zcmV-<0fzpGP)=$qmFdR}P2oOfV zU|<4VgMQxxxCU`-0$hV$&jh#zHh>I1V1Ku30$c+d;Lf1aF#%*iSJZBs0Cxue-@pdA z2CbF}AcGU^M}sfOy9O~C5WqFSD>^`)3~T@e862Ae{Ka543z8O#a*afilwMz5gDA=u z(`i^Pv*IGJo|YG6Kr_1mR;%nWd2jp{WI%v#Gnh=mdi~I3QXrAR9su`drSUjyHa}Ju z8`J_uqi|tJ+HSMFZgOR)ZU*mlfZeWqG%Y-fK?ZMifZqlgyfy_OgO{cNWI%t*O&Od4 Xkxf^INQ0u+00000NkvXXu0mjffu*e-u`Y1b?z zzWXd(t64Wrb6MRl-MPm3%bnSi&5lTH;%2!xfw$vO?LWcx>5tgDx7P8NE*G2%a+Rm6 KpUXO@geCxuo>m_K literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g05n0g16.png b/tests/data/pngsuite/g05n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..70b37f01e2b9e13a30a6e9d3c51a114a2f0953ca GIT binary patch literal 339 zcmV-Z0j&OsP)?t@NnF8DcSAbJ+I4}jD4==ze*zcJFZU7PBBkXpb0$0HQ1>69qAc{N%IA9o<0{k+y ztwZpB+XXm)2wVYpI0a#74`2wgEYEeVl>WRDLD#JdZnwEs3P4|pU@M>~u2)?HSOmDs z%O>jDD!>8DCayJ<2$}{h$mxDQ3z4SJr&0jRBM<=&(7Tr9be|rZe{e)l*V{)}8$|GW l@dAjTs?dUD3LXzX!4K_Ugk}Okv)}*#002ovPDHLkV1mh&gfRdB literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g05n2c08.png b/tests/data/pngsuite/g05n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..932c1365364fead1166e4772f29dcb7657f73f39 GIT binary patch literal 350 zcmV-k0iphhP)yIS#@w5JksQ*g`}>M?;BdsB#iGXl_D}xBv~JKVfNIcci2&6=2B-$jrU)Q|6XY8W5%7NoGC(z`*F^vs1lyuu23P2l z!4dKa0rt=jWC9bvghS52BVSt=-A}B^lR{o z!EBZfhpyn1c^lB7D8J-F$KT*fK)J|Z=K<*ToSF6eZn4N8k6hj>3?mmdm%hv(n&R wWU%o7coi9}As&7nsP&a50$ri)KG u9IC*rureVboiWQXC@_w%oP86+Of7~h92M4HZx@7u9OCKf=d#Wzp$PyhYDC`v literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g07n0g16.png b/tests/data/pngsuite/g07n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a47c2d5746fc93d252900c0b2286878b14a71b GIT binary patch literal 321 zcmV-H0lxl;P)ic&7(nC-rHzraP|afnxc^RYsd`d`5u7poSz$l82kp{Tq3Z6JE6!C z<~cx~GsZc95JJcub)b0oLy=wE_B`cklP8(MI6l9^UC0cE!3;nQ`rgu@>+B3Z0>z=! T&@6K-00000NkvXXu0mjfZ=Zkq literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g07n2c08.png b/tests/data/pngsuite/g07n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..597346460f1999fb225a46c941751a063ce744f4 GIT binary patch literal 340 zcmV-a0jvIrP)Ec1Z7JAAD^)rl zGc;g3%p!~-&*xWAO~jWXaK$Npe&EOP4FJlLpC7?~0$d0v3LyXpLqMLRlR!xgvP=k& z8i)Z>gESQaqy}ODGPs5U>}G%fNg@Ow1N4Z*fS)rkMhK9;MgMOA0e3K$8Wd6hG8n;r zXmA1Z-7-K1S_=WdAR39-HfGgLqn?XbwVVOhUIuloww+K0g9o7Nrm9jK0F(g&e1^=# z-V(Wa{fz-XY1a&35Di3ZYyEC(6%kphw4Tp(^SMg{u4DAwEbq7P7ygd;HOjyT;8iGt mb0`2ZIE4Zr1N1W+%HRPOfLawl;h_ou0000jY(XgVYP$Ug2i0{3Ntua3PevZO<6g^Ah?s$m6bVyVK1BpBEle`W(ImUKs7M+U~W1%@xC#RK_!JzX3_ zD(1YMYRK23AmC~*&8=hG7IXO0C1yqTPaJWFFL_6JBpnoMIXcsY>1ImurhiOn%Vt#m z5fC`n=)o~7+xK(flFC$FU60NsKN=pf&Dn9QJZi=3cwrm4I|rNBb9(vyap&(_JYhlR zCEhOE8{3?ktnW4_&R8ZOEj;gf4*xH^W5+UNujMpVzT34~{@9PX!h3Wk|Ka$Mox;Fy ze2R(Tv5(acSr+AHDoQLDVbJLg`uAs{=eP4));+&@o#p&$o;{4OIA-jB`e#}P$b+7) KelF{r5}E)9`D>*B literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g10n2c08.png b/tests/data/pngsuite/g10n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..b3039970c10e786659f9752913c41b8a26b1179a GIT binary patch literal 285 zcmV+&0pk9NP)@();|)eY}Flu=NxRyTwAba19zW zNcaI2oGKYjCc{&aErrDdt_X+yXV}i(ARy1f{s-JoAU8t`q60wT=m4lx4WLj1#Goi5 z0}g9&GjO^Y?CP)v$sk{c!58?k4IU`q1^i?TP{4Hwg$wQL5H j&i)?k>vRoL{Z;$`)U8ca-rtX&00000NkvXXu0mjffk|^a literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g10n3p04.png b/tests/data/pngsuite/g10n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..1b6a6be2ca571956ce45bae5470c03cd2266fd89 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+U~W1%@xC#RK_r0X`wF zKzij$28RFt|F8NV62kBw2K)ELwKW(gS)7nLjn&=f#?aQDJu;O{JayK!wx3QIX10fSyM0LA|{qo zr@2pEmRO+mfXPAELrdbu&4xCml^Xi(yO|>!d_)=C9<`pFX(h-9w2r~k)z4*}Q$iB} Dmq$l3 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g25n0g16.png b/tests/data/pngsuite/g25n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..a9f6787c7ab50968e37514529f53a6249762ca17 GIT binary patch literal 383 zcmV-_0f7FAP)$PJx&n)kH3|svhZZ(r0ivJ>sO?q;pvG#q^Pdnj*zaWkW*`MH zgTvuZ0}6;^p~3Np8;yq0Knh?6r_-MX=QC+2p~2;X8_lNB;Cht-m;nW}T0(={4L90t zp~3y`2b5*NfC2^sT+`Rg3?2{M=yd!5X7GIa0W_Ea1$4W905hON>h)}1tpH{-dv8qr zYh?yig&X}o0Kj6ArtTUrpa891&a%3ygBrvY39Yr(8X(K&^KXDL&H#scy)e;z2g~Jm zWsI8yn*n_$yCu)3Q-D0T+mfUnB%1+k42L$a*EYNPyBsudfL{?b7>)b@WOU@^z{4wh)7YG#lngB zpO4to4PwXAUtl<^EZyItpI$A4c0ho^z$dGfn@-I=c}&df(}j0HTdM#fvR(&W;o}K& zG9bWk2p1G&K>eeU5^p%h%I3sGP!q+00000NkvXXu0mjf+0UW; literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/g25n3p04.png b/tests/data/pngsuite/g25n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..4f943c6175f31c3609bf4458fff9d3c591f112f7 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+W8#6Mlqr_yhTJ0X`wF zK$<~Um*M|^0Re{pF+l47e;^$L6aWH-pup=-feKPQT^vIy=IlMUk+;Es$0ab@YvMKS z4NTlSPH?R`z_n#cTw`u=ph~f+$IqufMW?aPJ#nF}g1BpBEle`W(ImUKs7M+U~W1%@xC#RK_qo-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qG9=taAD!(1y)T7vK%uR?lygM zIK}cp><*ign#1-5wiApPcd>47oWOZOH-mqPPlA0u`y2l+k{0Ld8N_aQ--utQJ^wn$ N1)i>cF6*2UngAzTID!BG literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/oi1n2c16.png b/tests/data/pngsuite/oi1n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..50c1cb91a0171e9f34991b079fe932f5f0bb16d6 GIT binary patch literal 302 zcmV+}0nz@6P)NTxus~-YE?|ew94KIo9tHTv?hhRR zwrA%J^h9UxCeRmyPjW#d?oxNFL9(uFDZ1gBle+D$rIj`J+5;}Xa zfF63WfGT3xy1iYa$zve>zUI)9x>;M1&07*qoM6N<$g8PGj A5dZ)H literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/oi2n0g16.png b/tests/data/pngsuite/oi2n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..14d64c583db347908d4e107b49bdaf88e3857b8d GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq>1BpBEle`W(ImUKs7M+U~W1%@xC#RK^co-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qG9=taAD!(1y)T7vK%uR?lygM zIK}cp><*ign#1-5wiAr3HXJYpnk5G^i*Xn0_QnaE7j!fDm-r;u=d-`@{~~E|zMets XhWCy5O;z!=K$Q%hu6{1-oD!MJY5_^ zD&}0Bc95&tK)_}B1IPN)b=&{0{WeXGjd@a=TH53@RT6EkPi(I(=ofHeu+x7q>wQX5 zah-&%x^euuN1vn0w==yySE5m{$awnax1S1PFES>4-qaZX;>{9*dzc{lpeF5*>&z{m79Ma`yb}T3cx+N9l7QKY_b21tUy>hHS zj=$rVW!RSfocD`M`g^qt@_T0=(DrKPRwV_Ejec_{h{I9JdPiZ{w#YI8t;GR^e@i0d|ndJLIzJ) KKbLh*2~7a%CxW>E literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/oi4n0g16.png b/tests/data/pngsuite/oi4n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..69e73ede311c4a846a8f818330708658a1e0fe77 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq>1BpBEle`W(ImUKs7M+U~W1%@xC#RK{Bo-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qCI!=eVEdQwQX5 zah-&%x^euuN1vn0w==yySE5m{$awnax1S1PFES>4-qaZX;>{Y_l!4PL3!@ULbQoiNtWY z=b;I!`Z?mk+pi~%T4uHFkQ%qs0PKuo=U#gjgXq@dQ#YX;uR zyDEzTqN3i8Ri+t9;=Io`4iKjuJ*jdoASoRATB86`e`o#L4-kt!*XOIIkPy|$Z!G18 zk=$_R1cm^jDHwGE*;OPH+pecw0=8F|cWD7)9r{V(>YZh7s}#xX@Y-V@a8$R# zz7Nzll=T^a-D91a7GNOU#!3RDRppIxfH+g4`7VUA7;JpD{z%Gl^hz`rR!C-7WjBz2w=IKp0oL zbO>k?lt*0#RAuh<9{?e*sV()uX|32M9JssnY{osHpuWUu5cv8Oo7WFKnf5e90$&!U zD|&#%lN#4PfLz=wKl=n%AbF;bH~a_iR2$1}rLn7htMc}f7XqbjYTgrI+dp1QF98{q zx~>x7qmaPfO~8-eOc`>46CZ0QegN!tCr*3|kka8h&MF@x8JDN?qySsUVf_vKy0476 z9%wM?M@--UJ8OATkeUmSDcRFHm6nLa%*FSV76{aF1);#sVqI_>Kql)G-?4S=NapNh zVg_*djmhC=Ag9J7dkM%L^-MbokZB}6AQ$H>b5|DQ7>`=5gAqs{oMFj;fyD8u{}=gK zMu71K5`$&sNDOfBa_Q}rTV!=k^EBM^c>q~R=6AduZXuc8qS|W*kl#6Wnxp&)iHoCb zXd@uZXIuUPD6CbzZUDK2+Pw*)4M@m|&Mp?KwVGjB$JzxnI1su>k|SW z;K-2xP8~qD0I!0IuDeLqZiu^T&h0G>BMn)Ym=lSRkOKQt;)MxF$jp%`={{CrJA+}Q z0NGudCGHuG7?!!Lm%ady&A}>J%1A4M0{%q_gjthe+%dX`L1TnYm#8ctAc9 z@}pa>>=HU6*)gvdIs;@`N_gX0SxCrj<`CfL)P#i0DJdZ9W{Ka!FtV*beIQ<%iDapc zzwQpuzunh$8PLB|-d+oAxGoVK2OOgUZCC)=Ex%&=XT>2Qmra%!>Ggb-Hfk2fkY^() zKsHtKl(~0px+MSwNPBxOXxkqksf(TP*$R+5i!_m(4oOIRA3ry`IR({7L&)Y`5g+dy zjA3LNm(5d>Pa+|cbrc|HP1XT<>~@^s)UP}#S04qW zJ7f!3yE~lF1UCm1Ag?RrHNta!r8Eu0$jtfWu@_WGT8_ru{1AB9l%}=?3U3!0mB7Z| zi!2)ef4yhpK|nM&HhOB*ztD(3v5YRNcL0EJE literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/pp0n2c16.png b/tests/data/pngsuite/pp0n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..8f2aad7335206d0563ec5e8546bae83e16565080 GIT binary patch literal 962 zcmW-gPe_ze6vgk1W+4now6M&vl?^RQyA>2zjg8cRnT4C8a-ev#F_0RlCh$*z86iP| zaVyJO7(suuAQvVX1O;6NThywBgyle%p;kiF?Y!^7%*UPg-nqYX?l%`38+JvCR~8dd zB)L1WAJ5hPQxeAagYN1HJPOnCJ#h+k^;hS6n~B2RjrC1+_??J}9FY(yk@yB>bT*DpgTKuCNOVY>KHEazxSy09-hZpy3u#A`f8V zHsSyi48tL)AqHsN1Qs~Z7}}6FKO%n`+o-V&6GM>jhqkEH%nvXazo!T$>gO2@$wLLX z`|$=*dd46fKkdM#M|Gt4gY=kt2bIyaHXr#UDa%9SKVaIhyKeYwX|*h#PykDCr-AN)~w;?+^4yN zr-s8{bD3D{UA{K=ZMOCByHINGNoR9@dNzC}GcY)|Ju@)5BDQntP)ot4{Pc$K&wPET zb0n|#)BTaYxn$Ykj&#Mk)P>xtSgI$wXyNturRDT2Jr$Wxq-QF}D@JdO#pYwF-{qy3 za({X@R~7V)9!N#APsdv3V~y=a8^^ai{@Af>>)D}>Xm+S$ZFc#a+o9u`9GCs*$lY49 f5Z_z){0_hPQv2`7;*nR={=b*3Ye+n*O`ZD>%pJzM literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/pp0n6a08.png b/tests/data/pngsuite/pp0n6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..4ed7a30e4d16e0527c2695bf0493ec1ba156d8c4 GIT binary patch literal 818 zcmW-fy=zoa5XDDVMV1W~5)ehSNEfm%xBU z2&4*#Vrk)5qd16#e?&m+j8-!K=3aRF?(EE*Ip@rKwzzO@s(ZRCB2&ZbgJs_5>p6am z-v^V)Z(c|4^l$d%(39=C{jFOfho3IqSefU45fw2J7YUK9NLAECT{J|qlBQxN=3*h1 zRqHBl;w~QIS*@WGCgBnxkswK`q)EDDND_bzG*~oKoi(S9sk&;YW{o8>Q**UY%VI&& zP2JT)J&P2zVH&Ox8VN^QHBHksLzAhn1`N`$gcdmlgAFuTG-nB_nB!()mZgueMDFHc zo+TF+B*QJjB2f=1YAxL|ERlyF(4-qX&<_a|!WuA0!;(^XFc@s0!OC*3(!`u_&oUBy zj3tWjNPI;uEJ%8WCqCjd2EdDQj7BY1;s-S8#tt|k7=^F~4AOK$3myyx8|bVRRW)g1 zPO>qKL?2^`BC{6Q)?X~zMr)sKNkyvpUh8dE7RTmJZMz9B%1uKpztJiMZ4%IY4r~eY z(8Q?Quih^4C60%K{>u7`U*G4t?=SSOE=^ya`TK7B-cIk^kKIxK>$!`kdXxRvvtNF0 z{=1(CZ$@{A&yUj9`FybVvBPCeK0F$)bCK1Jv!jQXxa@3n&V2eaJ~@4&3S>CHFnD=o G?eTv$Q+DJ4 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ps1n0g08.png b/tests/data/pngsuite/ps1n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..99625fa4ba1c6964446797075c47ee05dcae22f5 GIT binary patch literal 1456 zcmXxkK}(cj5Ww*#aAOfA1P>uWA_;XUl%aEMY}7)@A`%EeORi%bMFPEcC<37_1p^(# z58$OQAu`alqXdS>Zh3N=`9rY#yvw`)eV+Lp_Wd|qc|1KiH`!X79z5x<=5@Z_-CWx9 znZ?_Anb_(*>$NNI50=lrzHF^Cw=;aYw)1B9?#A0!o2|;IT3D6USe-R$6&j%t8le#y zp-~#8Q5vOD8l^EBqcIwzF&d+B8mDm@r*Rsm37Vh@nxF}qs77!JE@{yjc z!KJtqm*P@fc~mxr%WxSk!)3T~kZN!lF2iNG3|Ed>4KBlFxD1!!N<=ld442_DT!t$@ zR)foM87{+RxH7B;m*Fy8hRbl}HrY5X$K|*jm*dJqs=?*B9GByATscBDxEz<`a$Jrp z2doB{<8oY%%W>uS)!=emj>~a5u3W0Y<+vP|<8oY?Wb^-3|G~f&xB^#hQ1@{KuD}(z z0#|Nd4X(fyxB^$;%EPO{6}SRd;0jzhS~a)=SKtaFjV?4UmX1mAVr#hYeYu!5+e{Vh*?JeDyT{@Zhyfr@Ddogvjv;XPO$z}Yw k`0#ss`FehH`ek!G(S~Q2+xLI{T(5`g;L%F|=;7$yKLBk?PXGV_ literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ps1n2c16.png b/tests/data/pngsuite/ps1n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7a6b380e9a2e60c887a260d43a41553260fc74 GIT binary patch literal 1620 zcmXxlUue~37{Kx0Hvcggjqqa5wnZ0q2=d=kL4nm-M{-~`!ka?f!Rk2%2GSHdS8n`@?ayH~ad{hwEnjwy0Kqsa!OTO|EN93>3xU&cXi8TL<6T z_xS63cfMIH^CJ6I2&=LtR%6Yv3XRYRjnD{<&?t@4D2>u6jnX8VM3ZO|O`=IOMq@Na zV>Cu%G?^yTWSUHqX>v4zOK?dMjTF&H5sial#U;1|m*5gy{x}+3f=h4-F2Us=iUyb9 z5?q2yaQT+e;1XPdOK=G;KQJ0xf=h4-F2UvFc%!%!m*P@fipz(M2AASeT#8F^IVBog zic4`RF2&^!qQRxO6qn*sT%JdROK~YK#ih7>vuJQBF2$v|6qg_6O~RFMC0q$t!sUZR zgDc@mxDu{}%g2lcSHhKWC0q%YBcj2Ta3x#`SHk6QqrsJMC0q$t!sTH!xDu{}E8$AG zd>d~Jm*Fy8hRbmIA<^J6T!zbV87?0o8eE3Ua2YPc%WxSkPrUj672m;(E91(ze1mw7E91(zGOmovw~q!_#+7kpTp5=i9u2OH zE91(zGAr)-96iXX{yejIXKXmyW6~f=;W#C=Y~#RUr~DD=C<7}Pd4V( zH~-n#+;niNVPDrK+m6lmtvvO7t!H)hgZe|I>Uj6!dzWuN&{h0UyVC!@}`gd2y$Mt{4pIX~;?82+n?%}i3yBA9R2bMfB^Yr&uM<0CVz0;%J!>30d8(#j? tiKe%Q>ay~W(faXa_sTCXI{$_Ic%%2f9ZRP!&BY%;-^MMK?|Q3;?gI^1pmYEL literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ps2n0g08.png b/tests/data/pngsuite/ps2n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..90b2979685772423e875e3504fcfee1d406d6a37 GIT binary patch literal 2320 zcmYk4K}%Fo7=}-vF^E!vi-@2W1+@s2p><45)If=Z1VNCbj)cC8aMZEGd0S>5Cs( zJyVm_Gd0qcmznjVR@Ql^~~0? zdZrdvOdOUJmK0Z{u%x&m$?BPHW%W!=R?o4*q*$@9zh`Rp)iX8wW@^~XkYryy^VYt4 zP9=Ty%sW{>) zq|8hTOUle7Sv}KLR?pOA^_=N)gPxgFR?pOA^_+de>Y2@C^-N7x&oK~I&$y7)Gc{Q~ z$Jzf|XMb5e<3v`^vD~r;U-oueZ@odkx4iv!b#3Khnd^M|I6XPJf2wok=+F7zj<`#D literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/ps2n2c16.png b/tests/data/pngsuite/ps2n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..a4a181e4ecfc378abcba1a2af79c0aa96eae57e1 GIT binary patch literal 2484 zcmYk4Z)ntY9LInAqm9Avh#oBGwjSvrRL)-t1*>k|sDbH-Jt?dmsdoql;x5t)bSqee zNKkNb>TLSJ5KOlMePH5(prGSe59(15hG-tNTI`k%!mfMs?)AmNe&6?fe)sx*KA#u& z(eTa}JKEQ`M^V%<^iukj#`&236U~k1#Si-y8b@m`^>Qj|nw;*d7DuC~tuQvcV`Oaq z;m7y9{pP+X(fEe`>OP`4q-;o~kjf#||4(sXlMo>hazvubuF(laZWRr1VAW|cg%5-gt86&BB` z!Q$D|`35{|PFOsv28(C!V;0Za3>MF-!Q$Bl%;H%tVDYRPES~M`!L7YNES}{A7SFca zV2ks|CmY^w52aHhhfn`p{I>o5Es69O3#ns29=&@1%e%#%wJo1aZp?mKE_6-~-s=Bl z`s2hv^z4%hCztjf8avwAzbPKA+^oI!&ei7MEBWNXbMa@jKb8-^{!>$?_SM8_b#b}* zNdElH+;jQ!w;oNtaA)^{mTlF=t<8T|cQj30tClb1raPu;LtQh^=X#&Wd{Eht%$(?1 zv-$;;WxjP*z>Dy^=4^c9w}F4(c<9=9i;ab& Np~0Q$O9Pqr{sYFSp`QQ% literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s01i3p01.png b/tests/data/pngsuite/s01i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0fad1fc982e54aea994e12efd3fe3584cabdbc GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?zc?q{RR^Ea{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y0;s*GHxH2&O@2a>I4&-uqx;TbZ%t=lFvY8kdJ=QNN1hN=BUHx3vIVCg! E01FBk(f|Me literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s01n3p01.png b/tests/data/pngsuite/s01n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..cb2c8c78261e509e7ef2c352306618963954a84a GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y0;s*GHxH2&O@2a>I4&-uqx;TbZ%t=lFvY8kdJ=QNN1hN=BUHx3vIVCg! E02xdg0RR91 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s02i3p01.png b/tests/data/pngsuite/s02i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..2defaed911a29507f745bd7183a9819b29cc53de GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^Od!n2%)r2CU%&n%ki(Mh=)Kx2KC^NX4Aw1O`S11~vx9e?93ZfWi!(u6{1- HoD!M4t literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s02n3p01.png b/tests/data/pngsuite/s02n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..2b1b669643540f182c425fb67869b7f97fe75f10 GIT binary patch literal 115 zcmeAS@N?(olHy`uVBq!ia0vp^Od!n23?w}&=BEQGmUKs7M+U~W1%@xC#RK`w#ZI0f zEG#VLKejFgaRYopTp9lVmyFR@1#)>jT^vIy<|HR1Bmj9V42<8zEkc1T22WQ%mvv4F FO#mnG8JGY7 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s03i3p01.png b/tests/data/pngsuite/s03i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..c23fdc463170faf97e53fccb4799386700b21a15 GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^%plANBpIb2ie~{iEa{HEjtq=#3k+XOiw8*-J9&n% zu&|W>*t!_VWee~Lab@_=@V}g49;WoqQ$(6ld^s L^>bP0l+XkKxV;@Z literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s03n3p01.png b/tests/data/pngsuite/s03n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..6d96ee4f873baf1df3652a8d70994eeea799c30b GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^%plANB6FUp{{d1g>5jgR42*3H3|~x(2T2w?d4{mC zu$2GUx){i13-AeXW%$qVzno#?)1~u)B7B}Mjv*Cuk`odN5)y#?V+@X#hCJRt7K5j& KpUXO@geCw&86D36 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s04i3p01.png b/tests/data/pngsuite/s04i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..0e710c2c397e371e4feab66add6a9f9763ce0c27 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFt%)r3-#KLAZh?DN<>&U>^w!rYkw0Iz&x!B1w zgoTBr{KwYCKrUN=Pl)S(hVuXa8D@QV-U$>D@pN$vshE?Tk-%_}nTL-@Si+8hL2?}n Uzopr0P-Lp3;+NC literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s04n3p01.png b/tests/data/pngsuite/s04n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..956396c45b5103d3c38dd8906be14002e5bee48f GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFt3?wJp^Voto>5jgR42*3H3|~x(2lAPVojgNW zSXjz`Y+VfGvIY2rxc+A-|Noz1)_3QfKoNdV7srr_Imtf`7%+0!GcfRQFf%r7-v+XT N!PC{xWt~$(695jV9kT!c literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s05i3p02.png b/tests/data/pngsuite/s05i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..d14cbd351ac11022eefcfa3bb2af528c3aadae41 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$9%)r3d&i3yCki(Mh=b^8f!C{x5dr%K!>0dAc};RLn`vNXST-!El6+N0&!i n!bU<#VwswOk4HkpRtAR1>$j<%)r2S&bt2^ki(Mh==jv*Cuk}VDtG(2QH%-+V! svtII_@t;Hw#zXcz;mHztXBa0j9DK~v7~1r+6R3f~)78&qol`;+01$C3h5!Hn literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s07n3p02.png b/tests/data/pngsuite/s07n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..6a582593d654c8d43aa8c8dfa8f6516e4f24c8c4 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j<3?z5j>~{cCEa{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y08<>}%WQZXm_$N%<+Sv-f=TJo4b eYw%F`{a>D;u##)1Tx>4LCI(MeKbLh*2~7YjwJ1CQ literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s08i3p02.png b/tests/data/pngsuite/s08i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..acf74f3fc4132609443b0555d56e5b314644bf23 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^93afZ%)r2SE-kGO$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vj!0%z$e6&;s5_~hX3XN8U8actlAYR0~A;Fba4!+n3J5qz{IFfcOc>T u0@fwp4bCJ+99*!q$#Hv=FS$q5Mw7orX>_}}cf hovEdPM`3y+BZF-itL;x80b!sr22WQ%mvv4FO#lIoCTIWv literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s09i3p02.png b/tests/data/pngsuite/s09i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..0bfae8e45678282b23bed2760c0dbbd736be9df8 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4^%)r3->c>4%AcrO0(btiIv2B6ji)rydK69~? zX9x=mOZktji-BC80G|+7hW`u<<^TUP{QqCh@IQEaktF()~}fr+~zg1bjT rBF;F5J&BF&_kSLqX%_`}QkWS^|FgS^^-Kp^#=zj|>gTe~DWM4fSkxz) literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s09n3p02.png b/tests/data/pngsuite/s09n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..711ab8245189b4d5118b4dcd49ef9771bf924fb8 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4^3?%3Nf7cA8SkfJR9T^zg78t&m77yez7dv@| zu&}U{|Jb@1$mI#}32|lk&%jXr|3Ab3|K$w-!x&P4;_{v@jv*Cuk`ox1e*fp;30o~G lp|iL#LdvQ6heDwO14Cvi>)|ZtdS#$e22WQ%mvv4FO#lN*C*c49 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s32i3p04.png b/tests/data/pngsuite/s32i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..0841910b72779aa7571cce45e56447eeb3de4520 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF%)r3-EjT<7$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c5&pba4!+ zm{U7pFJF^^h?~7@-J{?g64%>Ss_=bq+ht{1xSCJrO-tjMmhSi` nkfZu#wXNcYdz+%H|96_V1YK&G^7e=_(2oqBu6{1-oD!M>$PW;WtqGsLq6}$jpDV7@>y0l)ibBXvN}dz6L`X{!W|QK qt4`9uP~=9WliB7OneY3z7cem=9`<-$rKSgT2ZN`ppUXO@geCyfYFs4% literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s33i3p04.png b/tests/data/pngsuite/s33i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0dc14aba444d3f59f0bf77808ee7ee78ab5a48 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^iXhCw%)r2S>FoPcKn_c~qpu?aW7`757t`W_eCA>& z&kz9yJIm7?|5Q?Gve>sQ=2z#A&*U>UfA#bB(&kXT4uKE5vkQo zUQ-!gbN(`3qRGqhce6z7%EakmS0Y8FPq}6+_@ir6xO2`=y*VFuJPs^Aejwdi=Zl4) zY)`yQC*Lu~AJ4vKi$Bd@7qys2yXwnUHmtVq{n7=4!I#bZtC8xk9FB%)(-P6#}_whaYKv zG;#N1*N-P`3zt?rkunQiXB;>sd*S~OJ*$Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c1LAba4!+ zm{Z%gm#f)8#BG1p-0Bz*xXo g-$=Io|APMvAEo}ki@M*T3G^LmdKI;Vst0JTexR{#J2 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s34n3p04.png b/tests/data/pngsuite/s34n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..9cbc68b3b9d5f263eb64bca9ad8bdfeae8205f63 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^N+8U_3?xrvihTr9Ea{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y00D12$B>FS zQ_pYYZBP(ky%4X^8GYlzZKG+@7dEqqPBxHOE~fV1{h+qq6V*Svna^1j^)9?Ct99+6 zN12I`jtXnzk)}u!%RD37KjJGY{QS1{OXvRBqt2SFsin;wQV|yPQK!t*<5f${SKY|E by&mjqj=t@%(q8BXw3xxu)z4*}Q$iB}CDT{I literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s35i3p04.png b/tests/data/pngsuite/s35i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a5e0a6595f100edc1f79a3e0864ad6ea0d0121 GIT binary patch literal 399 zcmeAS@N?(olHy`uVBq!ia0vp^${@_b%)r1n`@_6HKn_c~qpu?aW7`757t`W_eCA>& z&kz9yJIm7?|5Q?Gve>sQ= z+doX6Y5h};;jD1&3&kR*!|w$e_FSCK!TZ;uv#nAtd0y%gzGN#yUNMtr9o7cw{d`v} znPPXp_t6M&TexoXtroF))1FRQrM1j3tI<%mZHpV5tekks+WAwqdfa)ug=wLE+m7oy zMQ7hT>LK{?oy%sWdO^0lW9vk3*7N!L?zPr!EpIN@4l($9_RGP?h0kp-%f1)C*BQ6t zSkfJR9T^zg78t&m77yez7dv@| zu&}U{|Jb@1$W;&U32_C|{~5{|{{M$i4CVjJK};YYC{Yd)E(fu`?q{2n^e{*@3Z79)POXW#oDtF1yr`=+itVv=OktFdG6g{K)mRoAX+EY7>z zmhXBt<&Eu!6r*o!cV_nNo&Ccp*=?%nxjo?-PXbeTw3r{SnJ?StNM`T3!o6nKZi}v&Xt(4rKl7t^ V?&lUg^#FQ_!PC{xWt~$(696v@lAZtn literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s36i3p04.png b/tests/data/pngsuite/s36i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..eb61b6f9a325db7d967bd796d3a65494bf6b7754 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|l%)r2yqPf);$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c5&tba4!+ znA1CPFITgHh@1WGUzfMPP>Mb3d2r#rz};nBJ2KhD%L@z2iugh<9M4MfUF6B#_T+KJ zyS#u&i*AX_`$J4FwOGR3+lYu(xyz9^Us?I$Nzg8@_uT%B&fwPAv<_h$1 zKV4X~uHW!2nO zw^mgdcYZzlI&jNId!5cjyapMo+SY3yv3S|MG5=1ghQ&wM_et*;#P6@Vu`=r)^ENJ> nM6Fzb-Rz~M-&QV*`e$h`)grF|l3?zm1T2})pmUKs7M+U~W1%@xC#RK`w#ZI0f zEG#VLKejFga@7NTLR^9Le}-~~|NkKrL;3%55EIA;N|b|y%R#KK``N64bh)RCV@SoE zeX02TU7fN^(b&f@AC0IF4)lp>A zamtZ6X3lW8^&N+fpX;N5a1N0dE1b9+oO)I`@yuDpE^(oyK}Bq#(;+7|2{WUFjT0Lq lq)!ST`XV5f-^|R;z~ISp;_}2b`+!bh@O1TaS?83{1OP(LROkQz literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s37i3p04.png b/tests/data/pngsuite/s37i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..6e2b1e9b79ba8ded32f713506b543f95c8720615 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^svyk5%)r3tu$^}qki(Mh=sg+HIV-2>Eakt zF(-9`wNR6RK-+&o*^hxQcxC(!_~<1(WXyQ8cE!t#;Gj#lmM+`0{Ul?NhPm`7gP#(U z&TKlpT{>aX1vlpoG2ywrj9K?;d1~@l8+XmqNYD|GnW?j3_LDi&_Gk5ZpVL(C5Y*hb z;_)GkI~OeSB#!?*!4ts2={s4)Kw+AwsIZx0;sW~{6Jr*4M-?k-J?sdRs5Q&mv0%AZ zytIqJyc-jCPuY6yD{r}_O<9KFm9UNB@vD7vZe722&ATSp?!|BMy_))a()awI`Eg15 zcb}IZ6e>9H6slHm#xw|b7U^#ds^C5mec`FsvsuL_-L{JOW$W&>5V^;FS zsTXzmnjHk%9_laj{iXhZjaU6f3%5cQ1CLzmy47pf9C;MBe%0{;2EMB|HJ5HS=D#U8 zTcE<&;mf3XHLadi$}J7S6KsC%TdZ8VLMtWoP@;^%GPWsSI*kflz0dEPDy4JU==ewT z$8HrlSvDN~XJuI*Zalg3>X&(%0bi?r*mu~p# z*kbkGd%RM6vU;~}yPmpD-2FE9?b`>wofE(7z53qT-=ZIGukYz~KPva4hT&JMP+%DE SUKyZ=7(8A5T-G@yGywpP!HFRN literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s38i3p04.png b/tests/data/pngsuite/s38i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..a0a8a140ad7ec7f78f5b8cb398f54233e790fe7c GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$Q%)r2?D{_Pz$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c5&rba4!+ zn6q@EJ$I9XOxyf_5svYTT%(q*Y;ODGw$)5_M`m;PZW9x8Q*O>*8?9X5^PP9_c=!F& zj}P}&avWz``7H13GiA$f!58}0_y?X%x||YHuGu}U@%Fz$#r)47t&6p-nF}}c@lTBs z^1PZ{v*FFH8(9sEQqM(?B}LEJyE$O3_FS z$q5XNhu)=5Tjidh!fa-!aP~lxV%mWM7U!NuQRf`SX00}f3tT>iIb{)A35DHSJCk^B z9JyieHiKao|6$!5cY4l9TNo}lec>oiL(-j$qysxN6CA{uC#7^J8uHKH+k8^@!3HLV YPnp`y=hnD91lr2r>FVdQ&MBb@0IdL5LI3~& literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s39i3p04.png b/tests/data/pngsuite/s39i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..04fee93eae400e745534756b48f5420cbe4a1d91 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^>LAR*%)r3N*;O+E$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>VvyPZpAc6d{hy(n;s1XK#Zdmg9K;0jffD5);c^h`>wY$Cpuv)!E{-7; zb8;sb7Bw3PxXwR5nPsxbIbI3B13h{Zl-LU%&pWl%I?8Km-rd09oy#9GScQZM32{6% zJn&)b?*IA=s?&@YhcsVH;1O9g(`9z%6oU2EhY-&tz!*HGHjC7g8ZRKA?r5euu=`tFBX7AyHo&^hw&tWyi;3*RQj<5NC7 zD$9QAmr-d~@vfp^>g%_&3Lb_R^iP%F$ND|O^6>H9g zXp(yF?QYZiJMI0h)x3XK|Fr(u@2&iL4zKdoR{mw=nP&Qp=ij3Tz`$bgboFyt=akR{ E0PqU5-v9sr literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s39n3p04.png b/tests/data/pngsuite/s39n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..c750100d55fbd07d216bcc5af538a83b9f7772a3 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^>LAR*3?%D%eb|5$OS+@4BLidG0>c;6;(>hTVkgfK z78aKBA6plL)CTy3xB}__4CM^}|3fH-^8e)^CXf%5Crf5MCykT z!yOH&Kayq_xt_}isYhMd#%sHX&9!mIgr_sq&#dB<+^ar$Z{X$9)vls_k8f1|*}8bi zpB=vzEdR6P)rUoYc6jZ*eQSQo)o-o)F5h}-kYN6lt?pKC%J$H%zv=qU-|SMRztaeP zGf~`5;@h^18+60tYao5g)5S5Q zV$RyWja;A|lo{eZ(@L`p} zS{LWU6$LrdObg}*USsKY346=g=`j6{lFBTGU2~>go4o6%r;zgB(0Rug*KVDo#;EA% pAydNHT#*-Kd$uF{lI;G>I4-d)zk<)z6+mAyc)I$ztaD0e0ssYck!}D0 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/s40n3p04.png b/tests/data/pngsuite/s40n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..864b6b9673b3b331f2956ad2299b7854210cdb41 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NV3?%C=ER6$FEa{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y0FS zXD@8zZ7|?*x#--bqd09rVn>dvna6z96-Ml=&4Mcg{<*&Jc=+gKnBVfCtuiaG{Fsq+ zN5I`d(XC(dB13ART()`KdT#Ey^-ixof4?!Sz`}fsxz-Y$_FSPy%NW9)eC5gyx=V3r k20fUweGf1AoYPn=%bN?oV&q3&xZP#{- zd#wGeV8okcyH@o)cboHb1rrf^jB^?sG2T2?@G1n)CJc@hyhCf)&E8%^0~1oF;v>7S z;6sBJiji@r0Yq=mmR;)Ojr>$W46R-Sau7HO7xZFtI1{|4z%-nLbW=B z3o0EAC)h$;8WIR1rohQ#w444G0#1m$Dj66xet|L#R>4C36e7xMM0T)(aSAa2XfV)D zcEU#my$(kCaRx~QL^LgQ_;=)3gHxFOXBZJd{maEJLqY3H<>rDuET^1Yth7z0>+1gi X{l69U>r1pj4E?y3$fw z3LPC~5Eu?Ow>bx*PBc1kWIARHF=os}<8u$TxvBB}f1oy5P`W{kzl6)>j^6kGfA2f- z`~RHyuLHPP3zER+gr^$apTp%;SiD#R;vJ2Rd{S@z+-2p1bTZD!RV+NOifLIU&uTs zaE81?yrhgg@q`IfRXqTjnr;GKFNW3KjX}4zVxZ4FgXd*s(ZFE9a5b7MKz26X)$9LG z&+U!?)zyVy3pqr7Bq1d50~sfsq>_}A+FGpRrY7tX9#13)1Tctg+c1b-yYP7603Ht= z!sEyY-tFzh#G0G016J#8z+$-u)Ys$P_ICWwmKHpkOd3!^xI`}9Pq-4f{bx0*+^SE_VlClnoi%|Y#7Z`h22w+;)xK8=@ykF38Wv&SbTQ0gnee+4}W(MW;&#YW1^ZP6=>`(a|rw5FIVVzI~X$*|S2# z#!gMe#Z=9B;j7ZcOd6B9%84Llg;62WOyR`&K*R&qyjI668Uj`Z|E0BdPrAU)mb3U z=~5vE2k|lQz4vDV3dQ)iLcy)1R&U>~RtxF%*YPf{2T4htok>Yuq?_=<#C@GZ=iYo5 z=;^^{Ll6SH>ZM@SDqJsaz8SmF;>CE>Y861E`I*cqfgzHR(9)8SfC~}N^;pQUV?snm zo;VR1X|s8~Hd|WSz(87>ka+ppv`GlL-0PLgx$e0gIE@Ozq2ur@DhdbZ&T-vi=%uA{ zke>b^i2=#U2|%mmwg3D$XH8&?$YhO;GMNy&cVi*2uK^!^h{x}~6Cx|i@6XCoC;|b6 zLP%p{c-`j{LaA(PQ!05pa651syuNY*7#3BC#C5-QYdp~Fal5x-1%_T%hj+WXu_HO1 zSQ$M%AtdlINl7uAQ&Rp+pr!_kf>jutJ}tzOC3gFgB?`sn&6ohpRG^~+6YzMHN?tF6 z)8Gvs_ItfP3Y9OUJ3g@%v-FJ~DU6%`p7 z)Olt$T~Sd!UsRM3M~+}20|P?D#rb@3aYB0gZM=f}n$%RcJ2lluI1TPj268{JSpMqw z(#Xj5ATJMVU8TZja7CF+c-LgQ0jykkmV}T1Z)>x&AAcP8jW9H!K(AMb#Kfwq#6%(9 zdJ7BLzaPqwJRVppB))>Rmzmkxnwc3qy>c2ne6jQN_2Kir{~kkZY{cD_MuP+Q&O34b zF&gnn<>h$S?_Ul|OJ@sx)&y8_ad~-hu@GD!97Re>K|xB&qDB4vixvs-(MMR6-Hvxh zNAcY06hf_bxzy_5Wv-p@`ik|vcQ5|p=ur%@xHuJLW+o7vbJnfHC+*q8Ezk(u?h8zy znS_T20^#98!p*WwR#+&LEn8-_E?XwV`1nk}hj4frZEhAqrE)q|DqbZx4c>IDBv*pr zVf@9&2+ll(g&73fVa*!eeB+b4x^SH6boqXx;$c0=OV$;L(@ za&nrQa&mYx$7%2ytRYH*og^*}=lHZV906rzC&2V{sF7S?0>KU+o}4^*waT#qxC!3? zz50+^bb0-!+_LIFVlkOn3uCR$oXN=hfy)oYZM=LTO5_V)JX0F)aUb#`{Px3~8K z45Cm8G#cZ?2?d2q03|3C!N$f8gK>%=kzAFOs;a7HXJsOhsJOUTC=>!T78DfJ0p#W7 zO#|fS<`x6+csvb_-PzgMH*VaxejVY*&B(||Pfw37i%v;TNli^nPEKZQ-I|z~7@ruA z92Sce8ykD3^-OehbYx^?czAeNSXdrFNJvO(?(>_pT_EMw{BQ#m>$Sn!qg3OkVyw9#4k*05u5X^#Wxw8I%DBhvS=>0kTjoKsJnz zkHa;PN~LfWvNvv&lMD4H5CQz1ooNFD1Ml8_0AO}^ckkGN(bYw&Ct|UTmX?<3ckj?> zcNB^Yu-39J8}w6t>_9>;(#;tUCqEAdt`EKrw%G5dUucga(q-6VG498*{K%rij4wv2 zoEfW%jzHYO{1#TLQQ`9W=k@mzoI;b9QinWz_A0mp3_C3m`>c%tC$KR#Xus#^maPqG>$Ip&r<7PP}+lo3xrqrK0bX_;b9>)$CG zYiDOPWRFqn6UcGDpA~Oj9{Dz;6-NwxejzAm$n^KEA< zw~yjS7UP676`?(gNA_%Ti&?JTRiQ)ukN>niNvk-4K4Y-(eYokz+n%p00U^e=@{X9+ z)rI4_;#GQ*EM)A{+^B9WciOLZ)vuJAK75`z`)0L0X_*pJxWq7Myp(uq&jr<7|o zLnIyhWR@l$6GSYpXJsSmv@J23K`FjDRPrN<`4!1UJg1FhP}`#*W-iAZNy`g6qae{l69U>r1pj4E?y3$fw z3LPC~5Eu?Ow>bx*PBc1kWIARHF=os}<8u$TxvBB}f1oy5P`W{kzl6)>j^6kGfA2f- z`~RHyuLHPP3zER+gr^$apTp%;SiD#R;vJ2Rd{S@z+-2p1bTZD!RV+NOifLIU&uTs zaE81?yrhgg@q`IfRXqTjnr;GKFNW3KjX}4zVxZ4FgXd*s(ZFE9a5b7MKz26X)$9LG z&+U!?)zyVy3pqr7Bq1d50~sfsq>_}A+FGpRrY7tX9#13)1Tctg+c1b-yYP7603Ht= z!sEyY-tFzh#G0G016J#8z+$-u)Ys$P_ICWwmKHpkOd3!^xI`}9Pq-4f{bx0*+^SE_VlClnoi%|Y#7Z`h22w+;)xK8=@ykF38Wv&SbTQ0gnee+4}W(MW;&#YW1^ZP6=>`(a|rw5FIVVzI~X$*|S2# z#!gMe#Z=9B;j7ZcOd6B9%84Llg;62WOyR`&K*R&qyjI668Uj`Z|E0BdPrAU)mb3U z=~5vE2k|lQz4vDV3dQ)iLcy)1R&U>~RtxF%*YPf{2T4htok>Yuq?_=<#C@GZ=iYo5 z=;^^{Ll6SH>ZM@SDqJsaz8SmF;>CE>Y861E`I*cqfgzHR(9)8SfC~}N^;pQUV?snm zo;VR1X|s8~Hd|WSz(87>ka+ppv`GlL-0PLgx$e0gIE@Ozq2ur@DhdbZ&T-vi=%uA{ zke>b^i2=#U2|%mmwg3D$XH8&?$YhO;GMNy&cVi*2uK^!^h{x}~6Cx|i@6XCoC;|b6 zLP%p{c-`j{LaA(PQ!05pa651syuNY*7#3BC#C5-QYdp~Fal5x-1%_T%hj+WXu_HO1 zSQ$M%AtdlINl7uAQ&Rp+pr!_kf>jutJ}tzOC3gFgB?`sn&6ohpRG^~+6YzMHN?tF6 z)8Gvs_ItfP3Y9OUJ3g@%v-FJ~DU6%`p7 z)Olt$T~Sd!UsRM3M~+}20|P?D#rb@3aYB0gZM=f}n$%RcJ2lluI1TPj268{JSpMqw z(#Xj5ATJMVU8TZja7CF+c-LgQ0jykkmV}T1Z)>x&AAcP8jW9H!K(AMb#Kfwq#6%(9 zdJ7BLzaPqwJRVppB))>Rmzmkxnwc3qy>c2ne6jQN_2Kir{~kkZY{cD_MuP+Q&O34b zF&gnn<>h$S?_Ul|OJ@sx)&y8_ad~-hu@GD!97Re>K|xB&qDB4vixvs-(MMR6-Hvxh zNAcY06hf_bxzy_5Wv-p@`ik|vcQ5|p=ur%@xHuJLW+o7vbJnfHC+*q8Ezk(u?h8zy znS_T20^#98!p*WwR#+&LEn8-_E?XwV`1nk}hj4frZEhAqrE)q|DqbZx4c>IDBv*pr zVf@9&2+ll(g&73fVa*!eeB+b4x^SH6boqXx;$c0=OV$;L(@ za&nrQa&mYx$7%2ytRYH*og^*}=lHZV906rzC&2V{sF7S?0>KU+o}4^J622^AeZriDs|F)fz44lCrgvCaK9(i)p7!%%LO z6LCs$SZ>MfJV}wPPOIFlR1QvYe%|MK-}ia{df)f+{c@b0>@`sOC;-qn<$!ZVI(j`f zDj^kjGph?}%2e!GEGVRlO(*lc0TkamJGz}*TU$#c5*r&IR@vH?l$6w=(b>AXMMXv1 zx04DB3jtEEU%$?+^=WBow*aI7Nl8fw2?+qjY&IL9hsk8d#>O5wLZs8_(b3V7k&zD74p)(r z6#W5wi5%j-eJnyYfy3casnmdg0P-cW&PSbeL&Go(2FJts`1l+vI)>xmtn;h^Zo*f9 zFF+!ZJUl$y-Q5WUf_a*`i;K%{;ch%0Z)Jtm(t1?CX%ln~ww zvI4CLn;>X`*DqdZX)#srsxB=p0rJcP5Q$0`7Z=q_)!{xs9cb~i;5IBQEI>6tCCtyy z&(6+*5T>W60ceneP(Tm>WPquush*y(ii(Z4cCD)F{LssxzP`RZfO2EwuCA_*j*dQn zArvZ!Mq?a5uB3Dcpag{?+Sxf^v1cR6WET~cs;a8FIk{LYE-o$>i9`TRH*Vah2Ph~g zm;uPo&o2hx^Z7bDJ92Y#uU)%#^(w-Tmz9;3nVA_=7L%5lmY$xTnwrYkv?)0`IX*ca z2^NbL7Z-QB?Q~2`OjJ}7l7z-JS_iG7g0sVN0Uz}3~&+1VKez@Wfj%a%*<6dWBL zfByUl>%J=rqtT`{H60urpc%{q%@q~D69^Qz2T+SJUKdaPBUi= zZ?YsBS+ans&A`7&dFaENu<+a*|IhOD!Fy5FU2($py#tmf$d>!3__F$7Rx`n0Xd`(x zXNPrB#Hf{`Do)y8Y}67x>Fw{qlr}T!YF_4_IUZux-oC*~jH=jeIQPaX!`r{y1WzBl z(m6wK7D&e$Zg(V>@2C;Wf~LRR?X8$9#=q?zc-|P5aetE9NbV#QTKGtM8suGqBBx#3 zxo@Q}hx+TEERS}!iYl~OZDE->d_uXdy?`@|M5G4?j`=QYAGR)#`a zvNJkHwy@!`Y;;2I`Sq)+{L9pEnB}|hM@{;rXnr^QKIxlagyn~gH+uDas6JD-A_hPD*sh|5-pZZezZNI zTBjQ-?c5``GX0PwW_dm>8`Y+1#_9&A`Q}k652Y3f(u)LcJ9%$iuabnh9D6vUApEqF nBzr1Qcj<%PHtn77gx$)ZQM<+~5{$JW7KKwMop80bl;r;b+-;m} literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/tbrn2c08.png b/tests/data/pngsuite/tbrn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..5cca0d621047cacf1637cf7d77e997d51cc6b15a GIT binary patch literal 1633 zcmV-n2A=teP))6_}Akuqmh*5X4X^rIbM;BH-v?$kU01p_ErCl=u4~ zL7fbz&H-~9!(}3aFu`RZW&unzb50QkgK2!RYsr=o3t~2tT^d3tzx&+X@9uj)%)Vj6 z{|IpB&Yj-g-pR?y{}^!Z-o3WAwzRagh=_<-fB!T`$I~7jJzDL9k&%A|7#|<+>gvkP z&5eqRQiO&cb#=`%Gt&SnAO*+-su`xq!J$j392p#Z_UzeG0aH^`SFc_zD=UkSkAGjG zNZGY3d;R({hG_tbfDeIqE;r1MUWVZftDkNW!h zs;jG$lamt?5{`w2W;;5Ta5(kAS>OWD3k(34fhLB@x3Eyz+ozkGX8`3uA)t^*Vq;_J zARVu%si6?50P_I-{r&0b>GXAy-pZYvJ_kMn+JSRiZt1pd#bWVg8=D~(>oza}`~v)> zM}7e)8HRFA`iDhFM^mix0K>z>DwQfHCnqyAGc`3;6%f#2ZhqFvO5^8uBq=H7FUwFU zT6XLhvbG*uwdz+cchJo2l$~8_P|)B15EmC05)$I?@88+kIS+9E{(W+tk&&UwQ56&v z(A`o(AH0rH_Tk~-0RaJGvDnww_wL=h^8j=?>6z)a6}IeCY}aO2b*Z|fq@=L0@WhD| zsSDdty^(jSiA*M&bM5WzEtks;bWvVj9&?GoHDC(zc6o7eG4)bKMMY_8X?Aw@u?6h# z;lshf`|a#hY<3Bkd&JHz$kWs3`0?Wg0OXPTF&CY{G^|Igi;9ZKH36!ss;DvOr&_J1 zx~1t&sZ>(M4;(lkk?c1!`x@w{b_L!AqU`OZt*xyF0OXE$lBa8(+d4*aQ!-UaQ=##! z_w+pDSx{e4UteEaTT3@Y0IErFaIj1kyl&n1z;8e!i?yF&L_nC8m3(Mu$N-?Zxp_n7 z2DAX*=>Wn$A?4)L>VvOzv*1+iR99Em(9l2wMRh0dROro{PXe>RH6x>UEG*vQa@TOV zQlU`t^yyOrfcExwL7@Om)cL>za2|4U%W^%=c<5%V3NB?X6h0+EjKsu5@-7xf85_?~ z_(n!?E-s$Cckkx$Tm=FtNq~V#ChO_xan5qaMSv9N2jF-3*7yqRh3Ek)Au1KoO;8fV zprIvzKyXeU{%KoVxrc`zkCz5CFib&h?McIcn>TN|Dcy8{RDkAq5^L3Kg|$LmUsXU< zBBJ4(W03sGWO5UeaSET!R&3c4%;9JOl9gkorlAz5VF1mVSE84$J}Q`0nqU|>1Di@4 ze5+F&_hR?T%1UBTp~Aw#cJ55qhku#R59RT^^+74-!fSSE~<7VgEJh?uUa0qm; z8Ez47t52=QkANEJ0t(=x^_iQy^73*TT0XxG7zGZwyYCSQ1YB+maEUU=$|_zAke{D# zTyIS3>>TO5U9}y3y6WrNG#}mt-ZU1(ApHmo3|zUggX&{s6zS#V<>Yh_y5_4hF$wDK z?p_S=`P`~WeyGw#>B+X26iZPz^D41kPE3=O0g4z6qf*N)=*PsGE4-+(Dp2{ zw2Zxeeeh*hh5=+_V`EuaSwV3@IIpj54kWn}jYdNZ8e`JrO`E(~ENUAnPWZ-+iMMY3 zY|zhwfLVQ0wY0S8#Df-Q7G&8n5<6nh7)vA)kx0bn+nAbqczMM?d^oX?lf?jYc4O#< zON|S4tujMN`;Hh?Jz7|PetuiGZY4pbYg^pItKUTv6B8tGw0Wp##Go?l literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/tbwn0g16.png b/tests/data/pngsuite/tbwn0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..99bdeed2b3b8564302d449e6578c4aca0f6261f5 GIT binary patch literal 1313 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 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/tp0n0g08.png b/tests/data/pngsuite/tp0n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..333465fcdc9f10f7f25b2d999b558f5421983ecc GIT binary patch literal 719 zcmV;=0xe{x-64Dw5ISbDJfGPNXYF1fsnx~?7~M3eMD*m6rOMo0;2$rUW>-c(^**S*Ycd0zuX+u!1|S9WB+#F78QX<>lo? ziQz$h-hRnIWoQ!H=elq>2fX`s$g4Md}>$Ugu1e*ygBpcmqZ3DNb_5HNEsBtg8Fz$MsRgsRcUEt!R)#7 z@*=Hdg|%Ijgaqfp6x>M8@W|(*DezA>78ATBV zGiJ?6^pq7`pj8TmNNXtGQ7M(fr#kNOGpUKtO+a# zE}lAlTDXoRkAt?j2v0jgK~H>oU`AO)UQprWsr_L}qI~YALPA1E5ej}SPEJnGOv?!@ zojAEOR7Ob9QdC4?8%mP9keiy8ksVOlKd~`Xk)KCEK=mA2ntaoimYx|<+}mFjqR+?8 zZTJ8q(f(PLp6*}V-CGiDD=qBv7F)8vQWR0&(VZLQZ(jZjd%k$Tpt-FhJuqOwUu^jT z1pXapZA%Q=jx2U BP!RwC literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/tp0n2c08.png b/tests/data/pngsuite/tp0n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6e42cb420fd08ecd78340256157fa5f8a22934 GIT binary patch literal 1594 zcmV-A2F3Y_P)u542F>)wJ;-zU<0Ta5X4X^rIbM; zBH-v?$kU01p_ErCl=u4~L7fbz&H-~9!(}3aFu`RZW&unzb50QkgK2zirzKlPEQpyV zJ88Z&UwhB*+;h+QpNot)Z1^7mZr{G$*Vi{SHT9YSckkY9Z*NaePmhd@j0*@zcXT}E z>DjB%+#enNPk@PuiSF+1yu7^V=xBLZ*b!IPd^0mOpafEZETD#AngxPxg<^DQ=;_m^ zO9f0%PhYumrM$d6AtB*?xjc2}&YX4Y${D5+CG4W_vSdOD(DVN&-oB_@QeZU}a320`R0!vG! zgF}Y7c_vT+6ajLvI4&-Z7Si(C+FA;c5-<-iFfc$*`Z-x=6;4i{1D^pMz*&|p+q$(x zB)Vj4J8WQZ3z!6c0e;dUzW@{rLwimBm&L@yP^|L+BO@b9r7|}+H!CYEEiFwM7}#lU ze#Y8b?eBj$IXU%j%aqGow{IV|u^C^v@>iA}GBZ1AZ=V(%{LdfavLmWItxn1d>CixU>w z(z&H&q%@~cmeiGMuLdu#(_V!Qg$)f2b#--gLIj|kgoK1hr6FtAeh>TxG#MD|V;DCe z+}c_;JUpxi(9+VfzG^*Mf$y{cVZV^}t ze*#wx4d1b}e2ZmQv#dlY6hC?LL=T{&qk~_>M>ADEa39m2fL{qvo7rko-xdG82;t3ZKJ~Z{8fjKg!o$ON?8wlCe~HHnv#{{d1tq7Cl~vHp z%#3~jNv`NUkyhKvAxIVA8=wbFDWm}$)k06v92)E2}b{Rj#QTCt*&@?&Ti zD zl4Z+2B9B~dgtK!fhf@n&;PLjfw||-Og6SEVLqkKcv9UCP1w{gUs+$RUkfbMoF`VR)x@ASCQaVB z(Z|4m%7&5?v0+2f&6_{#^|K%#LswL-t*u(|pn;hUX^xb{ju_O&VzJoG&5g&iH8u70 z_D*>4U~(ZRivi~B`tWs^S{JHXMW%x09Wf|-G_d^r{kLq{LV`-iwz!9v--{+ECrRLF z@=(%OV07*qoM6N<$f`h#14gdfE literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/tp0n3p08.png b/tests/data/pngsuite/tp0n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..69a69e5872234d96cab4cbb017a0933fbfedba81 GIT binary patch literal 1476 zcmWlXc~H^`6vv-Om}J3dn5OOMOgg5aIm=3#R_~R8*9gm+#ueDlIJqsFg@0;tH{|b8}HqQ5Jw$Ebasl zi9{wQqx{s={QP`?_T1du%K+m5+1c6W&Yc6O&&;#KYi za0xyG{0*U@p&=n5OeT{~rxS7s!NI{ht9Awk26}jqu-LA432IQH$P*->1%a<=E7fhf7KmpiNEL?|$g$1|@ z&=;ZU0fm$KWEP7BFz+mN_CD$D>KXyBfJUPQ1qHz$U@Noz`t>V3 z0Y5*#_4Rf5=AAr|%l))v3zbTRZXmD;`udA>dIa18XhRr(3s9%iK@&&<11kswKn|(| zCKfuzi4TRu*jp4GWDgcp#{666_U|?<$;@lL6fyrT=v@~MF43;U zZ$6b_)kkb?TQRlFx@L1DFHuvCdiGRV@qSb5o3SyX=dqWIo~SD}lgtU8-0hinIc|l^ zwZpyIy{+Kp3qku~jyuQS{wOJTffqk}ylg!rGf@@8WYp~qRTEe@i_6M#f}U2WR@4MfM)1HJRjPCMx~ z7uM(-p3*y>&A)fhi1A3;cS(L+J1;&pqWL&it>CX0-+eBqO{=g-lKzNGvG(`sNqtRF zeg3%mDzvL|F3Eho_0DyETn8H%dc!?dA!#0>Q=Vr9#{-Ga&|1#6CAW+Q0sfY$`N-&; z^0c=#@%4)8jy6X3lL6u3JAW=?c#tm>K2a$#(Q?|Uz}T^+pWADD@MB|q8>&Xr948aj zsY1|Z7&ad@u4wr4W%TE{WS7U&Rh^yI#(OsCtq$vQ3|A*M_uLm%-A~M)I@BiVUyS#YR$&g!`CNx58tIE z|3D@=NLJY$Q%;J12ZU?1w#&^2c5EzDN05DZLoa2szJ*SEwwg0|Mem<$Yn1cWcz^cq z-}lxrB6iz%k1R&3=>`|KS%};k)l(YskH!jI!g#-(&O>3hx)5(GX8X3fe_&q16?&Zr z)72bEymR&OySDOI3mZ0C3tSEiO=8X3u^BG}uBukDWrMyZ$LQ%Y4sr7@il=hRi%!IK N0G~qvls0mN@PBi2fm#3n literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/tp1n3p08.png b/tests/data/pngsuite/tp1n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c9f35a86271c056e955f637a8769381eb03827 GIT binary patch literal 1483 zcmWlXdpOez7{_0ijw~Xj6ZLfH5mEEBP|@KrEtkTuS}m>SI;>1?8{6D(v$V!$$}kk^ z;zXQM92O%H=ShmnbXw(ZQ8_r3^Xq+{_x=9)zVGMz<@$KL>7tBL0HEvPj`Ks*k)Uu?Q@xn6z>Z3lMM-Q#6tfUZ$jg9xOySS8oYSdsZ?58S}Ku90Gh5`xl#{MR8%wt zP*_-43Lq2;*RS7_pPzr}(xrd%E)}>Vg+~H{0|EmB;S209 z+JEZQsgoy9!bij)vJ2CNNF)M$vKCsqg}Grc6c_?OKR+KIALs+qBGU~U&cS2w^z{7x z{X6{3T?w5=n_Ror-Q69U!8X)ZUHvP8K!G~|wFu*%2C7slr~p15FS4}-9)W zgA1TkDj@~(fB8jCjUG%S0R(${)B5}SM@HTPu)4duH*Un5nj+Sda5!dbYwOg=2pWA9 zg`xngv~oCl+wa{*R;b1Lc@x0-<4`CPvRn@w_UQh+Ac}Mk^OKb>f7-E19*W;}xs}~! zRlIciNyF__FM9f7*5I)-+cbPa1|k-TrQvsONlsb*)pnz$h0|UcNA3@z)MNfwE}Uv0 zIbFH+_Zk14HEp3y&g@1-ft^E-J#CK+WhE5TXruYlt&^-N^P3g#I=H!w`R}L=sT9s{ zCuD1uhCdG)aY*zhVd3F}HZMyY{g2C62iLwz8h1Q_?PFhSvbid>^O4P?YqRlh((eZd z#_aspCH=EBx%*CRO=qIG-J;L_AlZKBgiu)@&Tb|Ii=AapW?Zqp>gYA)sH#J5XB+h; zk9wYVqsyC_bvIrV9&w7WX>VWUAVpP~na{j&$UYNXX^m&}Uyx5RnnjA&4L3VdD!1H_ zD#Iq{ZueA8l;TIb`kpn$X5SsBHj?FpV!HrYcY~@^RN}pDGk;X^V&G~0qorYaOP*rv z^qN~4t3n!C(Ta6lUVkRto3S5$_!4xZm;=Uxwl-UlXk<^TD! zwrXx-kZ%7r>OqrnxrwlgbC>i*G{g?VCRx6GHc+-!v-|w+aMq(Z)3<$!sgDrNgW zt{66;txYft&kQV}Qtm74k`-qO{C2WMU5|#0wUn?oyC~|ghKx56YPk5`Xp_O#x8g2M X(5+n&l!#upArS?SL*BSr7fRay;V71Q literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xc1n0g08.png b/tests/data/pngsuite/xc1n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..940422737011509e21d5c02e879c643a83d360e6 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE2qfRFb@ByLEa{HEjtq=#3k+XOiwE)@JzX3_ zD&{1oB&aZmaGco8!^+yj&!PF_yS#lurGboy!70HB=_!jUV|dtDd-^||`uG3*kM?JU ih7v%T2UAm1SQrAH{wp+nbR!aI7=x#)pUXO@geCxzGb>{N literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xc9n2c08.png b/tests/data/pngsuite/xc9n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..b11c2a7b4049475d967a8cc76b93ef1039684a3a GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE2_&^8vlamc;6;z7cmE{-7; zb9B#amdK II;Vst0B-g)L;wH) literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xd0n2c08.png b/tests/data/pngsuite/xd0n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..2f001610a85a662d8baa0c1f02c06adc02cfa20f GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3Si6xB+q0lO9E0X>5jgR42*3H3|~x(2l72UT^vIy z=DfXnkdwiHhsmM!&BVXki-fIRw7)F;aqgk^7G4(X1}>2wG7H{5sr9LFXk_B|YL`FM q!Y-omVL^$7@=Axs-38@~4=^@u{29mZaNZkeCWEJ|pUXO@geCyFeJ}z5 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xd3n2c08.png b/tests/data/pngsuite/xd3n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..9e4a3ff7accf4453ddcd58318f7048b326b44ad2 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnP1SGpp+}Q-ASkfJR9T^zg78t&m77yfmc)B=- zRLpsM^&lsM0S}Wy>zj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibzj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibc;6;z8n`u6{1- HoD!M<9fb>g literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xhdn0g08.png b/tests/data/pngsuite/xhdn0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..fcb8737fa2505b43955e995d95c3d6972b85fe32 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk@Bp957Lw$i1OS+@4BLidG0>c;6;(>fePZ!6K ziaE(C2`UUC949vOu(I~>b7=nfE^nVuX&@tFa7u7Oddi~87#=p(p8gM~{{27yqy1T- hp#)Io!PL|g7KVVQ{|ZeX-G~HP;_2$=vd$@?2>>eWDsTV* literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xlfn0g04.png b/tests/data/pngsuite/xlfn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..d9ec53ed94b34f50eeabf3029465e1106725ea2a GIT binary patch literal 145 zcmeAS@N?(llHy`uVBqrfa0vp^3Lwk^Bp4c;6;z7cmE{-7; zb9B#azopr048WOXaE2J literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xs2n0g01.png b/tests/data/pngsuite/xs2n0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..b8147f2a84b861b559fd52fc0ded6971debdc6f1 GIT binary patch literal 164 zcmeAS^mFIslHy`uVBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0C@{E=>Px# literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xs4n0g01.png b/tests/data/pngsuite/xs4n0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..45237a1d294f7432c06ae45769727d9745250221 GIT binary patch literal 164 zcmeAS@Jr|AlHy`uVBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0E~z=2mk;8 literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/xs7n0g01.png b/tests/data/pngsuite/xs7n0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..3f307f14ea5ed37b9f74b896a98ee4a5d2c9e111 GIT binary patch literal 164 zcmeAS@N?(oQs81>VBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0DK%Y?f?J) literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/z00n2c08.png b/tests/data/pngsuite/z00n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..7669eb8385172325c399f3229cfe834f886fecb2 GIT binary patch literal 3172 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj{$|z@zQy;uunKi&25+{%6Mj{~3NT zfY5g^iOI$zg{%daG8T~8Gz1(pwSa?x0cZixpELm=(-{~zY2*W_>0lpFKMoM4)4~E2 z)2SW@=%!OQ4zQR`#UR3NI<+joX*yLbz-Kz;kxamJ3L}}Y>68Q!QKpk^0kNi&7Y8Jm zPDUJ%W;&@sM6&55SwN2I#K!@drV|+lP)Gd0N=r*M+Cfdcn4n{+d)GIuBfe}0=haRfYbdY4|HeAW8JeNk!}u< z>b4FPx}gJ|u3eE@R|Qyfc?U*a*nwS_tjMJg1H3vP0MMC|F?z3LnBH6wQvU~l^-l+Q iz3w1HzgHBc=YRuMlTL2m+d~-u0000811+tMcYXzcm?aHZ#?gdL8ij-oNLTu@go{<42!=C2J(%l`2yyuQm;^LM9XM_s7MQs$ow Yp_Bdc41*5p0G-U>>FVdQ&MBb@0O=}Ly8r+H literal 0 HcmV?d00001 diff --git a/tests/data/pngsuite/z09n2c08.png b/tests/data/pngsuite/z09n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..5f191a78ee5601a45f1add2a3ad7a77b7b1ae0f1 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WmV3H5hE&|zdeNJ&K|z4|!mJGk ze#?uM?J%qpNVJm;SDAGELf+biOrjbV{C6uqc^By}RQhy!A*198PSpVRZwtidR0X(h zmlOPO>811+tMcYXzcm?aHZ#?gdL8ij-oNLTu@go{<42!=C2J(%l`2yyuQm;^LM9XM_s7MQs$ow Yp_Bdct_kk@3Uo4qr>mdKI;Vst043R2BLDyZ literal 0 HcmV?d00001 diff --git a/tests/python_tests/pngsuite_test.py b/tests/python_tests/pngsuite_test.py new file mode 100644 index 000000000..ca5f02f12 --- /dev/null +++ b/tests/python_tests/pngsuite_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +import os +import mapnik +from nose.tools import * +from utilities import execution_path + +datadir = '../data/pngsuite' + +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 assert_broken_file(fname): + assert_raises(RuntimeError, lambda: mapnik.Image.open(fname)) + +def assert_good_file(fname): + assert mapnik.Image.open(fname) + +def get_pngs(good): + files = [ x for x in os.listdir(datadir) if x.endswith('.png') ] + return [ os.path.join(datadir, x) for x in files if good != x.startswith('x') ] + +def test_good_pngs(): + for x in get_pngs(True): + yield assert_good_file, x + +def test_broken_pngs(): + for x in get_pngs(False): + yield assert_broken_file, x + +if __name__ == "__main__": + setup() + [eval(run)() for run in dir() if 'test_' in run] From 76211243a4bbb376ff78d5e1cf825ff56718431a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 6 Jun 2012 16:16:30 -0700 Subject: [PATCH 12/17] remove now unused blending modes as they have been replaced with AGG compositing modes - refs #1206 --- include/mapnik/graphics.hpp | 90 ------------------------------------- 1 file changed, 90 deletions(-) diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 0b5ba8ffa..f655d8d61 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -46,96 +46,6 @@ namespace mapnik { -struct Multiply -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = r1*r0/255; - g1 = g1*g0/255; - b1 = b1*b0/255; - } -}; -struct Multiply2 -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = r1*r0/128; - if (r1>255) r1=255; - g1 = g1*g0/128; - if (g1>255) g1=255; - b1 = b1*b0/128; - if (b1>255) b1=255; - } -}; -struct Divide -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = r0*256/(r1+1); - g1 = g0*256/(g1+1); - b1 = b0*256/(b1+1); - } -}; -struct Divide2 -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = r0*128/(r1+1); - g1 = g0*128/(g1+1); - b1 = b0*128/(b1+1); - } -}; -struct Screen -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = 255 - (255-r0)*(255-r1)/255; - g1 = 255 - (255-g0)*(255-g1)/255; - b1 = 255 - (255-b0)*(255-b1)/255; - } -}; -struct HardLight -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = (r1>128)?255-(255-r0)*(255-2*(r1-128))/256:r0*r1*2/256; - g1 = (g1>128)?255-(255-g0)*(255-2*(g1-128))/256:g0*g1*2/256; - b1 = (b1>128)?255-(255-b0)*(255-2*(b1-128))/256:b0*b1*2/256; - } -}; -struct MergeGrain -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = (r1+r0>128)?r1+r0-128:0; - if (r1>255) r1=255; - g1 = (g1+g0>128)?g1+g0-128:0; - if (g1>255) g1=255; - b1 = (b1+b0>128)?b1+b0-128:0; - if (b1>255) b1=255; - } -}; -struct MergeGrain2 -{ - inline static void mergeRGB(unsigned const &r0, unsigned const &g0, unsigned const &b0, - unsigned &r1, unsigned &g1, unsigned &b1) - { - r1 = (2*r1+r0>256)?2*r1+r0-256:0; - if (r1>255) r1=255; - g1 = (2*g1+g0>256)?2*g1+g0-256:0; - if (g1>255) g1=255; - b1 = (2*b1+b0>256)?2*b1+b0-256:0; - if (b1>255) b1=255; - } -}; - class MAPNIK_DECL image_32 { private: From c29c18e8dfe153566e314118ad185812e14301ba Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 6 Jun 2012 16:34:45 -0700 Subject: [PATCH 13/17] expose a get_pixel method on mapnik::grid (for testing purposes) --- bindings/python/mapnik_grid.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bindings/python/mapnik_grid.cpp b/bindings/python/mapnik_grid.cpp index 95a20efaf..b373f72ff 100644 --- a/bindings/python/mapnik_grid.cpp +++ b/bindings/python/mapnik_grid.cpp @@ -39,6 +39,18 @@ bool painted(mapnik::grid const& grid) return grid.painted(); } +int get_pixel(mapnik::grid const& grid, int x, int y) +{ + if (x < grid.width() && y < grid.height()) + { + mapnik::grid::value_type const * row = grid.getRow(y); + mapnik::grid::value_type const pixel = row[x]; + return pixel; + } + PyErr_SetString(PyExc_IndexError, "invalid x,y for grid dimensions"); + boost::python::throw_error_already_set(); +} + void export_grid() { class_ >( @@ -52,6 +64,7 @@ void export_grid() .def("width",&mapnik::grid::width) .def("height",&mapnik::grid::height) .def("view",&mapnik::grid::get_view) + .def("get_pixel",&get_pixel) .def("encode",encode, ( boost::python::arg("encoding")="utf", boost::python::arg("features")=true,boost::python::arg("resolution")=4 ), "Encode the grid as as optimized json\n" From 957c40f7631edfa1902f6e62e3198d9362fefe76 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 6 Jun 2012 16:36:38 -0700 Subject: [PATCH 14/17] move to int32 for grid rendering buffer - closes #1196 --- include/mapnik/grid/grid.hpp | 2 +- include/mapnik/grid/grid_pixel.hpp | 137 ++++++++++++++++++ include/mapnik/grid/grid_pixfmt.hpp | 6 + include/mapnik/grid/grid_view.hpp | 2 +- include/mapnik/svg/svg_renderer.hpp | 2 +- src/grid/grid_renderer.cpp | 7 +- src/grid/process_building_symbolizer.cpp | 10 +- src/grid/process_line_pattern_symbolizer.cpp | 6 +- src/grid/process_line_symbolizer.cpp | 6 +- src/grid/process_markers_symbolizer.cpp | 8 +- .../process_polygon_pattern_symbolizer.cpp | 6 +- src/grid/process_polygon_symbolizer.cpp | 6 +- tests/python_tests/render_grid_test.py | 45 ++++++ 13 files changed, 215 insertions(+), 28 deletions(-) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 95073a15b..c0fcf306d 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -329,7 +329,7 @@ public: }; -typedef MAPNIK_DECL hit_grid grid; +typedef MAPNIK_DECL hit_grid grid; } #endif //MAPNIK_GRID_HPP diff --git a/include/mapnik/grid/grid_pixel.hpp b/include/mapnik/grid/grid_pixel.hpp index 451fad349..23588472f 100644 --- a/include/mapnik/grid/grid_pixel.hpp +++ b/include/mapnik/grid/grid_pixel.hpp @@ -165,6 +165,143 @@ struct gray16 static self_type no_color() { return self_type(0,0); } }; +//==================================================================gray16 +struct gray32 +{ + typedef agg::int32 value_type; + typedef agg::int64u calc_type; + typedef agg::int64 long_type; + enum base_scale_e + { + base_shift = 32, + base_scale = 1 << base_shift, + base_mask = base_scale - 1 + }; + typedef gray32 self_type; + + value_type v; + value_type a; + + //-------------------------------------------------------------------- + gray32() {} + + //-------------------------------------------------------------------- + gray32(unsigned v_, unsigned a_=base_mask) : + v(agg::int32(v_)), a(agg::int32(a_)) {} + + //-------------------------------------------------------------------- + gray32(const self_type& c, unsigned a_) : + v(c.v), a(value_type(a_)) {} + + //-------------------------------------------------------------------- + void clear() + { + v = a = 0; + } + + //-------------------------------------------------------------------- + const self_type& transparent() + { + a = 0; + return *this; + } + + //-------------------------------------------------------------------- + void opacity(double a_) + { + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = (value_type)agg::uround(a_ * double(base_mask)); + } + + //-------------------------------------------------------------------- + double opacity() const + { + return double(a) / double(base_mask); + } + + + //-------------------------------------------------------------------- + const self_type& premultiply() + { + if(a == base_mask) return *this; + if(a == 0) + { + v = 0; + return *this; + } + v = value_type((calc_type(v) * a) >> base_shift); + return *this; + } + + //-------------------------------------------------------------------- + const self_type& premultiply(unsigned a_) + { + if(a == base_mask && a_ >= base_mask) return *this; + if(a == 0 || a_ == 0) + { + v = a = 0; + return *this; + } + calc_type v_ = (calc_type(v) * a_) / a; + v = value_type((v_ > a_) ? a_ : v_); + a = value_type(a_); + return *this; + } + + //-------------------------------------------------------------------- + const self_type& demultiply() + { + if(a == base_mask) return *this; + if(a == 0) + { + v = 0; + return *this; + } + calc_type v_ = (calc_type(v) * base_mask) / a; + v = value_type((v_ > base_mask) ? base_mask : v_); + return *this; + } + + //-------------------------------------------------------------------- + self_type gradient(self_type c, double k) const + { + self_type ret; + calc_type ik = agg::uround(k * base_scale); + ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift)); + ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); + return ret; + } + + //-------------------------------------------------------------------- + AGG_INLINE void add(const self_type& c, unsigned cover) + { + calc_type cv, ca; + if(cover == agg::cover_mask) + { + if(c.a == base_mask) + { + *this = c; + } + else + { + cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; + } + } + else + { + cv = v + ((c.v * cover + agg::cover_mask/2) >> agg::cover_shift); + ca = a + ((c.a * cover + agg::cover_mask/2) >> agg::cover_shift); + v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; + } + } + + //-------------------------------------------------------------------- + static self_type no_color() { return self_type(0,0); } +}; + } #endif diff --git a/include/mapnik/grid/grid_pixfmt.hpp b/include/mapnik/grid/grid_pixfmt.hpp index 53f73a19f..55dc6751d 100644 --- a/include/mapnik/grid/grid_pixfmt.hpp +++ b/include/mapnik/grid/grid_pixfmt.hpp @@ -634,6 +634,12 @@ typedef blender_gray blender_gray16; typedef pixfmt_alpha_blend_gray pixfmt_gray16; //----pixfmt_gray16 + +typedef blender_gray blender_gray32; + +typedef pixfmt_alpha_blend_gray pixfmt_gray32; //----pixfmt_gray16 + } #endif diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index dfa636255..7e18050db 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -201,7 +201,7 @@ private: feature_type const& features_; }; -typedef hit_grid_view > grid_view; +typedef hit_grid_view > grid_view; } diff --git a/include/mapnik/svg/svg_renderer.hpp b/include/mapnik/svg/svg_renderer.hpp index 666bbacb1..d375f4834 100644 --- a/include/mapnik/svg/svg_renderer.hpp +++ b/include/mapnik/svg/svg_renderer.hpp @@ -379,7 +379,7 @@ public: curved_.approximation_scale(scl); curved_.angle_tolerance(0.0); - mapnik::gray16 color(feature_id); + mapnik::gray32 color(feature_id); if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 16e4c8e1c..3907fcd28 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -105,12 +105,12 @@ void grid_renderer::render_marker(mapnik::feature_ptr const& feature, unsigne if (marker.is_vector()) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -132,7 +132,7 @@ void grid_renderer::render_marker(mapnik::feature_ptr const& feature, unsigne svg_renderer, renderer, - mapnik::pixfmt_gray16> svg_renderer(svg_path, + mapnik::pixfmt_gray32> svg_renderer(svg_path, (*marker.get_vector_data())->attributes()); svg_renderer.render_id(*ras_ptr, sl, renb, feature->id(), mtx, opacity, bbox); @@ -161,7 +161,6 @@ void grid_renderer::render_marker(mapnik::feature_ptr const& feature, unsigne pixmap_.add_feature(feature); } -template class hit_grid; template class grid_renderer; } diff --git a/src/grid/process_building_symbolizer.cpp b/src/grid/process_building_symbolizer.cpp index 52b1edd69..e7203cd61 100644 --- a/src/grid/process_building_symbolizer.cpp +++ b/src/grid/process_building_symbolizer.cpp @@ -47,12 +47,12 @@ void grid_renderer::process(building_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -108,7 +108,7 @@ void grid_renderer::process(building_symbolizer const& sym, path_type faces_path (t_,*faces,prj_trans); ras_ptr->add_path(faces_path); - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); ras_ptr->reset(); @@ -135,13 +135,13 @@ void grid_renderer::process(building_symbolizer const& sym, path_type path(t_,*frame,prj_trans); agg::conv_stroke stroke(path); ras_ptr->add_path(stroke); - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); ras_ptr->reset(); path_type roof_path (t_,*roof,prj_trans); ras_ptr->add_path(roof_path); - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); } } diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp index 2ab1ad8a5..92f9407a7 100644 --- a/src/grid/process_line_pattern_symbolizer.cpp +++ b/src/grid/process_line_pattern_symbolizer.cpp @@ -46,12 +46,12 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -75,7 +75,7 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, } // render id - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp index be3519586..d836ed75d 100644 --- a/src/grid/process_line_symbolizer.cpp +++ b/src/grid/process_line_symbolizer.cpp @@ -46,12 +46,12 @@ void grid_renderer::process(line_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -134,7 +134,7 @@ void grid_renderer::process(line_symbolizer const& sym, } // render id - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 4d83e521a..62154a8e6 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -56,12 +56,12 @@ void grid_renderer::process(markers_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -104,7 +104,7 @@ void grid_renderer::process(markers_symbolizer const& sym, svg_renderer, renderer, - mapnik::pixfmt_gray16 > svg_renderer(svg_path,(*marker)->attributes()); + mapnik::pixfmt_gray32 > svg_renderer(svg_path,(*marker)->attributes()); bool placed = false; for (unsigned i=0; inum_geometries(); ++i) @@ -285,7 +285,7 @@ void grid_renderer::process(markers_symbolizer const& sym, } } - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); pixmap_.add_feature(feature); } diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 855694df4..3f71f0c88 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -45,12 +45,12 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -68,7 +68,7 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, } // render id - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp index 649366bd8..c353fdee9 100644 --- a/src/grid/process_polygon_symbolizer.cpp +++ b/src/grid/process_polygon_symbolizer.cpp @@ -45,12 +45,12 @@ void grid_renderer::process(polygon_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - typedef agg::renderer_base ren_base; + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray16 pixf(buf); + mapnik::pixfmt_gray32 pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -67,7 +67,7 @@ void grid_renderer::process(polygon_symbolizer const& sym, } // render id - ren.color(mapnik::gray16(feature->id())); + ren.color(mapnik::gray32(feature->id())); agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index 140f97c9d..0525f71c5 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -186,5 +186,50 @@ def test_render_grid3(): eq_(resolve(utf5,38,10),{"Name": "South West"}) eq_(resolve(utf5,38,46),{"Name": "South East"}) + +def gen_grid_for_id(pixel_key): + ds = mapnik.MemoryDatasource() + context = mapnik.Context() + context.push('Name') + f = mapnik.Feature(context,pixel_key) + f['Name'] = str(pixel_key) + f.add_geometries_from_wkt('POLYGON ((0 0, 0 256, 256 256, 256 0, 0 0))') + ds.add_feature(f) + s = mapnik.Style() + r = mapnik.Rule() + symb = mapnik.PolygonSymbolizer() + r.symbols.append(symb) + s.rules.append(r) + lyr = mapnik.Layer('Places') + lyr.datasource = ds + lyr.styles.append('places_labels') + width,height = 256,256 + m = mapnik.Map(width,height) + m.append_style('places_labels',s) + m.layers.append(lyr) + m.zoom_all() + grid = mapnik.Grid(m.width,m.height,key='__id__') + mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name']) + return grid + +def test_negative_id(): + grid = gen_grid_for_id(-1) + eq_(grid.get_pixel(128,128),-1) + utf1 = grid.encode('utf',resolution=4) + eq_(utf1['keys'],['-1']) + +def test_32bit_int_id(): + int32 = 2147483647 + grid = gen_grid_for_id(int32) + eq_(grid.get_pixel(128,128),int32) + utf1 = grid.encode('utf',resolution=4) + eq_(utf1['keys'],[str(int32)]) + + max_neg = -(int32+1) + grid = gen_grid_for_id(max_neg) + eq_(grid.get_pixel(128,128),max_neg) + utf1 = grid.encode('utf',resolution=4) + eq_(utf1['keys'],[str(max_neg)]) + if __name__ == "__main__": [eval(run)() for run in dir() if 'test_' in run] From f374d01896e5f26c3f772db2c6f79123185f2e8d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 6 Jun 2012 17:32:16 -0700 Subject: [PATCH 15/17] only mark deprecated api names for removal at major versions to ensure we are semver compatible - thanks @migurski - closes #1129 --- bindings/python/mapnik/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/mapnik/__init__.py b/bindings/python/mapnik/__init__.py index 4aa2afe27..129b90b59 100644 --- a/bindings/python/mapnik/__init__.py +++ b/bindings/python/mapnik/__init__.py @@ -67,13 +67,13 @@ class _MapnikMetaclass(BoostPythonMetaclass): _injector = _MapnikMetaclass('_injector', (object, ), {}) def Filter(*args,**kwargs): - warnings.warn("'Filter' is deprecated and will be removed in Mapnik 2.0.1, use 'Expression' instead", + warnings.warn("'Filter' is deprecated and will be removed in Mapnik 3.x, use 'Expression' instead", DeprecationWarning, 2) return Expression(*args, **kwargs) class Envelope(Box2d): def __init__(self, *args, **kwargs): - warnings.warn("'Envelope' is deprecated and will be removed in Mapnik 2.0.1, use 'Box2d' instead", + warnings.warn("'Envelope' is deprecated and will be removed in Mapnik 3.x, use 'Box2d' instead", DeprecationWarning, 2) Box2d.__init__(self, *args, **kwargs) From 6a4c2072545389e973769d786eb834c6e0d6a642 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Thu, 7 Jun 2012 11:46:50 +0100 Subject: [PATCH 16/17] + make it compile against latyest master (FIXME) --- demo/viewer/mapwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 102dfe030..220eb5586 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -534,7 +534,7 @@ void render_grid(mapnik::Map const& map, double scaling_factor, QPixmap & pix) try { ren.apply(); - boost::uint16_t *imdata = static_cast(buf.raw_data()); + int * imdata = static_cast(buf.raw_data()); QImage image(width,height,QImage::Format_RGB32); for (unsigned i = 0 ; i < height ; ++i) From 013f0aa62fecfa43b06c27ec5dd6bb3e8be296ca Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Thu, 7 Jun 2012 11:51:23 +0100 Subject: [PATCH 17/17] + add templated ctor and avoid including agg_trans_affine.h --- include/mapnik/transform_expression.hpp | 98 ++++++++++++------------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/include/mapnik/transform_expression.hpp b/include/mapnik/transform_expression.hpp index b55a872ba..069863470 100644 --- a/include/mapnik/transform_expression.hpp +++ b/include/mapnik/transform_expression.hpp @@ -31,9 +31,6 @@ #include #include -// agg -#include - // stl #include @@ -53,7 +50,8 @@ struct matrix_node explicit matrix_node(double const* m) : a_(m[0]), b_(m[1]), c_(m[2]), d_(m[3]), e_(m[4]), f_(m[5]) {} - explicit matrix_node(agg::trans_affine const& m) + template + explicit matrix_node(T const& m) : a_(m.sx), b_(m.shy), c_(m.shx), d_(m.sy), e_(m.tx), f_(m.ty) {} matrix_node(expr_node const& a, expr_node const& b, expr_node const& c, @@ -115,58 +113,58 @@ struct skewY_node namespace detail { - // boost::spirit::traits::clear(T& val) [with T = boost::variant<...>] - // attempts to assign to the variant's current value a default-constructed - // value ot the same type, which not only requires that each value-type is - // default-constructible, but also makes little sense with our variant of - // transform nodes... +// boost::spirit::traits::clear(T& val) [with T = boost::variant<...>] +// attempts to assign to the variant's current value a default-constructed +// value ot the same type, which not only requires that each value-type is +// default-constructible, but also makes little sense with our variant of +// transform nodes... - typedef boost::variant< identity_node - , matrix_node - , translate_node - , scale_node - , rotate_node - , skewX_node - , skewY_node - > transform_variant; +typedef boost::variant< identity_node + , matrix_node + , translate_node + , scale_node + , rotate_node + , skewX_node + , skewY_node + > transform_variant; - // ... thus we wrap the variant-type in a distinct type and provide - // a custom clear overload, which resets the value to identity_node +// ... thus we wrap the variant-type in a distinct type and provide +// a custom clear overload, which resets the value to identity_node - struct transform_node +struct transform_node +{ + transform_variant base_; + + transform_node() + : base_() {} + + template + transform_node(T const& val) + : base_(val) {} + + template + transform_node& operator= (T const& val) { - transform_variant base_; - - transform_node() - : base_() {} - - template - transform_node(T const& val) - : base_(val) {} - - template - transform_node& operator= (T const& val) - { - base_ = val; - return *this; - } - - transform_variant const& operator* () const - { - return base_; - } - - transform_variant& operator* () - { - return base_; - } - }; - - inline void clear(transform_node& val) - { - val.base_ = identity_node(); + base_ = val; + return *this; } + transform_variant const& operator* () const + { + return base_; + } + + transform_variant& operator* () + { + return base_; + } +}; + +inline void clear(transform_node& val) +{ + val.base_ = identity_node(); +} + } // namespace detail typedef detail::transform_node transform_node;