Merge branch 'master' into mapnik-geometry

This commit is contained in:
artemp 2015-03-09 14:59:45 +01:00
commit 317e9c497f
21 changed files with 251 additions and 77 deletions

View file

@ -52,6 +52,7 @@ Mapnik is written by Artem Pavlenko with contributions from:
* Igor Podolskiy * Igor Podolskiy
* Reid Priedhorsky * Reid Priedhorsky
* Brian Quinion * Brian Quinion
* Even Rouault
* Marcin Rudowski * Marcin Rudowski
* Sandro Santilli * Sandro Santilli
* Christopher Schmidt * Christopher Schmidt

View file

@ -1283,6 +1283,7 @@ if not preconfigured:
else: else:
env['MISSING_DEPS'].append('libxml2') env['MISSING_DEPS'].append('libxml2')
if not env['HOST']:
if conf.CheckHasDlfcn(): if conf.CheckHasDlfcn():
env.Append(CPPDEFINES = '-DMAPNIK_HAS_DLCFN') env.Append(CPPDEFINES = '-DMAPNIK_HAS_DLCFN')
else: else:
@ -1340,7 +1341,7 @@ if not preconfigured:
conf.prioritize_paths(silent=True) conf.prioritize_paths(silent=True)
# test for C++11 support, which is required # test for C++11 support, which is required
if not conf.supports_cxx11(): if not env['HOST'] and not conf.supports_cxx11():
color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)") color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)")
Exit(1) Exit(1)
@ -1361,7 +1362,7 @@ if not preconfigured:
env['MISSING_DEPS'].append(env['ICU_LIB_NAME']) env['MISSING_DEPS'].append(env['ICU_LIB_NAME'])
elif libname == 'harfbuzz': elif libname == 'harfbuzz':
if not conf.harfbuzz_version(): if not conf.harfbuzz_version():
env['MISSING_DEPS'].append('harfbuzz-min-version') env['SKIPPED_DEPS'].append('harfbuzz-min-version')
if env['BIGINT']: if env['BIGINT']:
env.Append(CPPDEFINES = '-DBIGINT') env.Append(CPPDEFINES = '-DBIGINT')

View file

@ -222,6 +222,11 @@ void set_pixel_int(mapnik::image_any & im, unsigned x, unsigned y, int val)
mapnik::set_pixel(im, x, y, val); mapnik::set_pixel(im, x, y, val);
} }
unsigned get_type(mapnik::image_any & im)
{
return im.get_dtype();
}
std::shared_ptr<image_any> open_from_file(std::string const& filename) std::shared_ptr<image_any> open_from_file(std::string const& filename)
{ {
boost::optional<std::string> type = type_from_filename(filename); boost::optional<std::string> type = type_from_filename(filename);
@ -441,6 +446,7 @@ void export_image()
arg("y"), arg("y"),
arg("get_color")=false arg("get_color")=false
)) ))
.def("get_type",&get_type)
.def("clear",&clear) .def("clear",&clear)
//TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3 //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3

View file

@ -124,6 +124,7 @@ class image
public: public:
using pixel = T; using pixel = T;
using pixel_type = typename T::type; using pixel_type = typename T::type;
static const image_dtype dtype = T::id;
static constexpr std::size_t pixel_size = sizeof(pixel_type); static constexpr std::size_t pixel_size = sizeof(pixel_type);
private: private:
detail::image_dimensions<max_size> dimensions_; detail::image_dimensions<max_size> dimensions_;
@ -313,6 +314,11 @@ public:
{ {
return painted_; return painted_;
} }
inline image_dtype get_dtype() const
{
return dtype;
}
}; };
using image_rgba8 = image<rgba8_t>; using image_rgba8 = image<rgba8_t>;
@ -327,22 +333,6 @@ using image_gray64 = image<gray64_t>;
using image_gray64s = image<gray64s_t>; using image_gray64s = image<gray64s_t>;
using image_gray64f = image<gray64f_t>; using image_gray64f = image<gray64f_t>;
enum image_dtype : std::uint8_t
{
image_dtype_rgba8 = 0,
image_dtype_gray8,
image_dtype_gray8s,
image_dtype_gray16,
image_dtype_gray16s,
image_dtype_gray32,
image_dtype_gray32s,
image_dtype_gray32f,
image_dtype_gray64,
image_dtype_gray64s,
image_dtype_gray64f,
image_dtype_null
};
} // end ns } // end ns
#endif // MAPNIK_IMAGE_DATA_HPP #endif // MAPNIK_IMAGE_DATA_HPP

