From fec0750fcf2c4d250928e73f9685e885439dd9cd Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 8 Feb 2012 15:45:08 -0800 Subject: [PATCH 01/16] remove usage of boost::lexical_cast during image encoding - refs #1055 --- src/image_util.cpp | 155 ++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 78 deletions(-) diff --git a/src/image_util.cpp b/src/image_util.cpp index 574990feb..cc845ad13 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -38,7 +38,7 @@ extern "C" #include // boost -#include +#include // jpeg #if defined(HAVE_JPEG) @@ -73,6 +73,8 @@ extern "C" #include "agg_trans_affine.h" #include "agg_image_filters.h" +using namespace boost::spirit; + namespace mapnik { @@ -156,85 +158,84 @@ void handle_png_options(std::string const& type, { *use_octree = true; } - else if (boost::algorithm::istarts_with(t,std::string("c="))) + else if (boost::algorithm::istarts_with(t, "c=")) { - try + if (*colors < 0) + throw ImageWriterException("invalid color parameter: unavailable for true color images"); + + std::string const& val = t.substr(2); + std::string::const_iterator str_beg = val.begin(); + std::string::const_iterator str_end = val.end(); + bool r = qi::phrase_parse(str_beg,str_end,qi::int_,ascii::space,*colors); + if (!r || (str_beg != str_end) || *colors < 0 || *colors > 256) + throw ImageWriterException("invalid color parameter: " + val); + } + else if (boost::algorithm::istarts_with(t, "t=")) + { + if (*colors < 0) + throw ImageWriterException("invalid trans_mode parameter: unavailable for true color images"); + + std::string const& val = t.substr(2); + std::string::const_iterator str_beg = val.begin(); + std::string::const_iterator str_end = val.end(); + bool r = qi::phrase_parse(str_beg,str_end,qi::int_,ascii::space,*trans_mode); + if (!r || (str_beg != str_end) || *trans_mode < 0 || *trans_mode > 2) + throw ImageWriterException("invalid trans_mode parameter: " + val); + } + else if (boost::algorithm::istarts_with(t, "g=")) + { + if (*colors < 0) + throw ImageWriterException("invalid gamma parameter: unavailable for true color images"); + std::string const& val = t.substr(2); + std::string::const_iterator str_beg = val.begin(); + std::string::const_iterator str_end = val.end(); + bool r = qi::phrase_parse(str_beg,str_end,qi::double_,ascii::space,*gamma); + if (!r || (str_beg != str_end) || *gamma < 0) { - if (*colors < 0) - throw ImageWriterException("invalid color parameter: unavailable for true color images"); - *colors = boost::lexical_cast(t.substr(2)); - if (*colors < 0 || *colors > 256) - throw ImageWriterException("invalid color parameter: " + t.substr(2) + " out of bounds"); - } - catch(boost::bad_lexical_cast &) - { - throw ImageWriterException("invalid color parameter: " + t.substr(2)); + throw ImageWriterException("invalid gamma parameter: " + val); } } - else if (boost::algorithm::istarts_with(t, std::string("t="))) + else if (boost::algorithm::istarts_with(t, "z=")) { - try + /* + #define Z_NO_COMPRESSION 0 + #define Z_BEST_SPEED 1 + #define Z_BEST_COMPRESSION 9 + #define Z_DEFAULT_COMPRESSION (-1) + */ + std::string const& val = t.substr(2); + std::string::const_iterator str_beg = val.begin(); + std::string::const_iterator str_end = val.end(); + bool r = qi::phrase_parse(str_beg,str_end,qi::int_,ascii::space,*compression); + if (!r || (str_beg != str_end) + || *compression < Z_DEFAULT_COMPRESSION + || *compression > Z_BEST_COMPRESSION) { - if (*colors < 0) - throw ImageWriterException("invalid trans_mode parameter: unavailable for true color images"); - *trans_mode = boost::lexical_cast(t.substr(2)); - if (*trans_mode < 0 || *trans_mode > 2) - throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2) + " out of bounds"); - } - catch(boost::bad_lexical_cast &) - { - throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); + throw ImageWriterException("invalid compression parameter: " + val + " (only -1 through 9 are valid)"); } } - else if (boost::algorithm::istarts_with(t, std::string("g="))) + else if (boost::algorithm::istarts_with(t, "s=")) { - try + std::string const& s = t.substr(2); + if (s == "default") { - if (*colors < 0) - throw ImageWriterException("invalid gamma parameter: unavailable for true color images"); - *gamma = boost::lexical_cast(t.substr(2)); - if (*gamma < 0) - throw ImageWriterException("invalid gamma parameter: " + t.substr(2) + " out of bounds"); + *strategy = Z_DEFAULT_STRATEGY; } - catch(boost::bad_lexical_cast &) + else if (s == "filtered") { - throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); + *strategy = Z_FILTERED; } - } - else if (boost::algorithm::istarts_with(t,std::string("z="))) - { - try + else if (s == "huff") { - *compression = boost::lexical_cast(t.substr(2)); - /* - #define Z_NO_COMPRESSION 0 - #define Z_BEST_SPEED 1 - #define Z_BEST_COMPRESSION 9 - #define Z_DEFAULT_COMPRESSION (-1) - */ - if (*compression < Z_DEFAULT_COMPRESSION || *compression > Z_BEST_COMPRESSION) - throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " out of bounds (only -1 through 9 are valid)"); + *strategy = Z_HUFFMAN_ONLY; } - catch(boost::bad_lexical_cast &) + else if (s == "rle") { - throw ImageWriterException("invalid compression parameter: " + t.substr(2)); + *strategy = Z_RLE; } - } - else if (boost::algorithm::istarts_with(t,std::string("s="))) - { - try + else { - std::string s = boost::lexical_cast(t.substr(2)); - if (s == "default") *strategy = Z_DEFAULT_STRATEGY; - else if (s == "filtered") *strategy = Z_FILTERED; - else if (s == "huff") *strategy = Z_HUFFMAN_ONLY; - else if (s == "rle") *strategy = Z_RLE; - else - throw ImageWriterException("invalid compression strategy parameter: " + s); - } - catch(boost::bad_lexical_cast &) - { - throw ImageWriterException("invalid compression strategy parameter: " + t.substr(2)); + throw ImageWriterException("invalid compression strategy parameter: " + s); } } } @@ -250,7 +251,7 @@ void save_to_stream(T const& image, if (stream) { //all this should go into image_writer factory - if (type == "png" || boost::algorithm::istarts_with(type, std::string("png"))) + if (type == "png" || boost::algorithm::istarts_with(type, "png")) { int colors = 256; int compression = Z_DEFAULT_COMPRESSION; @@ -276,12 +277,12 @@ void save_to_stream(T const& image, else save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma); } - else if (boost::algorithm::istarts_with(type, std::string("tif"))) + else if (boost::algorithm::istarts_with(type, "tif")) { throw ImageWriterException("palettes are not currently supported when writing to tiff format (yet)"); } #if defined(HAVE_JPEG) - else if (boost::algorithm::istarts_with(type, std::string("jpeg"))) + else if (boost::algorithm::istarts_with(type, "jpeg")) { throw ImageWriterException("palettes are not currently supported when writing to jpeg format"); } @@ -300,7 +301,7 @@ void save_to_stream(T const& image, if (stream) { //all this should go into image_writer factory - if (type == "png" || boost::algorithm::istarts_with(type, std::string("png"))) + if (type == "png" || boost::algorithm::istarts_with(type, "png")) { int colors = 256; int compression = Z_DEFAULT_COMPRESSION; @@ -324,28 +325,26 @@ void save_to_stream(T const& image, else save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma); } - else if (boost::algorithm::istarts_with(type, std::string("tif"))) + else if (boost::algorithm::istarts_with(type, "tif")) { save_as_tiff(stream, image); } #if defined(HAVE_JPEG) - else if (boost::algorithm::istarts_with(type, std::string("jpeg"))) + else if (boost::algorithm::istarts_with(type, "jpeg")) { int quality = 85; - try + std::string const& val = type.substr(4); + if(!val.empty()) { - if(type.substr(4).length() != 0) + std::string::const_iterator str_beg = val.begin(); + std::string::const_iterator str_end = val.end(); + bool r = qi::phrase_parse(str_beg,str_end,qi::int_,ascii::space,quality); + if (!r || (str_beg != str_end) || quality < 0 || quality > 100) { - quality = boost::lexical_cast(type.substr(4)); - if(quality<0 || quality>100) - throw ImageWriterException("invalid jpeg quality: " + type.substr(4) + " out of bounds"); + throw ImageWriterException("invalid jpeg quality: " + val); } - save_as_jpeg(stream, quality, image); - } - catch(boost::bad_lexical_cast &) - { - throw ImageWriterException("invalid jpeg quality: " + type.substr(4) + " not a number"); } + save_as_jpeg(stream, quality, image); } #endif else throw ImageWriterException("unknown file type: " + type); From b44a63ac1fb3c502e9b5247dca5876586439b00a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 9 Feb 2012 16:00:11 -0800 Subject: [PATCH 02/16] link all remaining plugins to boost_system to avoid potential linking errors with boost-trunk (upcoming 1.49) - closes #1070 --- plugins/input/csv/build.py | 1 + plugins/input/gdal/build.py | 1 + plugins/input/kismet/build.py | 1 + plugins/input/occi/build.py | 1 + plugins/input/postgis/build.py | 1 + 5 files changed, 5 insertions(+) diff --git a/plugins/input/csv/build.py b/plugins/input/csv/build.py index e2112c2aa..ae41bf6d1 100644 --- a/plugins/input/csv/build.py +++ b/plugins/input/csv/build.py @@ -17,6 +17,7 @@ plugin_sources = Split( libraries = [] libraries.append('mapnik') +libraries.append('boost_system%s' % env['BOOST_APPEND']) libraries.append(env['ICU_LIB_NAME']) TARGET = plugin_env.SharedLibrary( diff --git a/plugins/input/gdal/build.py b/plugins/input/gdal/build.py index 3866b2245..572ac2356 100644 --- a/plugins/input/gdal/build.py +++ b/plugins/input/gdal/build.py @@ -38,6 +38,7 @@ plugin_env['LIBS'] = [env['PLUGINS']['gdal']['lib']] # Link Library to Dependencies plugin_env['LIBS'].append('mapnik') +plugin_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND']) plugin_env['LIBS'].append(env['ICU_LIB_NAME']) if env['RUNTIME_LINK'] == 'static': diff --git a/plugins/input/kismet/build.py b/plugins/input/kismet/build.py index 2d03126f5..930be63a7 100644 --- a/plugins/input/kismet/build.py +++ b/plugins/input/kismet/build.py @@ -37,6 +37,7 @@ libraries = [] # Link Library to Dependencies libraries.append('mapnik') libraries.append(env['ICU_LIB_NAME']) +libraries.append('boost_system%s' % env['BOOST_APPEND']) if env['THREADING'] == 'multi': libraries.append('boost_thread%s' % env['BOOST_APPEND']) diff --git a/plugins/input/occi/build.py b/plugins/input/occi/build.py index 9c8b30a0b..62becff91 100644 --- a/plugins/input/occi/build.py +++ b/plugins/input/occi/build.py @@ -38,6 +38,7 @@ occi_src = Split( libraries = [ 'occi', 'ociei' ] libraries.append('mapnik') +libraries.append('boost_system%s' % env['BOOST_APPEND']) libraries.append(env['ICU_LIB_NAME']) input_plugin = plugin_env.SharedLibrary('../occi', source=occi_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS']) diff --git a/plugins/input/postgis/build.py b/plugins/input/postgis/build.py index c1d4a00a6..6987ef593 100644 --- a/plugins/input/postgis/build.py +++ b/plugins/input/postgis/build.py @@ -38,6 +38,7 @@ plugin_env['LIBS'] = ['pq'] # Link Library to Dependencies plugin_env['LIBS'].append('mapnik') +plugin_env['LIBS'].append('boost_system%s' % env['BOOST_APPEND']) plugin_env['LIBS'].append(env['ICU_LIB_NAME']) if env['THREADING'] == 'multi': plugin_env['LIBS'].append('boost_thread%s' % env['BOOST_APPEND']) From c33d534b802f353a2cd1b42e98a6f5e8e04bc2b5 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 9 Feb 2012 16:00:39 -0800 Subject: [PATCH 03/16] link to boost system --- plugins/input/templates/helloworld/build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/input/templates/helloworld/build.py b/plugins/input/templates/helloworld/build.py index 402b88202..c0b75f0c9 100644 --- a/plugins/input/templates/helloworld/build.py +++ b/plugins/input/templates/helloworld/build.py @@ -44,6 +44,7 @@ plugin_sources = Split( libraries = [ '' ] # eg 'libfoo' libraries.append('mapnik') +libraries.append('boost_system%s' % env['BOOST_APPEND']) # link libicuuc, but ICU_LIB_NAME is used custom builds of icu can # have different library names like osx which offers /usr/lib/libicucore.dylib libraries.append(env['ICU_LIB_NAME']) From 0748d2beea3d878c3a7f667b2c7efb9ba3f00a5b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 9 Feb 2012 17:28:31 -0800 Subject: [PATCH 04/16] avoid mutex locks on pj_transform for proj 4.7 and above - closes #1072 --- src/proj_transform.cpp | 6 ++++-- src/projection.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/proj_transform.cpp b/src/proj_transform.cpp index c52dfd7c6..e6f0965c4 100644 --- a/src/proj_transform.cpp +++ b/src/proj_transform.cpp @@ -102,7 +102,8 @@ bool proj_transform::forward (double * x, double * y , double * z, int point_cou } do { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +// https://github.com/mapnik/mapnik/issues/1072 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 mutex::scoped_lock lock(projection::mutex_); #endif if (pj_transform( source_.proj_, dest_.proj_, point_count, @@ -153,7 +154,8 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co } do { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +// https://github.com/mapnik/mapnik/issues/1072 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 mutex::scoped_lock lock(projection::mutex_); #endif diff --git a/src/projection.cpp b/src/projection.cpp index 5fc97e150..66706edb6 100644 --- a/src/projection.cpp +++ b/src/projection.cpp @@ -34,7 +34,7 @@ namespace mapnik { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 boost::mutex projection::mutex_; #endif @@ -84,7 +84,7 @@ std::string const& projection::params() const void projection::forward(double & x, double &y ) const { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 mutex::scoped_lock lock(mutex_); #endif projUV p; @@ -102,7 +102,7 @@ void projection::forward(double & x, double &y ) const void projection::inverse(double & x,double & y) const { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 mutex::scoped_lock lock(mutex_); #endif if (is_geographic_) @@ -120,7 +120,7 @@ void projection::inverse(double & x,double & y) const projection::~projection() { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 mutex::scoped_lock lock(mutex_); #endif if (proj_) pj_free(proj_); @@ -131,7 +131,7 @@ projection::~projection() void projection::init() { -#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 +#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 470 mutex::scoped_lock lock(mutex_); #endif #if PJ_VERSION >= 480 From 6824b87aff12377c10ca522f9ccdca5c6ae9c11d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 9 Feb 2012 17:30:05 -0800 Subject: [PATCH 05/16] add proj 4.7 mutex change to changelog - refs #1072 --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index caa88a4ad..8dfa52f59 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,8 @@ For a complete change history, see the SVN log. Mapnik 2.1.0 ------------ +- Removed mutex locking during reprojection if using >= proj 4.7 (#1072) + - Removed PointDatasource - use more robust MemoryDatasource instead (#1032) - SQLite - Added support for !intersects! token in sql subselects (#809) allow custom positioning of rtree spatial filter. From ff66cc13261e910ce9510063894e931e57db903d Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Fri, 10 Feb 2012 10:52:06 +0000 Subject: [PATCH 06/16] + check if index is valid in to_string() + output feature id --- include/mapnik/feature.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp index 557fdea3b..81a9b7da4 100644 --- a/include/mapnik/feature.hpp +++ b/include/mapnik/feature.hpp @@ -254,12 +254,16 @@ public: std::string to_string() const { std::stringstream ss; - ss << "Feature (" << std::endl; + ss << "Feature ( id=" << id_ << std::endl; context_type::map_type::const_iterator itr = ctx_->mapping_.begin(); context_type::map_type::const_iterator end = ctx_->mapping_.end(); for ( ;itr!=end; ++itr) { - ss << " " << itr->first << ":" << data_[itr->second] << std::endl; + std::size_t index = itr->second; + if (index < data_.size()) + { + ss << " " << itr->first << ":" << data_[itr->second] << std::endl; + } } ss << ")" << std::endl; return ss.str(); From f19bcafbf6797aa7ebd1bb8ca5dd97d8ae937a3c Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Fri, 10 Feb 2012 10:53:04 +0000 Subject: [PATCH 07/16] + make wkt_parser noncopyable --- include/mapnik/wkt/wkt_factory.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/mapnik/wkt/wkt_factory.hpp b/include/mapnik/wkt/wkt_factory.hpp index 2b459495c..b5e1cecce 100644 --- a/include/mapnik/wkt/wkt_factory.hpp +++ b/include/mapnik/wkt/wkt_factory.hpp @@ -26,6 +26,8 @@ // mapnik #include #include +// boost +#include #include #include // stl @@ -41,7 +43,7 @@ MAPNIK_DECL bool from_wkt(std::string const& wkt, boost::ptr_vector= 104700 -class wkt_parser +class wkt_parser : boost::noncopyable { typedef std::string::const_iterator iterator_type; public: From 602264d3686fe12d060c0ec9ea1ddb38adcbef88 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Fri, 10 Feb 2012 11:56:53 +0000 Subject: [PATCH 08/16] + implement 'in situ' boost::spirit::qi based geojson parser --- .../json/feature_collection_grammar.hpp | 126 ++++++ .../mapnik/json/feature_collection_parser.hpp | 57 +++ include/mapnik/json/feature_grammar.hpp | 380 ++++++++++++++++++ src/build.py | 5 + src/json/feature_collection_parser.cpp | 47 +++ 5 files changed, 615 insertions(+) create mode 100644 include/mapnik/json/feature_collection_grammar.hpp create mode 100644 include/mapnik/json/feature_collection_parser.hpp create mode 100644 include/mapnik/json/feature_grammar.hpp create mode 100644 src/json/feature_collection_parser.cpp diff --git a/include/mapnik/json/feature_collection_grammar.hpp b/include/mapnik/json/feature_collection_grammar.hpp new file mode 100644 index 000000000..edd457d07 --- /dev/null +++ b/include/mapnik/json/feature_collection_grammar.hpp @@ -0,0 +1,126 @@ +/***************************************************************************** + * + * 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_FEATURE_COLLECTION_GRAMMAR_HPP +#define MAPNIK_FEATURE_COLLECTION_GRAMMAR_HPP + +// mapnik +#include + +// spirit::qi +#include +#include +#include +#include +#include + +// stl +#include + +namespace mapnik { namespace json { + +namespace qi = boost::spirit::qi; +namespace phoenix = boost::phoenix; +namespace ascii = boost::spirit::ascii; + +struct generate_id +{ + typedef int result_type; + + generate_id(int start) + : id_(start) {} + + int operator() () const + { + return id_++; + } + mutable int id_; +}; + +template +struct feature_collection_grammar : + qi::grammar(), ascii::space_type> +{ + feature_collection_grammar(context_ptr const& ctx, mapnik::transcoder const& tr) + : feature_collection_grammar::base_type(feature_collection,"feature-collection"), + ctx_(ctx), + feature_g(tr), + generate_id_(1) + { + using qi::lit; + using qi::eps; + using qi::_a; + using qi::_b; + using qi::_val; + using qi::_r1; + using phoenix::push_back; + using phoenix::construct; + using phoenix::new_; + using phoenix::val; + + feature_collection = lit('{') >> (type | features) % lit(",") >> lit('}') + ; + + type = lit("\"type\"") > lit(":") > lit("\"FeatureCollection\"") + ; + + features = lit("\"features\"") + > lit(":") + > lit('[') + > feature(_val) % lit(',') + > lit(']') + ; + + feature = eps[_a = construct(new_(ctx_,generate_id_()))] + >> feature_g(*_a)[push_back(_r1,_a)] + ; + + type.name("type"); + features.name("features"); + feature.name("feature"); + feature_g.name("feature-grammar"); + + qi::on_error + ( + feature_collection + , std::clog + << phoenix::val("Error parsing GeoJSON ") + << qi::_4 + << phoenix::val(" here: \"") + << construct(qi::_3, qi::_2) + << phoenix::val("\"") + << std::endl + ); + } + + context_ptr ctx_; + qi::rule(), ascii::space_type> feature_collection; // START + qi::rule type; + qi::rule(), ascii::space_type> features; + qi::rule, void(std::vector&), ascii::space_type> feature; + feature_grammar feature_g; + boost::phoenix::function generate_id_; +}; + +}} + +#endif // MAPNIK_FEATURE_COLLECTION_GRAMMAR_HPP diff --git a/include/mapnik/json/feature_collection_parser.hpp b/include/mapnik/json/feature_collection_parser.hpp new file mode 100644 index 000000000..9b962a19d --- /dev/null +++ b/include/mapnik/json/feature_collection_parser.hpp @@ -0,0 +1,57 @@ +/***************************************************************************** + * + * 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_FEATURE_COLLECTION_PARSER_HPP +#define MAPNIK_FEATURE_COLLECTION_PARSER_HPP + +// mapnik +#include +#include +#include + +//#include + +// boost +#include +#include +// stl +#include + +namespace mapnik { namespace json { + +template struct feature_collection_grammar; + +class feature_collection_parser //: private boost::noncopyable +{ + typedef std::string::const_iterator iterator_type; + typedef mapnik::Feature feature_type; +public: + feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr); + ~feature_collection_parser(); + bool parse(std::string const& json, std::vector & features); +private: + boost::scoped_ptr > grammar_; +}; + +}} + +#endif //MAPNIK_FEATURE_COLLECTION_PARSER_HPP diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp new file mode 100644 index 000000000..707f89973 --- /dev/null +++ b/include/mapnik/json/feature_grammar.hpp @@ -0,0 +1,380 @@ +/***************************************************************************** + * + * 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_FEATURE_GRAMMAR_HPP +#define MAPNIK_FEATURE_GRAMMAR_HPP + +// mapnik +#include + +// spirit::qi +#include +#include +#include +#include +#include + +// stl +#include + +namespace mapnik { namespace json { + +namespace qi = boost::spirit::qi; +namespace phoenix = boost::phoenix; +namespace fusion = boost::fusion; +namespace ascii = boost::spirit::ascii; + +class attribute_value_visitor + : public boost::static_visitor +{ +public: + attribute_value_visitor(mapnik::transcoder const& tr) + : tr_(tr) {} + + mapnik::value operator()(std::string const& val) const + { + return mapnik::value(tr_.transcode(val.c_str())); + } + + template + mapnik::value operator()(T const& val) const + { + return mapnik::value(val); + } + mapnik::transcoder const& tr_; +}; + +struct put_property +{ + template + struct result + { + typedef void type; + }; + explicit put_property(mapnik::transcoder const& tr) + : tr_(tr) {} + + template + void operator() (T0 & feature, T1 const& key, T2 const& val) const + { + mapnik::value v = boost::apply_visitor(attribute_value_visitor(tr_),val); // TODO: optimize + feature.put_new(key, v); + } + + mapnik::transcoder const& tr_; +}; + +struct extract_geometry +{ + template + struct result + { + typedef boost::ptr_vector& type; + }; + + template + boost::ptr_vector& operator() (T & feature) const + { + return feature.paths(); + } +}; + +struct push_vertex +{ + template + struct result + { + typedef void type; + }; + + template + void operator() (T0 c, T1 path, T2 x, T3 y) const + { + BOOST_ASSERT( path!=0 ); + path->push_vertex(x,y,c); + } +}; + +struct cleanup +{ + template + struct result + { + typedef void type; + }; + + template + void operator() (T0 & path) const + { + if (path) delete path, path=0; + } +}; + +template +struct feature_grammar : + qi::grammar +{ + feature_grammar(mapnik::transcoder const& tr) + : feature_grammar::base_type(feature,"feature"), + put_property_(put_property(tr)) + { + using qi::lit; + using qi::int_; + using qi::double_; + using qi::no_skip; + using ascii::char_; + using qi::_val; + using qi::_1; + using qi::_2; + using qi::_3; + using qi::_4; + using qi::_a; + using qi::_b; + using qi::_r1; + using qi::_r2; + using qi::fail; + using qi::on_error; + using qi::_pass; + using qi::eps; + using qi::raw; + + using phoenix::new_; + using phoenix::push_back; + using phoenix::construct; + + // generic json types + value = object | array | string_ + | number + ; + + pairs = key_value % lit(',') + ; + + key_value = (string_ >> lit(':') >> value) + ; + + object = lit('{') + >> *pairs + >> lit('}') + ; + array = lit('[') + >> value >> *(lit(',') >> value) + >> lit(']') + ; + + number %= strict_double + | int_ + | lit("true") [_val = true] + | lit ("false") [_val = false] + | lit("null")[_val = construct()] + ; + + unesc_char.add + ("\\\"", '\"') // quotation mark + ("\\\\", '\\') // reverse solidus + ("\\/", '/') // solidus + ("\\b", '\b') // backspace + ("\\f", '\f') // formfeed + ("\\n", '\n') // newline + ("\\r", '\r') // carrige return + ("\\t", '\t') // tab + ; + + string_ %= lit('"') >> *(unesc_char | "\\u" >> hex4 | (char_ - lit('"'))) >> lit('"') + ; + + // geojson types + + feature_type = lit("\"type\"") + >> lit(':') + >> lit("\"Feature\"") + ; + + feature = lit('{') + >> (feature_type | (lit("\"geometry\"") > lit(':') > geometry(_r1)) | properties(_r1) | key_value) % lit(',') + >> lit('}') + ; + + properties = lit("\"properties\"") + >> lit(':') >> (lit('{') >> attributes(_r1) >> lit('}')) | lit("null") + ; + + attributes = (string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',') + ; + + attribute_value %= number | string_ ; + + // Nabialek trick - FIXME: how to bind argument to dispatch rule? + // geometry = lit("\"geometry\"") + // >> lit(':') >> lit('{') + // >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] + // >> lit(',') >> lit("\"coordinates\"") >> lit(':') + // >> qi::lazy(*_a) + // >> lit('}') + // ; + // geometry_dispatch.add + // ("\"Point\"",&point_coordinates) + // ("\"LineString\"",&linestring_coordinates) + // ("\"Polygon\"",&polygon_coordinates) + // ; + ////////////////////////////////////////////////////////////////// + + geometry = (lit('{')[_a = 0 ] + >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] // <---- should be Nabialek trick! + >> lit(',') + >> (lit("\"coordinates\"") > lit(':') > coordinates(_r1,_a) + | + lit("\"geometries\"") > lit(':') + >> lit('[') >> geometry_collection(_r1) >> lit(']')) + >> lit('}')) + | lit("null") + ; + + geometry_dispatch.add + ("\"Point\"",1) + ("\"LineString\"",2) + ("\"Polygon\"",3) + ("\"MultiPoint\"",4) + ("\"MultiLineString\"",5) + ("\"MultiPolygon\"",6) + ("\"GeometryCollection\"",7) + // + ; + + coordinates = eps(_r2 == 1) > point_coordinates(extract_geometry_(_r1)) + | eps(_r2 == 2) > linestring_coordinates(extract_geometry_(_r1)) + | eps(_r2 == 3) > polygon_coordinates(extract_geometry_(_r1)) + | eps(_r2 == 4) > multipoint_coordinates(extract_geometry_(_r1)) + | eps(_r2 == 5) > multilinestring_coordinates(extract_geometry_(_r1)) + | eps(_r2 == 6) > multipolygon_coordinates(extract_geometry_(_r1)) + ; + + point_coordinates = eps[ _a = new_(Point) ] + > ( point(SEG_MOVETO,_a) [push_back(_r1,_a)] | eps[cleanup_(_a)][_pass = false] ) + ; + + linestring_coordinates = eps[ _a = new_(LineString)] + > (points(_a) [push_back(_r1,_a)] + | eps[cleanup_(_a)][_pass = false]) + ; + + polygon_coordinates = eps[ _a = new_(Polygon) ] + > ((lit('[') + > points(_a) % lit(',') + > lit(']')) [push_back(_r1,_a)] + | eps[cleanup_(_a)][_pass = false]) + ; + + multipoint_coordinates = lit('[') + > (point_coordinates(_r1) % lit(',')) + > lit(']') + ; + + multilinestring_coordinates = lit('[') + > (linestring_coordinates(_r1) % lit(',')) + > lit(']') + ; + + multipolygon_coordinates = lit('[') + > (polygon_coordinates(_r1) % lit(',')) + > lit(']') + ; + + geometry_collection = *geometry(_r1) >> *(lit(',') >> geometry(_r1)) + ; + + // point + point = (lit('[') > double_ > lit(',') > double_ > lit(']')) [push_vertex_(_r1,_r2,_1,_2)]; + // points + points = lit('[')[_a = SEG_MOVETO] > point (_a,_r1) % lit(',') [_a = SEG_LINETO] > lit(']'); + + on_error + ( + feature + , std::cerr + << phoenix::val("Error! Expecting ") + << _4 // what failed? + << phoenix::val(" here: \"") + << construct(_3, _2) // iterators to error-pos, end + << phoenix::val("\"") + << std::endl + ); + + } + + // start + // generic JSON + qi::rule value; + qi::symbols unesc_char; + qi::uint_parser< unsigned, 16, 4, 4 > hex4 ; + qi::rule string_; + qi::rule key_value; + qi::rule(),ascii::space_type> number; + qi::rule object; + qi::rule array; + qi::rule pairs; + qi::real_parser > strict_double; + + // geoJSON + qi::rule feature; // START + qi::rule feature_type; + + // Nabialek trick ////////////////////////////////////// + //typedef typename qi::rule dispatch_rule; + //qi::rule, void(FeatureType&),ascii::space_type> geometry; + //qi::symbols geometry_dispatch; + //////////////////////////////////////////////////////// + + qi::rule, void(FeatureType&),ascii::space_type> geometry; + qi::symbols geometry_dispatch; + + qi::rule point; + qi::rule,void(geometry_type*),ascii::space_type> points; + qi::rule coordinates; + // + qi::rule, + void(boost::ptr_vector& ),ascii::space_type> point_coordinates; + qi::rule, + void(boost::ptr_vector& ),ascii::space_type> linestring_coordinates; + qi::rule, + void(boost::ptr_vector& ),ascii::space_type> polygon_coordinates; + + qi::rule& ),ascii::space_type> multipoint_coordinates; + qi::rule& ),ascii::space_type> multilinestring_coordinates; + qi::rule& ),ascii::space_type> multipolygon_coordinates; + qi::rule geometry_collection; + + qi::rule properties; + qi::rule, void(FeatureType &),ascii::space_type> attributes; + qi::rule(), ascii::space_type> attribute_value; + + phoenix::function put_property_; + phoenix::function extract_geometry_; + boost::phoenix::function push_vertex_; + boost::phoenix::function cleanup_; + +}; + +}} + +#endif // MAPNIK_FEATURE_GRAMMAR_HPP diff --git a/src/build.py b/src/build.py index 1fc21f836..ac0f902ca 100644 --- a/src/build.py +++ b/src/build.py @@ -163,6 +163,7 @@ source = Split( svg_points_parser.cpp svg_transform_parser.cpp warp.cpp + json/feature_collection_parser.cpp """ ) @@ -355,12 +356,14 @@ includes = glob.glob('../include/mapnik/*.hpp') svg_includes = glob.glob('../include/mapnik/svg/*.hpp') wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp') grid_includes = glob.glob('../include/mapnik/grid/*.hpp') +json_includes = glob.glob('../include/mapnik/json/*.hpp') util_includes = glob.glob('../include/mapnik/util/*.hpp') inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik') svg_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/svg') wkt_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/wkt') grid_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/grid') +json_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/json') util_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/util') if 'uninstall' not in COMMAND_LINE_TARGETS: @@ -368,10 +371,12 @@ if 'uninstall' not in COMMAND_LINE_TARGETS: env.Alias(target='install', source=env.Install(svg_inc_target, svg_includes)) env.Alias(target='install', source=env.Install(wkt_inc_target, wkt_includes)) env.Alias(target='install', source=env.Install(grid_inc_target, grid_includes)) + env.Alias(target='install', source=env.Install(json_inc_target, json_includes)) env.Alias(target='install', source=env.Install(util_inc_target, util_includes)) env['create_uninstall_target'](env, inc_target) env['create_uninstall_target'](env, svg_inc_target) env['create_uninstall_target'](env, wkt_inc_target) env['create_uninstall_target'](env, grid_inc_target) +env['create_uninstall_target'](env, json_inc_target) env['create_uninstall_target'](env, util_inc_target) diff --git a/src/json/feature_collection_parser.cpp b/src/json/feature_collection_parser.cpp new file mode 100644 index 000000000..eb8e0d12a --- /dev/null +++ b/src/json/feature_collection_parser.cpp @@ -0,0 +1,47 @@ +/***************************************************************************** + * + * 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 +#include + +namespace mapnik { namespace json { + +feature_collection_parser::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr) + : grammar_(new feature_collection_grammar(ctx,tr)) {} + +feature_collection_parser::~feature_collection_parser() {} + +bool feature_collection_parser::parse(std::string const& json, std::vector & features) +{ + using namespace boost::spirit; + iterator_type first = json.begin(); + iterator_type last = json.end(); + return qi::phrase_parse(first, last, *grammar_, ascii::space, features); +} + +}} + From 38e7b7cce066905ab07a21b48412bf1c644c87ad Mon Sep 17 00:00:00 2001 From: Matt Amos Date: Fri, 10 Feb 2012 15:21:02 +0000 Subject: [PATCH 09/16] Still need to increment pos counter in shapeindex even when the geometry is null, otherwise reads are possible beyond the end of file. --- utils/shapeindex/shapeindex.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp index 7777189b9..a5ba5ca81 100644 --- a/utils/shapeindex/shapeindex.cpp +++ b/utils/shapeindex/shapeindex.cpp @@ -165,6 +165,9 @@ int main (int argc,char** argv) box2d item_ext; if (shape_type==shape_io::shape_null) { + // still need to increment pos, or the pos counter + // won't indicate EOF until too late. + pos+=4+content_length; continue; } else if (shape_type==shape_io::shape_point) From 32ac2e464c865e2fb9e80dbafb7d78ea61f71ca8 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 10 Feb 2012 10:20:26 -0800 Subject: [PATCH 10/16] restore compile for boost 1.42 --- src/json/feature_collection_parser.cpp | 9 +++++++++ src/wkt/wkt_factory.cpp | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/json/feature_collection_parser.cpp b/src/json/feature_collection_parser.cpp index eb8e0d12a..8c5a811e6 100644 --- a/src/json/feature_collection_parser.cpp +++ b/src/json/feature_collection_parser.cpp @@ -30,17 +30,26 @@ namespace mapnik { namespace json { +#if BOOST_VERSION >= 104700 feature_collection_parser::feature_collection_parser(mapnik::context_ptr const& ctx, mapnik::transcoder const& tr) : grammar_(new feature_collection_grammar(ctx,tr)) {} feature_collection_parser::~feature_collection_parser() {} +#endif bool feature_collection_parser::parse(std::string const& json, std::vector & features) { +#if BOOST_VERSION >= 104700 using namespace boost::spirit; iterator_type first = json.begin(); iterator_type last = json.end(); return qi::phrase_parse(first, last, *grammar_, ascii::space, features); +#else + std::ostringstream s; + s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + throw std::runtime_error("mapnik::feature_collection_parser::parse() requires at least boost 1.47 while your build was compiled against boost " + s.str()); + return false; +#endif } }} diff --git a/src/wkt/wkt_factory.cpp b/src/wkt/wkt_factory.cpp index 46f300ec9..298b871fa 100644 --- a/src/wkt/wkt_factory.cpp +++ b/src/wkt/wkt_factory.cpp @@ -54,7 +54,6 @@ bool from_wkt(std::string const& wkt, boost::ptr_vector & paths) wkt_parser parser; return parser.parse(wkt,paths); #else - // TODO - remove this after mapnik 2.0.0 release std::ostringstream s; s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; throw std::runtime_error("mapnik::from_wkt() requires at least boost 1.47 while your build was compiled against boost " + s.str()); From 4bf8a7f69e0c08391138900461013b71efa92f67 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 10 Feb 2012 10:31:11 -0800 Subject: [PATCH 11/16] boost 1.42 compatibility --- include/mapnik/json/feature_grammar.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp index 707f89973..86b265d12 100644 --- a/include/mapnik/json/feature_grammar.hpp +++ b/include/mapnik/json/feature_grammar.hpp @@ -141,7 +141,11 @@ struct feature_grammar : using qi::lit; using qi::int_; using qi::double_; +#if BOOST_VERSION > 104200 using qi::no_skip; +#else + using qi::lexeme; +#endif using ascii::char_; using qi::_val; using qi::_1; From a682212266bb7ef0c30cf4dd1f836485a596b42d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 10 Feb 2012 11:20:00 -0800 Subject: [PATCH 12/16] small optimization by avoiding repeated case sensitive checks --- src/image_util.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/image_util.cpp b/src/image_util.cpp index cc845ad13..f5c19de18 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -158,7 +158,7 @@ void handle_png_options(std::string const& type, { *use_octree = true; } - else if (boost::algorithm::istarts_with(t, "c=")) + else if (boost::algorithm::starts_with(t, "c=")) { if (*colors < 0) throw ImageWriterException("invalid color parameter: unavailable for true color images"); @@ -170,7 +170,7 @@ void handle_png_options(std::string const& type, if (!r || (str_beg != str_end) || *colors < 0 || *colors > 256) throw ImageWriterException("invalid color parameter: " + val); } - else if (boost::algorithm::istarts_with(t, "t=")) + else if (boost::algorithm::starts_with(t, "t=")) { if (*colors < 0) throw ImageWriterException("invalid trans_mode parameter: unavailable for true color images"); @@ -182,7 +182,7 @@ void handle_png_options(std::string const& type, if (!r || (str_beg != str_end) || *trans_mode < 0 || *trans_mode > 2) throw ImageWriterException("invalid trans_mode parameter: " + val); } - else if (boost::algorithm::istarts_with(t, "g=")) + else if (boost::algorithm::starts_with(t, "g=")) { if (*colors < 0) throw ImageWriterException("invalid gamma parameter: unavailable for true color images"); @@ -195,7 +195,7 @@ void handle_png_options(std::string const& type, throw ImageWriterException("invalid gamma parameter: " + val); } } - else if (boost::algorithm::istarts_with(t, "z=")) + else if (boost::algorithm::starts_with(t, "z=")) { /* #define Z_NO_COMPRESSION 0 @@ -214,7 +214,7 @@ void handle_png_options(std::string const& type, throw ImageWriterException("invalid compression parameter: " + val + " (only -1 through 9 are valid)"); } } - else if (boost::algorithm::istarts_with(t, "s=")) + else if (boost::algorithm::starts_with(t, "s=")) { std::string const& s = t.substr(2); if (s == "default") @@ -251,7 +251,8 @@ void save_to_stream(T const& image, if (stream) { //all this should go into image_writer factory - if (type == "png" || boost::algorithm::istarts_with(type, "png")) + std::string t = boost::algorithm::to_lower_copy(type); + if (t == "png" || boost::algorithm::starts_with(t, "png")) { int colors = 256; int compression = Z_DEFAULT_COMPRESSION; @@ -260,7 +261,7 @@ void save_to_stream(T const& image, double gamma = -1; bool use_octree = true; - handle_png_options(type, + handle_png_options(t, &colors, &compression, &strategy, @@ -277,12 +278,12 @@ void save_to_stream(T const& image, else save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma); } - else if (boost::algorithm::istarts_with(type, "tif")) + else if (boost::algorithm::starts_with(t, "tif")) { throw ImageWriterException("palettes are not currently supported when writing to tiff format (yet)"); } #if defined(HAVE_JPEG) - else if (boost::algorithm::istarts_with(type, "jpeg")) + else if (boost::algorithm::starts_with(t, "jpeg")) { throw ImageWriterException("palettes are not currently supported when writing to jpeg format"); } @@ -301,7 +302,8 @@ void save_to_stream(T const& image, if (stream) { //all this should go into image_writer factory - if (type == "png" || boost::algorithm::istarts_with(type, "png")) + std::string t = boost::algorithm::to_lower_copy(type); + if (t == "png" || boost::algorithm::starts_with(t, "png")) { int colors = 256; int compression = Z_DEFAULT_COMPRESSION; @@ -310,7 +312,7 @@ void save_to_stream(T const& image, double gamma = -1; bool use_octree = true; - handle_png_options(type, + handle_png_options(t, &colors, &compression, &strategy, @@ -325,15 +327,15 @@ void save_to_stream(T const& image, else save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma); } - else if (boost::algorithm::istarts_with(type, "tif")) + else if (boost::algorithm::starts_with(t, "tif")) { save_as_tiff(stream, image); } #if defined(HAVE_JPEG) - else if (boost::algorithm::istarts_with(type, "jpeg")) + else if (boost::algorithm::starts_with(t, "jpeg")) { int quality = 85; - std::string const& val = type.substr(4); + std::string const& val = t.substr(4); if(!val.empty()) { std::string::const_iterator str_beg = val.begin(); From bfd79276a71ac30805d8102e42eb5fcc07bd89c6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 10 Feb 2012 12:14:53 -0800 Subject: [PATCH 13/16] only encode if image has dimensions (avoid abort in png writer on zero size width or height) --- src/image_util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/image_util.cpp b/src/image_util.cpp index f5c19de18..98851eb15 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -248,7 +248,7 @@ void save_to_stream(T const& image, std::string const& type, rgba_palette const& palette) { - if (stream) + if (stream && image.width() > 0 && image.height() > 0) { //all this should go into image_writer factory std::string t = boost::algorithm::to_lower_copy(type); @@ -299,7 +299,7 @@ void save_to_stream(T const& image, std::ostream & stream, std::string const& type) { - if (stream) + if (stream && image.width() > 0 && image.height() > 0) { //all this should go into image_writer factory std::string t = boost::algorithm::to_lower_copy(type); From 75e264a594b0056daff5e7fa28c861ff9d49dad9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 10 Feb 2012 12:15:23 -0800 Subject: [PATCH 14/16] only form up ostringstream if needed --- src/libxml2_loader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libxml2_loader.cpp b/src/libxml2_loader.cpp index 64a67f14a..c4111696f 100644 --- a/src/libxml2_loader.cpp +++ b/src/libxml2_loader.cpp @@ -84,10 +84,10 @@ public: if ( !doc ) { xmlError * error = xmlCtxtGetLastError( ctx_ ); - std::ostringstream os; - os << "XML document not well formed"; if (error) { + std::ostringstream os; + os << "XML document not well formed"; os << ": " << std::endl << error->message; // remove CR std::string msg = os.str().substr(0, os.str().size() - 1); From 0acd2137b8b30ac8401d67daf794cb623d933408 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 10 Feb 2012 15:14:15 -0800 Subject: [PATCH 15/16] restore agg renderer clip_box, accidentally disabled in 21d05444 - refs #1075 --- src/agg/agg_renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index 13a777f4e..ca9b81f83 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -189,8 +189,8 @@ void agg_renderer::start_map_processing(Map const& map) #ifdef MAPNIK_DEBUG std::clog << "start map processing bbox=" << map.get_current_extent() << "\n"; - ras_ptr->clip_box(0,0,width_,height_); #endif + ras_ptr->clip_box(0,0,width_,height_); } template From 7ef1c3544e0751a534072372f5ed29553dabb1ea Mon Sep 17 00:00:00 2001 From: Hermann Kraus Date: Sat, 11 Feb 2012 11:24:33 +0100 Subject: [PATCH 16/16] Bugfix: Collect expressions for formating::format_node. --- include/mapnik/text_processing.hpp | 1 + src/text_processing.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/mapnik/text_processing.hpp b/include/mapnik/text_processing.hpp index 9807b835c..c6349b24b 100644 --- a/include/mapnik/text_processing.hpp +++ b/include/mapnik/text_processing.hpp @@ -143,6 +143,7 @@ public: void to_xml(boost::property_tree::ptree &xml) const; static node_ptr from_xml(boost::property_tree::ptree const& xml); virtual void apply(char_properties const& p, Feature const& feature, processed_text &output) const; + virtual void add_expressions(expression_set &output) const; void set_child(node_ptr child); node_ptr get_child() const; diff --git a/src/text_processing.cpp b/src/text_processing.cpp index be352b6b2..c02243608 100644 --- a/src/text_processing.cpp +++ b/src/text_processing.cpp @@ -277,6 +277,11 @@ node_ptr format_node::get_child() const return child_; } +void format_node::add_expressions(expression_set &output) const +{ + if (child_) child_->add_expressions(output); +} + } //namespace formating /************************************************************/