View file

@ -31,6 +31,7 @@ namespace mapnik {
struct image_null struct image_null
{ {
using pixel_type = uint8_t; using pixel_type = uint8_t;
static const image_dtype dtype = image_dtype_null;
unsigned char const* getBytes() const { return nullptr; } unsigned char const* getBytes() const { return nullptr; }
unsigned char* getBytes() { return nullptr;} unsigned char* getBytes() { return nullptr;}
unsigned getSize() const { return 0; } unsigned getSize() const { return 0; }
@ -40,6 +41,7 @@ struct image_null
bool painted() const { return false; } bool painted() const { return false; }
double get_offset() const { return 0.0; } double get_offset() const { return 0.0; }
void set_offset(double) {} void set_offset(double) {}
image_dtype get_dtype() const { return dtype; }
double get_scaling() const { return 1.0; } double get_scaling() const { return 1.0; }
void set_scaling(double) {} void set_scaling(double) {}
bool get_premultiplied() const { return false; } bool get_premultiplied() const { return false; }
@ -88,6 +90,15 @@ struct get_bytes_visitor
} }
}; };
struct get_dtype_visitor
{
template <typename T>
image_dtype operator()(T & data)
{
return data.get_dtype();
}
};
struct get_bytes_visitor_const struct get_bytes_visitor_const
{ {
template <typename T> template <typename T>
@ -263,6 +274,11 @@ struct image_any : image_base
return util::apply_visitor(detail::get_scaling_visitor(),*this); return util::apply_visitor(detail::get_scaling_visitor(),*this);
} }
image_dtype get_dtype() const
{
return util::apply_visitor(detail::get_dtype_visitor(),*this);
}
void set_offset(double val) void set_offset(double val)
{ {
util::apply_visitor(detail::set_offset_visitor(val),*this); util::apply_visitor(detail::set_offset_visitor(val),*this);
@ -306,6 +322,7 @@ inline image_any create_image_any(int width,
case image_dtype_null: case image_dtype_null:
return image_any(std::move(image_null())); return image_any(std::move(image_null()));
case image_dtype_rgba8: case image_dtype_rgba8:
case IMAGE_DTYPE_MAX:
default: default:
return image_any(std::move(image_rgba8(width, height, initialize, premultiplied, painted))); return image_any(std::move(image_rgba8(width, height, initialize, premultiplied, painted)));
} }

View file

@ -33,6 +33,7 @@ class image_view
public: public:
using pixel = typename T::pixel; using pixel = typename T::pixel;
using pixel_type = typename T::pixel_type; using pixel_type = typename T::pixel_type;
static const image_dtype dtype = T::dtype;
static constexpr std::size_t pixel_size = sizeof(pixel_type); static constexpr std::size_t pixel_size = sizeof(pixel_type);
image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data) image_view(unsigned x, unsigned y, unsigned width, unsigned height, T const& data)
@ -42,8 +43,8 @@ public:
height_(height), height_(height),
data_(data) data_(data)
{ {
if (x_ >= data_.width()) x_=data_.width()-1; if (x_ >= data_.width() && data_.width() > 0) x_ = data_.width() - 1;
if (y_ >= data_.height()) y_=data_.height()-1; if (y_ >= data_.height() && data.height() > 0) y_ = data_.height() - 1;
if (x_ + width_ > data_.width()) width_ = data_.width() - x_; if (x_ + width_ > data_.width()) width_ = data_.width() - x_;
if (y_ + height_ > data_.height()) height_ = data_.height() - y_; if (y_ + height_ > data_.height()) height_ = data_.height() - y_;
} }
@ -132,6 +133,11 @@ public:
return data_.get_scaling(); return data_.get_scaling();
} }
inline image_dtype get_dtype() const
{
return dtype;
}
private: private:
unsigned x_; unsigned x_;
unsigned y_; unsigned y_;

View file

@ -69,6 +69,15 @@ struct get_view_size_visitor
} }
}; };
struct get_view_dtype_visitor
{
template <typename T>
image_dtype operator()(T const& data) const
{
return data.get_dtype();
}
};
struct get_view_row_size_visitor struct get_view_row_size_visitor
{ {
template <typename T> template <typename T>
@ -148,6 +157,11 @@ struct image_view_any : image_view_base
{ {
return util::apply_visitor(detail::get_view_scaling_visitor(),*this); return util::apply_visitor(detail::get_view_scaling_visitor(),*this);
} }
image_dtype get_dtype() const
{
return util::apply_visitor(detail::get_view_dtype_visitor(),*this);
}
}; };
} }

View file

@ -25,16 +25,36 @@
#include <mapnik/global.hpp> #include <mapnik/global.hpp>
struct rgba8_t { using type = std::uint32_t; }; namespace mapnik {
struct gray8_t { using type = std::uint8_t; };
struct gray8s_t { using type = std::int8_t; };
struct gray16_t { using type = std::uint16_t; };
struct gray16s_t { using type = std::int16_t; };
struct gray32_t { using type = std::uint32_t; };
struct gray32s_t { using type = std::int32_t; };
struct gray32f_t { using type = float; };
struct gray64_t { using type = std::uint64_t; };
struct gray64s_t { using type = std::int64_t; };
struct gray64f_t { using type = double; };
enum image_dtype : std::uint8_t
{
image_dtype_rgba8 = 0,
image_dtype_gray8,
image_dtype_gray8s,
image_dtype_gray16,
image_dtype_gray16s,
image_dtype_gray32,
image_dtype_gray32s,
image_dtype_gray32f,
image_dtype_gray64,
image_dtype_gray64s,
image_dtype_gray64f,
image_dtype_null,
IMAGE_DTYPE_MAX
};
struct rgba8_t { using type = std::uint32_t; static const image_dtype id = image_dtype_rgba8; };
struct gray8_t { using type = std::uint8_t; static const image_dtype id = image_dtype_gray8; };
struct gray8s_t { using type = std::int8_t; static const image_dtype id = image_dtype_gray8s; };
struct gray16_t { using type = std::uint16_t; static const image_dtype id = image_dtype_gray16; };
struct gray16s_t { using type = std::int16_t; static const image_dtype id = image_dtype_gray16s; };
struct gray32_t { using type = std::uint32_t; static const image_dtype id = image_dtype_gray32; };
struct gray32s_t { using type = std::int32_t; static const image_dtype id = image_dtype_gray32s; };
struct gray32f_t { using type = float; static const image_dtype id = image_dtype_gray32f; };
struct gray64_t { using type = std::uint64_t; static const image_dtype id = image_dtype_gray64; };
struct gray64s_t { using type = std::int64_t; static const image_dtype id = image_dtype_gray64s; };
struct gray64f_t { using type = double; static const image_dtype id = image_dtype_gray64f; };
} // end ns
#endif // MAPNIK_PIXEL_TYPES_HPP #endif // MAPNIK_PIXEL_TYPES_HPP

View file

@ -176,18 +176,19 @@ geojson_datasource::geojson_datasource(parameters const& params)
namespace { namespace {
using base_iterator_type = char const*; using base_iterator_type = char const*;
const mapnik::transcoder tr("utf8"); const mapnik::transcoder geojson_datasource_static_tr("utf8");
const mapnik::json::feature_collection_grammar<base_iterator_type,mapnik::feature_impl> fc_grammar(tr); const mapnik::json::feature_collection_grammar<base_iterator_type,mapnik::feature_impl> geojson_datasource_static_fc_grammar(geojson_datasource_static_tr);
const mapnik::json::feature_grammar<base_iterator_type, mapnik::feature_impl> geojson_datasource_static_feature_grammar(geojson_datasource_static_tr);
const mapnik::json::extract_bounding_box_grammar<base_iterator_type> geojson_datasource_static_bbox_grammar;
} }
template <typename Iterator> template <typename Iterator>
void geojson_datasource::initialise_index(Iterator start, Iterator end) void geojson_datasource::initialise_index(Iterator start, Iterator end)
{ {
mapnik::json::boxes boxes; mapnik::json::boxes boxes;
mapnik::json::extract_bounding_box_grammar<Iterator> bbox_grammar;
boost::spirit::ascii::space_type space; boost::spirit::ascii::space_type space;
Iterator itr = start; Iterator itr = start;
if (!boost::spirit::qi::phrase_parse(itr, end, (bbox_grammar)(boost::phoenix::ref(boxes)) , space)) if (!boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_bbox_grammar)(boost::phoenix::ref(boxes)) , space))
{ {
throw mapnik::datasource_exception("GeoJSON Plugin: could not parse: '" + filename_ + "'"); throw mapnik::datasource_exception("GeoJSON Plugin: could not parse: '" + filename_ + "'");
} }
@ -207,10 +208,8 @@ void geojson_datasource::initialise_index(Iterator start, Iterator end)
Iterator end = itr + geometry_index.second; Iterator end = itr + geometry_index.second;
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1)); mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1));
static const mapnik::transcoder tr("utf8");
static const mapnik::json::feature_grammar<Iterator, mapnik::feature_impl> grammar(tr);
boost::spirit::ascii::space_type space; boost::spirit::ascii::space_type space;
if (!boost::spirit::qi::phrase_parse(itr, end, (grammar)(boost::phoenix::ref(*feature)), space)) if (!boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_feature_grammar)(boost::phoenix::ref(*feature)), space))
{ {
throw std::runtime_error("Failed to parse geojson feature"); throw std::runtime_error("Failed to parse geojson feature");
} }
@ -237,7 +236,7 @@ void geojson_datasource::parse_geojson(Iterator start, Iterator end)
mapnik::json::default_feature_callback callback(features_); mapnik::json::default_feature_callback callback(features_);
bool result = boost::spirit::qi::phrase_parse(start, end, (fc_grammar) bool result = boost::spirit::qi::phrase_parse(start, end, (geojson_datasource_static_fc_grammar)
(boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)), (boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
space); space);
if (!result) if (!result)

View file

@ -58,7 +58,7 @@ public:
{ {
std::string err_msg = "Postgis Plugin: "; std::string err_msg = "Postgis Plugin: ";
err_msg += status(); err_msg += status();
err_msg += "\nConnection string: '"; err_msg += "Connection string: '";
err_msg += connection_str; err_msg += connection_str;
err_msg += "'\n"; err_msg += "'\n";
MAPNIK_LOG_DEBUG(postgis) << "postgis_connection: creation failed, closing connection - " << this; MAPNIK_LOG_DEBUG(postgis) << "postgis_connection: creation failed, closing connection - " << this;
@ -71,7 +71,7 @@ public:
if ( ! ok ) { if ( ! ok ) {
std::string err_msg = "Postgis Plugin: "; std::string err_msg = "Postgis Plugin: ";
err_msg += status(); err_msg += status();
err_msg += "\nConnection string: '"; err_msg += "Connection string: '";
err_msg += connection_str; err_msg += connection_str;
err_msg += "'\n"; err_msg += "'\n";
close(); close();
@ -127,7 +127,7 @@ public:
{ {
std::string err_msg = "Postgis Plugin: "; std::string err_msg = "Postgis Plugin: ";
err_msg += status(); err_msg += status();
err_msg += "\nin executeQuery Full sql was: '"; err_msg += "in executeQuery Full sql was: '";
err_msg += sql; err_msg += sql;
err_msg += "'\n"; err_msg += "'\n";
if ( result ) PQclear(result); if ( result ) PQclear(result);
@ -142,12 +142,19 @@ public:
std::string status; std::string status;
if (conn_) if (conn_)
{ {
if ( isOK() ) return PQerrorMessage(conn_); char * err_msg = PQerrorMessage(conn_);
else return "Bad connection"; if (err_msg == nullptr)
{
status = "Bad connection\n";
} }
else else
{ {
status = "Uninitialized connection"; status = std::string(err_msg);
}
}
else
{
status = "Uninitialized connection\n";
} }
return status; return status;
} }
@ -167,7 +174,7 @@ public:
{ {
std::string err_msg = "Postgis Plugin: "; std::string err_msg = "Postgis Plugin: ";
err_msg += status(); err_msg += status();
err_msg += "\nin executeAsyncQuery Full sql was: '"; err_msg += "in executeAsyncQuery Full sql was: '";
err_msg += sql; err_msg += sql;
err_msg += "'\n"; err_msg += "'\n";
clearAsyncResult(PQgetResult(conn_)); clearAsyncResult(PQgetResult(conn_));
@ -191,7 +198,7 @@ public:
{ {
std::string err_msg = "Postgis Plugin: "; std::string err_msg = "Postgis Plugin: ";
err_msg += status(); err_msg += status();
err_msg += "\nin getNextAsyncResult"; err_msg += "in getNextAsyncResult";
clearAsyncResult(result); clearAsyncResult(result);
// We need to guarde against losing the connection // We need to guarde against losing the connection
// (i.e db restart) so here we invalidate the full connection // (i.e db restart) so here we invalidate the full connection
@ -208,7 +215,7 @@ public:
{ {
std::string err_msg = "Postgis Plugin: "; std::string err_msg = "Postgis Plugin: ";
err_msg += status(); err_msg += status();
err_msg += "\nin getAsyncResult"; err_msg += "in getAsyncResult";
clearAsyncResult(result); clearAsyncResult(result);
// We need to be guarded against losing the connection // We need to be guarded against losing the connection
// (i.e db restart), we invalidate the full connection // (i.e db restart), we invalidate the full connection

View file

@ -159,6 +159,10 @@ postgis_datasource::postgis_datasource(parameters const& params)
geometry_table_ = geometry_table_.substr(0); geometry_table_ = geometry_table_.substr(0);
} }
// NOTE: geometry_table_ how should ideally be a table name, but
// there are known edge cases where this will break down and
// geometry_table_ may even be empty: https://github.com/mapnik/mapnik/issues/2718
// If we do not know both the geometry_field and the srid // If we do not know both the geometry_field and the srid
// then first attempt to fetch the geometry name from a geometry_columns entry. // then first attempt to fetch the geometry name from a geometry_columns entry.
// This will return no records if we are querying a bogus table returned // This will return no records if we are querying a bogus table returned
@ -166,7 +170,7 @@ postgis_datasource::postgis_datasource(parameters const& params)
// the table parameter references a table, view, or subselect not // the table parameter references a table, view, or subselect not
// registered in the geometry columns. // registered in the geometry columns.
geometryColumn_ = geometry_field_; geometryColumn_ = geometry_field_;
if (geometryColumn_.empty() || srid_ == 0) if (!geometry_table_.empty() && (geometryColumn_.empty() || srid_ == 0))
{ {
#ifdef MAPNIK_STATS #ifdef MAPNIK_STATS
mapnik::progress_timer __stats2__(std::clog, "postgis_datasource::init(get_srid_and_geometry_column)"); mapnik::progress_timer __stats2__(std::clog, "postgis_datasource::init(get_srid_and_geometry_column)");
@ -227,8 +231,16 @@ postgis_datasource::postgis_datasource(parameters const& params)
{ {
std::ostringstream s; std::ostringstream s;
s << "SELECT ST_SRID(\"" << geometryColumn_ << "\") AS srid FROM " s << "SELECT ST_SRID(\"" << geometryColumn_ << "\") AS srid FROM ";
<< populate_tokens(geometry_table_) << " WHERE \"" << geometryColumn_ << "\" IS NOT NULL LIMIT 1;"; if (!geometry_table_.empty())
{
s << geometry_table_;
}
else
{
s << populate_tokens(table_);
}
s << " WHERE \"" << geometryColumn_ << "\" IS NOT NULL LIMIT 1;";
shared_ptr<ResultSet> rs = conn->executeQuery(s.str()); shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next()) if (rs->next())

View file

@ -251,7 +251,7 @@ if env['PLUGIN_LINKING'] == 'static':
lib_env.AppendUnique(CPPPATH='../plugins/') lib_env.AppendUnique(CPPPATH='../plugins/')
for plugin in env['REQUESTED_PLUGINS']: for plugin in env['REQUESTED_PLUGINS']:
details = env['PLUGINS'][plugin] details = env['PLUGINS'][plugin]
if details['lib'] in env['LIBS'] or not details['lib']: if not details['lib'] or details['lib'] in env['LIBS']:
plugin_env = SConscript('../plugins/input/%s/build.py' % plugin) plugin_env = SConscript('../plugins/input/%s/build.py' % plugin)
if not plugin_env: if not plugin_env:
print("Notice: no 'plugin_env' variable found for plugin: '%s'" % plugin) print("Notice: no 'plugin_env' variable found for plugin: '%s'" % plugin)

View file

@ -40,8 +40,24 @@ expression_ptr parse_expression(std::string const& str)
auto node = std::make_shared<expr_node>(); auto node = std::make_shared<expr_node>();
std::string::const_iterator itr = str.begin(); std::string::const_iterator itr = str.begin();
std::string::const_iterator end = str.end(); std::string::const_iterator end = str.end();
try { bool r = false;
bool r = boost::spirit::qi::phrase_parse(itr, end, g, space, *node); try
{
r = boost::spirit::qi::phrase_parse(itr, end, g, space, *node);
}
catch (std::exception const& ex)
{
if (std::string("boost::spirit::qi::expectation_failure") == std::string(ex.what()))
{
// no need to show "boost::spirit::qi::expectation_failure" which is a std::runtime_error
throw config_error("Failed to parse expression: \"" + str + "\"");
}
else
{
// show "Could not initialize ICU resources" from boost::regex which is a std::runtime_error
throw config_error(std::string(ex.what()) + " for expression: \"" + str + "\"");
}
}
if (r && itr == end) if (r && itr == end)
{ {
return node; return node;
@ -51,11 +67,6 @@ expression_ptr parse_expression(std::string const& str)
throw config_error("Failed to parse expression: \"" + str + "\""); throw config_error("Failed to parse expression: \"" + str + "\"");
} }
} }
catch (std::exception const&) // boost::spirit::qi::expectation_failure
{
throw config_error("Failed to parse expression: \"" + str + "\"");
}
}
} }

View file

@ -93,9 +93,19 @@ struct visitor_image_copy_so
} }
T0 operator() (T0 const& src) T0 operator() (T0 const& src)
{
if (offset_ == src.get_offset() && scaling_ == src.get_scaling())
{ {
return T0(src); return T0(src);
} }
else
{
T0 dst(src);
dst.set_scaling(scaling_);
dst.set_offset(offset_);
return T0(std::move(dst));
}
}
template <typename T1> template <typename T1>
T0 operator() (T1 const& src) T0 operator() (T1 const& src)
@ -340,6 +350,10 @@ MAPNIK_DECL image_any image_copy(image_any const& data, image_dtype type, double
return image_any(std::move(image_copy<image_gray64f>(data, offset, scaling))); return image_any(std::move(image_copy<image_gray64f>(data, offset, scaling)));
case image_dtype_null: case image_dtype_null:
throw std::runtime_error("Can not cast a null image"); throw std::runtime_error("Can not cast a null image");
case IMAGE_DTYPE_MAX:
default:
throw std::runtime_error("Can not cast unknown type");
} }
throw std::runtime_error("Unknown image type passed"); throw std::runtime_error("Unknown image type passed");
} }

View file

@ -46,11 +46,24 @@ jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t):
stream_(stream), t_(t) {} stream_(stream), t_(t) {}
template <typename T> template <typename T>
void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & stream) void process_rgba8_jpeg(T const& image, std::string const& type, std::ostream & stream)
{ {
#if defined(HAVE_JPEG) #if defined(HAVE_JPEG)
int quality = 85; int quality = 85;
std::string val = t.substr(4); //std::string val = type.substr(4);
if (type != "jpeg")
{
boost::char_separator<char> sep(":");
boost::tokenizer< boost::char_separator<char> > tokens(type, sep);
for (auto const& t : tokens)
{
if (t == "jpeg")
{
continue;
}
else if (boost::algorithm::starts_with(t, "quality="))
{
std::string val = t.substr(8);
if (!val.empty()) if (!val.empty())
{ {
if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100) if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100)
@ -58,6 +71,9 @@ void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & str
throw ImageWriterException("invalid jpeg quality: '" + val + "'"); throw ImageWriterException("invalid jpeg quality: '" + val + "'");
} }
} }
}
}
}
save_as_jpeg(stream, quality, image); save_as_jpeg(stream, quality, image);
#else #else
throw ImageWriterException("jpeg output is not enabled in your build of Mapnik"); throw ImageWriterException("jpeg output is not enabled in your build of Mapnik");

View file

@ -3,6 +3,12 @@
"objects": { "objects": {
"escaped": { "escaped": {
"type": "GeometryCollection", "type": "GeometryCollection",
"bbox": [
-180,
-90,
180,
90
],
"geometries": [ "geometries": [
{ {
"type": "Point", "type": "Point",

View file

@ -10,6 +10,12 @@ def setup():
# from another directory we need to chdir() # from another directory we need to chdir()
os.chdir(execution_path('.')) os.chdir(execution_path('.'))
def test_type():
im = mapnik.Image(256, 256)
eq_(im.get_type(), mapnik.ImageType.rgba8)
im = mapnik.Image(256, 256, mapnik.ImageType.gray8)
eq_(im.get_type(), mapnik.ImageType.gray8)
def test_image_premultiply(): def test_image_premultiply():
im = mapnik.Image(256,256) im = mapnik.Image(256,256)
eq_(im.premultiplied(),False) eq_(im.premultiplied(),False)

View file

@ -53,7 +53,7 @@ def test_can_parse_xml_with_deprecated_properties():
except RuntimeError, e: except RuntimeError, e:
# only test datasources that we have installed # only test datasources that we have installed
if not 'Could not create datasource' in str(e) \ if not 'Could not create datasource' in str(e) \
and not 'Bad connection' in str(e): and not 'could not connect' in str(e):
failures.append('Failed to load valid map %s (%s)' % (filename,e)) failures.append('Failed to load valid map %s (%s)' % (filename,e))
eq_(len(failures),0,'\n'+'\n'.join(failures)) eq_(len(failures),0,'\n'+'\n'.join(failures))
mapnik.logger.set_severity(default_logging_severity) mapnik.logger.set_severity(default_logging_severity)
@ -73,7 +73,7 @@ def test_good_files():
except RuntimeError, e: except RuntimeError, e:
# only test datasources that we have installed # only test datasources that we have installed
if not 'Could not create datasource' in str(e) \ if not 'Could not create datasource' in str(e) \
and not 'Bad connection' in str(e): and not 'could not connect' in str(e):
failures.append('Failed to load valid map %s (%s)' % (filename,e)) failures.append('Failed to load valid map %s (%s)' % (filename,e))
eq_(len(failures),0,'\n'+'\n'.join(failures)) eq_(len(failures),0,'\n'+'\n'.join(failures))

View file

@ -283,6 +283,16 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
eq_(meta['encoding'],u'UTF8') eq_(meta['encoding'],u'UTF8')
eq_(meta['geometry_type'],mapnik.DataGeometryType.Polygon) eq_(meta['geometry_type'],mapnik.DataGeometryType.Polygon)
def test_bad_connection():
try:
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,
table='test',
max_size=20,
geometry_field='geom',
user="rolethatdoesnotexist")
except Exception, e:
assert 'role "rolethatdoesnotexist" does not exist' in str(e)
def test_empty_db(): def test_empty_db():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='empty') ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='empty')
fs = ds.featureset() fs = ds.featureset()
@ -844,7 +854,8 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
fs = ds_bad.featureset() fs = ds_bad.featureset()
for feature in fs: for feature in fs:
pass pass
except RuntimeError: except RuntimeError, e:
assert 'invalid input syntax for integer' in str(e)
failed = True failed = True
eq_(failed,True) eq_(failed,True)
@ -907,7 +918,8 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
mapnik.render_to_file(map1,'/tmp/mapnik-postgis-test-map1.png', 'png') mapnik.render_to_file(map1,'/tmp/mapnik-postgis-test-map1.png', 'png')
# Test must fail if error was not raised just above # Test must fail if error was not raised just above
eq_(False,True) eq_(False,True)
except RuntimeError: except RuntimeError, e:
assert 'invalid input syntax for integer' in str(e)
pass pass
# This used to raise an exception before correction of issue 2042 # This used to raise an exception before correction of issue 2042
mapnik.render_to_file(map2,'/tmp/mapnik-postgis-test-map2.png', 'png') mapnik.render_to_file(map2,'/tmp/mapnik-postgis-test-map2.png', 'png')
@ -1158,6 +1170,42 @@ if 'postgis' in mapnik.DatasourceCache.plugin_names() \
eq_(meta.get('key_field'),"gid") eq_(meta.get('key_field'),"gid")
eq_(meta['geometry_type'],None) eq_(meta['geometry_type'],None)
# currently needs manual `geometry_table` passed
# to avoid misparse of `geometry_table`
# in the future ideally this would not need manual `geometry_table`
# https://github.com/mapnik/mapnik/issues/2718
# currently `bogus` would be picked automatically for geometry_table
def test_broken_parsing_of_comments():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='''
(select * FROM test) AS data
-- select this from bogus''',
geometry_table='test')
fs = ds.featureset()
for id in range(1,5):
eq_(fs.next().id(),id)
meta = ds.describe()
eq_(meta['srid'],4326)
eq_(meta['geometry_type'],mapnik.DataGeometryType.Collection)
# same
# to avoid misparse of `geometry_table`
# in the future ideally this would not need manual `geometry_table`
# https://github.com/mapnik/mapnik/issues/2718
# currently nothing would be picked automatically for geometry_table
def test_broken_parsing_of_comments():
ds = mapnik.PostGIS(dbname=MAPNIK_TEST_DBNAME,table='''
(select * FROM test) AS data
-- select this from bogus.''',
geometry_table='test')
fs = ds.featureset()
for id in range(1,5):
eq_(fs.next().id(),id)
meta = ds.describe()
eq_(meta['srid'],4326)
eq_(meta['geometry_type'],mapnik.DataGeometryType.Collection)
atexit.register(postgis_takedown) atexit.register(postgis_takedown)

View file

@ -27,7 +27,7 @@ def compare_map(xml):
except RuntimeError, e: except RuntimeError, e:
# only test datasources that we have installed # only test datasources that we have installed
if not 'Could not create datasource' in str(e) \ if not 'Could not create datasource' in str(e) \
and not 'Bad connection' in str(e): and not 'could not connect' in str(e):
raise RuntimeError(str(e)) raise RuntimeError(str(e))
return return
(handle, test_map) = tempfile.mkstemp(suffix='.xml', prefix='mapnik-temp-map1-') (handle, test_map) = tempfile.mkstemp(suffix='.xml', prefix='mapnik-temp-map1-')

View file

@ -214,7 +214,7 @@ def render(filename, config, scale_factor, reporting):
return return
except Exception, e: except Exception, e:
if 'Could not create datasource' in str(e) \ if 'Could not create datasource' in str(e) \
or 'Bad connection' in str(e): or 'could not connect' in str(e):
return m return m
reporting.other_error(filename, repr(e)) reporting.other_error(filename, repr(e))
return m return m