Merge branch 'master' of github.com:mapnik/mapnik

This commit is contained in:
Dane Springmeyer 2012-04-11 08:06:47 -07:00
commit f5da52bb22
13 changed files with 639 additions and 478 deletions

View File

@ -2,60 +2,60 @@
Mapnik is written by Artem Pavlenko with contributions from:
Andy Allen
AJ Ashton
Matt Amos
Lucio Asnaghi
Justin Bronn
Christopher Brown
Jon Burgess
Toby Collet
Robert Coup
Berteun Damman
Craig de Stigter
Jean-Francois Doyon
David Eastcott
Krzysztof Godlewski
Beau Gunderson
John Hague
Dominic Hargreaves
Aubrey Holland
Tom Hughes
Konstantin Käfer
Mak Kolybabi
Peter Körner
Hermann Kraus
Stella Laurenzo
David Leaver
Carlos López
Dennis Luxen
Tom MacWright
Michal Migurski
Andrii Mishkovskyi
Ben Moores
Dražen Odobašić
Cameron Patrick
Igor Podolskiy
Reid Priedhorsky
Brian Quinion
Marcin Rudowski
Christopher Schmidt
Andreas Schneider
Vincent Schut
Ehud Shabtai
David Siegel
Steve Singer
Paul Smith
Vince Spader
Philipp Spitzer
Dane Springmeyer
Dave Stubbs
River Tarnell
Oliver Tonnhofer
Alberto Valverde
Martijn van Oosterhout
Andreas Volz
Lennard voor den Dag
Shaun Walbridge
Nick Whitelegg
Leslie Wu
* Andy Allen
* AJ Ashton
* Matt Amos
* Lucio Asnaghi
* Justin Bronn
* Christopher Brown
* Jon Burgess
* Toby Collet
* Robert Coup
* Berteun Damman
* Craig de Stigter
* Jean-Francois Doyon
* David Eastcott
* Krzysztof Godlewski
* Beau Gunderson
* John Hague
* Dominic Hargreaves
* Aubrey Holland
* Tom Hughes
* Konstantin Käfer
* Mak Kolybabi
* Peter Körner
* Hermann Kraus
* Stella Laurenzo
* David Leaver
* Carlos López
* Dennis Luxen
* Tom MacWright
* Michal Migurski
* Andrii Mishkovskyi
* Ben Moores
* Dražen Odobašić
* Cameron Patrick
* Igor Podolskiy
* Reid Priedhorsky
* Brian Quinion
* Marcin Rudowski
* Christopher Schmidt
* Andreas Schneider
* Vincent Schut
* Ehud Shabtai
* David Siegel
* Steve Singer
* Paul Smith
* Vince Spader
* Philipp Spitzer
* Dane Springmeyer
* Dave Stubbs
* River Tarnell
* Oliver Tonnhofer
* Alberto Valverde
* Martijn van Oosterhout
* Andreas Volz
* Lennard voor den Dag
* Shaun Walbridge
* Nick Whitelegg
* Leslie Wu

View File

@ -9,6 +9,8 @@ For a complete change history, see the SVN log.
## Mapnik 2.1.0
- Improved logging/debugging system with release logs and file redirection (#937 and partially #986, #467)
- GDAL: allow setting nodata value on the fly (will override value if nodata is set in data) (#1161)
- GDAL: respect nodata for paletted/colormapped images (#1160)

View File

@ -347,7 +347,7 @@ opts.AddVariables(
# Variables for logging and statistics
BoolVariable('ENABLE_LOG', 'Enable logging, which is enabled by default when building in *debug*', 'False'),
BoolVariable('ENABLE_STATS', 'Enable global statistics during map processing', 'False'),
('LOG_FORMAT_STRING', 'The format string used before log output string, piped through strftime (max length of 255 characters)', 'Mapnik LOG> %Y-%m-%d %H:%M:%S:'),
('DEFAULT_LOG_SEVERITY', 'The default severity of the logger (eg. "info", "debug", "warn", "error", "fatal", "none")', 'error'),
# Other variables
BoolVariable('SHAPE_MEMORY_MAPPED_FILE', 'Utilize memory-mapped files in Shapefile Plugin (higher memory usage, better performance)', 'True'),
@ -1417,7 +1417,20 @@ if not preconfigured:
ndebug_flags = '-DNDEBUG'
# Enable logging in debug mode (always) and release mode (when specified)
log_enabled = ' -DMAPNIK_LOG -DMAPNIK_LOG_FORMAT="%s"' % env['LOG_FORMAT_STRING']
if env['DEFAULT_LOG_SEVERITY']:
severities = ['info', 'debug', 'warn', 'error', 'fatal', 'none']
if env['DEFAULT_LOG_SEVERITY'] not in severities:
color_print(1,"Cannot set default logger severity to '%s', available options are 'info', 'debug', 'warn', 'error', 'fatal', 'none'." % env['DEFAULT_LOG_SEVERITY'])
Exit(1)
else:
log_severity = severities.index(env['DEFAULT_LOG_SEVERITY'])
else:
if env['DEBUG']:
log_severity = 1 # debug
else:
log_severity = 3 # error
log_enabled = ' -DMAPNIK_LOG -DMAPNIK_DEFAULT_LOG_SEVERITY=%d' % log_severity
if env['DEBUG']:
debug_flags += log_enabled
@ -1432,7 +1445,7 @@ if not preconfigured:
# Add rdynamic to allow using statics between application and plugins
# http://stackoverflow.com/questions/8623657/multiple-instances-of-singleton-across-shared-libraries-on-linux
if env['PLATFORM'] != 'Darwin':
if env['PLATFORM'] != 'Darwin' and env['CXX'] == 'g++':
env.MergeFlags('-rdynamic')
# Customizing the C++ compiler flags depending on:
@ -1719,7 +1732,7 @@ if not HELP_REQUESTED:
# devtools not ready for public
#SConscript('utils/ogrindex/build.py')
#SConscript('utils/svg2png/build.py')
SConscript('utils/svg2png/build.py')
env['LIBS'].remove('boost_program_options%s' % env['BOOST_APPEND'])
else :
color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' won't be available")

View File

@ -22,112 +22,48 @@
#include <boost/python.hpp>
#include <mapnik/debug.hpp>
using mapnik::logger::severity;
using mapnik::logger::format;
using mapnik::logger::output;
void set_severity(const severity::type& s)
{
severity::set(s);
}
severity::type get_severity()
{
return severity::get();
}
void set_object_severity(const std::string& object_name, const severity::type& s)
{
severity::set_object(object_name, s);
}
severity::type get_object_severity(const std::string& object_name)
{
return severity::get_object(object_name);
}
#include <mapnik/utils.hpp>
void export_logger()
{
using namespace boost::python;
enum_<mapnik::logger::severity::type>("SeverityType")
.value("Info", severity::info)
.value("Debug", severity::debug)
.value("Warn", severity::warn)
.value("Error", severity::error)
.value("Fatal", severity::fatal)
.value("None", severity::none)
;
/*
using mapnik::logger;
using mapnik::singleton;
using mapnik::CreateStatic;
using namespace boost::python;
class_<singleton<severity,CreateStatic>,boost::noncopyable>("Singleton",no_init)
.def("instance",&singleton<severity,CreateStatic>::instance,
class_<singleton<logger,CreateStatic>,boost::noncopyable>("Singleton",no_init)
.def("instance",&singleton<logger,CreateStatic>::instance,
return_value_policy<reference_existing_object>())
.staticmethod("instance")
;
class_<severity,bases<singleton<severity,CreateStatic> >,
boost::noncopyable>("Severity",no_init)
.def("get",&severity::get)
.def("set",&severity::set)
.def("get_object",&severity::get_object)
.def("set_object",&severity::set_object)
.staticmethod("get")
.staticmethod("set")
.staticmethod("get_object")
.staticmethod("set_object")
class_<logger,bases<singleton<logger,CreateStatic> >,
boost::noncopyable>("logger",no_init)
.def_readonly("Info", logger::info)
.def_readonly("Debug", logger::debug)
.def_readonly("Warn", logger::warn)
.def_readonly("Error", logger::error)
.def_readonly("Fatal", logger::fatal)
.def_readonly("None", logger::none)
.def("get_severity", &logger::get_severity)
.def("set_severity", &logger::set_severity)
.def("get_object_severity", &logger::get_object_severity)
.def("set_object_severity", &logger::set_object_severity)
.def("clear_object_severity", &logger::clear_object_severity)
.def("get_format", &logger::get_format)
.def("set_format", &logger::set_format)
.def("str", &logger::str)
.def("use_file", &logger::use_file)
.def("use_console", &logger::use_console)
.staticmethod("get_severity")
.staticmethod("set_severity")
.staticmethod("get_object_severity")
.staticmethod("set_object_severity")
.staticmethod("clear_object_severity")
.staticmethod("get_format")
.staticmethod("set_format")
.staticmethod("str")
.staticmethod("use_file")
.staticmethod("use_console")
;
*/
def("set_severity", &set_severity,
"\n"
"Set global logger severity.\n"
"\n"
"Usage:\n"
">>> from mapnik import SeverityType, set_severity\n"
">>> set_severity(SeverityType.None)\n"
">>> set_severity(SeverityType.Info)\n"
">>> set_severity(SeverityType.Debug)\n"
">>> set_severity(SeverityType.Warn)\n"
">>> set_severity(SeverityType.Error)\n"
">>> set_severity(SeverityType.Fatal)\n"
);
def("get_severity", &get_severity,
"\n"
"Get global logger severity.\n"
"\n"
"Usage:\n"
">>> from mapnik import get_severity\n"
">>> get_severity()\n"
);
def("set_object_severity", &set_object_severity,
"\n"
"Set logger severity for a single object.\n"
"\n"
"Usage:\n"
">>> from mapnik import SeverityType, set_object_severity\n"
">>> set_object_severity('ogr', SeverityType.None)\n"
">>> set_object_severity('gdal', SeverityType.Info)\n"
">>> set_object_severity('cairo_renderer', SeverityType.Debug)\n"
">>> set_object_severity('agg_renderer', SeverityType.Warn)\n"
">>> set_object_severity('bindings', SeverityType.Error)\n"
);
def("get_object_severity", &get_object_severity,
"\n"
"Get logger severity for a single object.\n"
"\n"
"Usage:\n"
">>> from mapnik import get_object_severity"
">>> get_object_severity('ogr')\n"
);
}

View File

@ -43,122 +43,115 @@
namespace mapnik {
namespace logger {
class MAPNIK_DECL severity :
public singleton<severity,CreateStatic>,
private boost::noncopyable
class MAPNIK_DECL logger :
public singleton<logger,CreateStatic>,
private boost::noncopyable
{
public:
enum severity_type
{
public:
enum type
{
info,
debug,
warn,
error,
fatal,
none
};
info,
debug,
warn,
error,
fatal,
none
};
typedef boost::unordered_map<std::string, type> severity_map;
typedef boost::unordered_map<std::string, severity_type> severity_map;
// globally get security level
static type get()
// global security level
static severity_type get_severity()
{
return severity_level_;
}
static void set_severity(const severity_type& severity_level)
{
#ifdef MAPNIK_THREADSAFE
boost::mutex::scoped_lock lock(severity_mutex_);
#endif
severity_level_ = severity_level;
}
// per object security levels
static severity_type get_object_severity(const std::string& object_name)
{
severity_map::iterator it = object_severity_level_.find(object_name);
if (object_name.empty() || it == object_severity_level_.end())
{
return severity_level_;
}
// globally set security level
static void set(const type& severity_level)
else
{
#ifdef MAPNIK_THREADSAFE
boost::mutex::scoped_lock lock(mutex_);
#endif
severity_level_ = severity_level;
return it->second;
}
}
// per object get security level
static type get_object(const std::string& object_name)
{
severity_map::iterator it = object_severity_level_.find(object_name);
if (object_name.empty() || it == object_severity_level_.end())
{
return severity_level_;
}
else
{
return it->second;
}
}
// per object set security level
static void set_object(const std::string& object_name,
const type& security_level)
{
#ifdef MAPNIK_THREADSAFE
boost::mutex::scoped_lock lock(mutex_);
#endif
if (! object_name.empty())
{
object_severity_level_[object_name] = security_level;
}
}
private:
static type severity_level_;
static severity_map object_severity_level_;
#ifdef MAPNIK_THREADSAFE
static boost::mutex mutex_;
#endif
};
class MAPNIK_DECL format :
public singleton<format,CreateStatic>,
private boost::noncopyable
static void set_object_severity(const std::string& object_name,
const severity_type& security_level)
{
public:
static std::string get()
{
return format_;
}
static void set(const std::string& format)
{
#ifdef MAPNIK_THREADSAFE
boost::mutex::scoped_lock lock(mutex_);
boost::mutex::scoped_lock lock(severity_mutex_);
#endif
format_ = format;
if (! object_name.empty())
{
object_severity_level_[object_name] = security_level;
}
}
static std::string str();
private:
static std::string format_;
#ifdef MAPNIK_THREADSAFE
static boost::mutex mutex_;
#endif
};
class MAPNIK_DECL output :
public singleton<output,CreateStatic>,
private boost::noncopyable
static void clear_object_severity()
{
public:
static void use_file(const std::string& filepath);
static void use_console();
#ifdef MAPNIK_THREADSAFE
boost::mutex::scoped_lock lock(severity_mutex_);
#endif
private:
static std::ofstream file_output_;
static std::string file_name_;
static std::streambuf* saved_buf_;
};
object_severity_level_.clear();
}
// format
static std::string get_format()
{
return format_;
}
static void set_format(const std::string& format)
{
#ifdef MAPNIK_THREADSAFE
boost::mutex::scoped_lock lock(format_mutex_);
#endif
format_ = format;
}
// interpolate the format string for output
static std::string str();
// output
static void use_file(const std::string& filepath);
static void use_console();
private:
static severity_type severity_level_;
static severity_map object_severity_level_;
static bool severity_env_check_;
static std::string format_;
static bool format_env_check_;
static std::ofstream file_output_;
static std::string file_name_;
static std::streambuf* saved_buf_;
#ifdef MAPNIK_THREADSAFE
static boost::mutex severity_mutex_;
static boost::mutex format_mutex_;
#endif
};
namespace detail {
template<class Ch, class Tr, class A>
class clog_sink
@ -166,19 +159,19 @@ namespace mapnik {
public:
typedef std::basic_ostringstream<Ch, Tr, A> stream_buffer;
void operator()(const stream_buffer &s)
void operator()(const logger::severity_type& severity, const stream_buffer &s)
{
#ifdef MAPNIK_THREADSAFE
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
#endif
std::clog << format::str() << " " << s.str() << std::endl;
std::clog << logger::str() << " " << s.str() << std::endl;
}
};
template<template <class Ch, class Tr, class A> class OutputPolicy,
severity::type Severity,
logger::severity_type Severity,
class Ch = char,
class Tr = std::char_traits<Ch>,
class A = std::allocator<Ch> >
@ -204,7 +197,7 @@ namespace mapnik {
#ifdef MAPNIK_LOG
if (check_severity())
{
output_policy()(streambuf_);
output_policy()(Severity, streambuf_);
}
#endif
}
@ -222,7 +215,7 @@ namespace mapnik {
#ifdef MAPNIK_LOG
inline bool check_severity()
{
return Severity >= severity::get_object(object_name_);
return Severity >= logger::get_object_severity(object_name_);
}
typename output_policy::stream_buffer streambuf_;
@ -230,45 +223,46 @@ namespace mapnik {
#endif
};
typedef base_log<clog_sink, severity::info> base_log_info;
typedef base_log<clog_sink, severity::debug> base_log_debug;
typedef base_log<clog_sink, severity::warn> base_log_warn;
typedef base_log<clog_sink, severity::error> base_log_error;
typedef base_log<clog_sink, severity::fatal> base_log_fatal;
}
typedef base_log<clog_sink, logger::info> base_log_info;
typedef base_log<clog_sink, logger::debug> base_log_debug;
typedef base_log<clog_sink, logger::warn> base_log_warn;
typedef base_log<clog_sink, logger::error> base_log_error;
typedef base_log<clog_sink, logger::fatal> base_log_fatal;
} // namespace detail
class MAPNIK_DECL info : public logger::base_log_info {
// real interfaces
class MAPNIK_DECL info : public detail::base_log_info {
public:
info() : logger::base_log_info() {}
info(const char* object_name) : logger::base_log_info(object_name) {}
info() : detail::base_log_info() {}
info(const char* object_name) : detail::base_log_info(object_name) {}
};
class MAPNIK_DECL debug : public logger::base_log_debug {
class MAPNIK_DECL debug : public detail::base_log_debug {
public:
debug() : logger::base_log_debug() {}
debug(const char* object_name) : logger::base_log_debug(object_name) {}
debug() : detail::base_log_debug() {}
debug(const char* object_name) : detail::base_log_debug(object_name) {}
};
class MAPNIK_DECL warn : public logger::base_log_warn {
class MAPNIK_DECL warn : public detail::base_log_warn {
public:
warn() : logger::base_log_warn() {}
warn(const char* object_name) : logger::base_log_warn(object_name) {}
warn() : detail::base_log_warn() {}
warn(const char* object_name) : detail::base_log_warn(object_name) {}
};
class MAPNIK_DECL error : public logger::base_log_error {
class MAPNIK_DECL error : public detail::base_log_error {
public:
error() : logger::base_log_error() {}
error(const char* object_name) : logger::base_log_error(object_name) {}
error() : detail::base_log_error() {}
error(const char* object_name) : detail::base_log_error(object_name) {}
};
class MAPNIK_DECL fatal : public logger::base_log_fatal {
class MAPNIK_DECL fatal : public detail::base_log_fatal {
public:
fatal() : logger::base_log_fatal() {}
fatal(const char* object_name) : logger::base_log_fatal(object_name) {}
fatal() : detail::base_log_fatal() {}
fatal(const char* object_name) : detail::base_log_fatal(object_name) {}
};
// logging helpers
#define MAPNIK_LOG_INFO(s) mapnik::info(#s)
#define MAPNIK_LOG_DEBUG(s) mapnik::debug(#s)
#define MAPNIK_LOG_WARN(s) mapnik::warn(#s)

View File

@ -56,11 +56,10 @@ public:
void begin_path()
{
push_attr();
unsigned idx = source_.start_new_path();
attributes_.add(path_attributes(cur_attr(), idx));
}
void end_path()
{
if(attributes_.size() == 0)
@ -71,7 +70,6 @@ public:
unsigned idx = attributes_[attributes_.size() - 1].index;
attr.index = idx;
attributes_[attributes_.size() - 1] = attr;
pop_attr();
}
void move_to(double x, double y, bool rel=false) // M, m
@ -235,7 +233,21 @@ public:
cur_attr().visibility_flag = flag;
}
bool visibility()
{
return cur_attr().visibility_flag;
}
void display(bool flag)
{
cur_attr().display_flag = flag;
}
bool display()
{
return cur_attr().display_flag;
}
void stroke_width(double w)
{
cur_attr().stroke_width = w;

View File

@ -45,6 +45,7 @@ struct path_attributes
bool stroke_flag;
bool even_odd_flag;
bool visibility_flag;
bool display_flag;
agg::line_join_e line_join;
agg::line_cap_e line_cap;
double miter_limit;
@ -63,6 +64,7 @@ struct path_attributes
stroke_flag(false),
even_odd_flag(false),
visibility_flag(true),
display_flag(true),
line_join(agg::miter_join),
line_cap(agg::butt_cap),
miter_limit(4.0),
@ -83,6 +85,7 @@ struct path_attributes
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
visibility_flag(attr.visibility_flag),
display_flag(attr.display_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),
@ -102,6 +105,7 @@ struct path_attributes
stroke_flag(attr.stroke_flag),
even_odd_flag(attr.even_odd_flag),
visibility_flag(attr.visibility_flag),
display_flag(attr.display_flag),
line_join(attr.line_join),
line_cap(attr.line_cap),
miter_limit(attr.miter_limit),

View File

@ -65,24 +65,28 @@ DATASOURCE_PLUGIN(geos_datasource)
void geos_notice(const char* format, ...)
{
#ifdef MAPNIK_LOG
char buffer[512];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
vsnprintf(buffer, 512, format, args);
va_end(args);
MAPNIK_LOG_WARN(geos) << "geos_datasource: " << buffer;
#endif
}
void geos_error(const char* format, ...)
{
#ifdef MAPNIK_LOG
char buffer[512];
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
vsnprintf(buffer, 512, format, args);
va_end(args);
MAPNIK_LOG_ERROR(geos) << "geos_datasource: " << buffer;
#endif
}

View File

@ -157,7 +157,7 @@ void occi_datasource::bind() const
*params_.get<std::string>("user"),
*params_.get<std::string>("password"),
*params_.get<std::string>("host"),
*params_.get<int>("max_size", 10),
*params_.get<int>("max_size", 5),
*params_.get<int>("initial_size", 1),
1,
StatelessConnectionPool::HOMOGENEOUS);

View File

@ -30,54 +30,91 @@
#define MAPNIK_LOG_FORMAT "Mapnik LOG> %Y-%m-%d %H:%M:%S:"
#endif
namespace mapnik { namespace logger {
#ifndef MAPNIK_DEFAULT_LOG_SEVERITY
#ifdef MAPNIK_DEBUG
#define MAPNIK_DEFAULT_LOG_SEVERITY 1
#else
#define MAPNIK_DEFAULT_LOG_SEVERITY 3
#endif
#endif
namespace mapnik {
// mutexes
#ifdef MAPNIK_THREADSAFE
boost::mutex logger::severity_mutex_;
boost::mutex logger::format_mutex_;
#endif
// first time checks
bool logger::severity_env_check_ = true;
bool logger::format_env_check_ = true;
// severity
severity::type severity::severity_level_ =
#ifdef MAPNIK_DEBUG
severity::debug
#else
severity::error
#endif
logger::severity_type logger::severity_level_ =
#if MAPNIK_DEFAULT_LOG_SEVERITY == 0
logger::info
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 1
logger::debug
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 2
logger::warn
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 3
logger::error
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 4
logger::fatal
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 5
logger::none
#else
#error "Wrong default log severity level specified!"
#endif
;
severity::severity_map severity::object_severity_level_ = severity::severity_map();
#ifdef MAPNIK_THREADSAFE
boost::mutex severity::mutex_;
#endif
logger::severity_map logger::object_severity_level_ = logger::severity_map();
// format
#define __xstr__(s) __str__(s)
#define __str__(s) #s
std::string format::format_ = __xstr__(MAPNIK_LOG_FORMAT);
std::string logger::format_ = __xstr__(MAPNIK_LOG_FORMAT);
#undef __xstr__
#undef __str__
#ifdef MAPNIK_THREADSAFE
boost::mutex format::mutex_;
std::string logger::str()
{
#if 0
// update the format from getenv if this is the first time
if (logger::format_env_check_)
{
logger::format_env_check_ = false;
const char* log_format = getenv("MAPNIK_LOG_FORMAT");
if (log_format != NULL)
{
logger::format_ = log_format;
}
}
#endif
std::string format::str()
{
char buf[256];
const time_t tm = time(0);
strftime(buf, sizeof(buf), format::format_.c_str(), localtime(&tm));
strftime(buf, sizeof(buf), logger::format_.c_str(), localtime(&tm));
return buf;
}
// output
std::ofstream output::file_output_;
std::string output::file_name_;
std::streambuf* output::saved_buf_ = 0;
std::ofstream logger::file_output_;
std::string logger::file_name_;
std::streambuf* logger::saved_buf_ = 0;
void output::use_file(const std::string& filepath)
void logger::use_file(const std::string& filepath)
{
// save clog rdbuf
if (saved_buf_ == 0)
@ -109,7 +146,7 @@ void output::use_file(const std::string& filepath)
}
}
void output::use_console()
void logger::use_console()
{
// save clog rdbuf
if (saved_buf_ == 0)
@ -117,9 +154,14 @@ void output::use_console()
saved_buf_ = std::clog.rdbuf();
}
// close the file to force a flush
if (file_output_.is_open())
{
file_output_.close();
}
std::clog.rdbuf(saved_buf_);
}
}
}
} // namespace mapnik

View File

@ -190,22 +190,43 @@ void png_reader::read(unsigned x0, unsigned y0,image_data_32& image)
if (png_get_gAMA(png_ptr, info_ptr, &gamma))
png_set_gamma(png_ptr, 2.2, gamma);
png_read_update_info(png_ptr, info_ptr);
//START read image rows
unsigned w=std::min(unsigned(image.width()),width_);
unsigned h=std::min(unsigned(image.height()),height_);
unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
boost::scoped_array<png_byte> row(new png_byte[rowbytes]);
for (unsigned i=0;i<height_;++i)
if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_)
{
png_read_row(png_ptr,row.get(),0);
if (i>=y0 && i<h)
if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7)
{
image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w);
png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
// according to docs png_read_image
// "..automatically handles interlacing,
// so you don't need to call png_set_interlace_handling()"
}
png_read_update_info(png_ptr, info_ptr);
// we can read whole image at once
// alloc row pointers
boost::scoped_array<png_byte*> rows(new png_bytep[height_]);
for (unsigned i=0; i<height_; ++i)
rows[i] = (png_bytep)image.getRow(i);
png_read_image(png_ptr, rows.get());
}
//END
else
{
png_read_update_info(png_ptr, info_ptr);
unsigned w=std::min(unsigned(image.width()),width_);
unsigned h=std::min(unsigned(image.height()),height_);
unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
boost::scoped_array<png_byte> row(new png_byte[rowbytes]);
//START read image rows
for (unsigned i=0;i<height_;++i)
{
png_read_row(png_ptr,row.get(),0);
if (i>=y0 && i<h)
{
image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w);
}
}
//END
}
png_read_end(png_ptr,0);
png_destroy_read_struct(&png_ptr, &info_ptr,0);
fclose(fp);

View File

@ -46,29 +46,29 @@
namespace mapnik { namespace svg {
typedef std::vector<std::pair<double, agg::rgba8> > color_lookup_type;
typedef std::vector<std::pair<double, agg::rgba8> > color_lookup_type;
namespace qi = boost::spirit::qi;
namespace qi = boost::spirit::qi;
typedef std::vector<std::pair<std::string, std::string> > pairs_type;
typedef std::vector<std::pair<std::string, std::string> > pairs_type;
template <typename Iterator,typename SkipType>
struct key_value_sequence_ordered
: qi::grammar<Iterator, pairs_type(), SkipType>
template <typename Iterator,typename SkipType>
struct key_value_sequence_ordered
: qi::grammar<Iterator, pairs_type(), SkipType>
{
key_value_sequence_ordered()
: key_value_sequence_ordered::base_type(query)
{
key_value_sequence_ordered()
: key_value_sequence_ordered::base_type(query)
{
query = pair >> *( qi::lit(';') >> pair);
pair = key >> -(':' >> value);
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9-");
value = +(qi::char_ - qi::lit(';'));
}
query = pair >> *( qi::lit(';') >> pair);
pair = key >> -(':' >> value);
key = qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9-");
value = +(qi::char_ - qi::lit(';'));
}
qi::rule<Iterator, pairs_type(), SkipType> query;
qi::rule<Iterator, std::pair<std::string, std::string>(), SkipType> pair;
qi::rule<Iterator, std::string(), SkipType> key, value;
};
qi::rule<Iterator, pairs_type(), SkipType> query;
qi::rule<Iterator, std::pair<std::string, std::string>(), SkipType> pair;
qi::rule<Iterator, std::string(), SkipType> key, value;
};
agg::rgba8 parse_color(const char* str)
{
@ -175,44 +175,11 @@ void svg_parser::start_element(xmlTextReaderPtr reader)
const xmlChar *name;
name = xmlTextReaderConstName(reader);
if (!is_defs_ && xmlStrEqual(name, BAD_CAST "g"))
{
path_.push_attr();
parse_attr(reader);
}
else if (xmlStrEqual(name, BAD_CAST "defs"))
if (xmlStrEqual(name, BAD_CAST "defs"))
{
if (xmlTextReaderIsEmptyElement(reader) == 0)
is_defs_ = true;
}
else if ( !is_defs_ && xmlStrEqual(name, BAD_CAST "path"))
{
parse_path(reader);
}
else if (!is_defs_ && xmlStrEqual(name, BAD_CAST "polygon") )
{
parse_polygon(reader);
}
else if (!is_defs_ && xmlStrEqual(name, BAD_CAST "polyline"))
{
parse_polyline(reader);
}
else if (!is_defs_ && xmlStrEqual(name, BAD_CAST "line"))
{
parse_line(reader);
}
else if (!is_defs_ && xmlStrEqual(name, BAD_CAST "rect"))
{
parse_rect(reader);
}
else if (!is_defs_ && xmlStrEqual(name, BAD_CAST "circle"))
{
parse_circle(reader);
}
else if (!is_defs_ && xmlStrEqual(name, BAD_CAST "ellipse"))
{
parse_ellipse(reader);
}
// the gradient tags *should* be in defs, but illustrator seems not to put them in there so
// accept them anywhere
else if (xmlStrEqual(name, BAD_CAST "linearGradient"))
@ -227,18 +194,65 @@ void svg_parser::start_element(xmlTextReaderPtr reader)
{
parse_gradient_stop(reader);
}
#ifdef MAPNIK_LOG
else if (!xmlStrEqual(name, BAD_CAST "svg"))
if ( !is_defs_ )
{
MAPNIK_LOG_WARN(svg_parser) << "svg_parser: Unhandled svg element=" << name;
}
if (xmlStrEqual(name, BAD_CAST "g"))
{
path_.push_attr();
parse_attr(reader);
}
else
{
path_.push_attr();
parse_attr(reader);
if (path_.display())
{
if (xmlStrEqual(name, BAD_CAST "path"))
{
parse_path(reader);
}
else if (xmlStrEqual(name, BAD_CAST "polygon") )
{
parse_polygon(reader);
}
else if (xmlStrEqual(name, BAD_CAST "polyline"))
{
parse_polyline(reader);
}
else if (xmlStrEqual(name, BAD_CAST "line"))
{
parse_line(reader);
}
else if (xmlStrEqual(name, BAD_CAST "rect"))
{
parse_rect(reader);
}
else if (xmlStrEqual(name, BAD_CAST "circle"))
{
parse_circle(reader);
}
else if (xmlStrEqual(name, BAD_CAST "ellipse"))
{
parse_ellipse(reader);
}
#ifdef MAPNIK_LOG
else if (!xmlStrEqual(name, BAD_CAST "svg"))
{
MAPNIK_LOG_WARN(svg_parser) << "svg_parser: Unhandled svg element=" << name;
}
#endif
}
path_.pop_attr();
}
}
}
void svg_parser::end_element(xmlTextReaderPtr reader)
{
const xmlChar *name;
name = xmlTextReaderConstName(reader);
if (!is_defs_ && xmlStrEqual(name, BAD_CAST "g"))
{
path_.pop_attr();
@ -251,6 +265,7 @@ void svg_parser::end_element(xmlTextReaderPtr reader)
{
gradient_map_[temporary_gradient_.first] = temporary_gradient_.second;
}
}
void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
@ -370,7 +385,7 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
}
else if (xmlStrEqual(name, BAD_CAST "display") && xmlStrEqual(value, BAD_CAST "none"))
{
path_.visibility(false);
path_.display(false);
}
}
@ -378,100 +393,127 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value )
void svg_parser::parse_attr(xmlTextReaderPtr reader)
{
const xmlChar *name, *value;
while (xmlTextReaderMoveToNextAttribute(reader))
if (xmlTextReaderMoveToFirstAttribute(reader) == 1)
{
name = xmlTextReaderConstName(reader);
value = xmlTextReaderConstValue(reader);
if (xmlStrEqual(name, BAD_CAST "style"))
do
{
typedef std::vector<std::pair<std::string,std::string> > cont_type;
typedef cont_type::value_type value_type;
cont_type vec;
parse_style((const char*)value, vec);
BOOST_FOREACH(value_type kv , vec )
name = xmlTextReaderConstName(reader);
value = xmlTextReaderConstValue(reader);
if (xmlStrEqual(name, BAD_CAST "style"))
{
parse_attr(BAD_CAST kv.first.c_str(),BAD_CAST kv.second.c_str());
typedef std::vector<std::pair<std::string,std::string> > cont_type;
typedef cont_type::value_type value_type;
cont_type vec;
parse_style((const char*)value, vec);
BOOST_FOREACH(value_type kv , vec )
{
parse_attr(BAD_CAST kv.first.c_str(),BAD_CAST kv.second.c_str());
}
}
}
else
{
parse_attr(name,value);
}
else
{
parse_attr(name,value);
}
} while(xmlTextReaderMoveToNextAttribute(reader) == 1);
}
xmlTextReaderMoveToElement(reader);
}
void svg_parser::parse_path(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "d");
if (value)
{
path_.begin_path();
parse_attr(reader);
if (!mapnik::svg::parse_path((const char*) value, path_))
{
std::runtime_error("can't parse PATH\n");
xmlFree(value);
throw std::runtime_error("can't parse PATH\n");
}
path_.end_path();
xmlFree(value);
}
}
void svg_parser::parse_polygon(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "points");
if (value)
{
path_.begin_path();
parse_attr(reader);
if (!mapnik::svg::parse_points((const char*) value, path_))
{
xmlFree(value);
throw std::runtime_error("Failed to parse <polygon>\n");
}
path_.close_subpath();
path_.end_path();
xmlFree(value);
}
}
void svg_parser::parse_polyline(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "points");
if (value)
{
path_.begin_path();
parse_attr(reader);
if (!mapnik::svg::parse_points((const char*) value, path_))
{
xmlFree(value);
throw std::runtime_error("Failed to parse <polygon>\n");
}
path_.end_path();
xmlFree(value);
}
}
void svg_parser::parse_line(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
double x1 = 0.0;
double y1 = 0.0;
double x2 = 0.0;
double y2 = 0.0;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "x1");
if (value) x1 = parse_double((const char*)value);
if (value)
{
x1 = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "y1");
if (value) y1 = parse_double((const char*)value);
if (value)
{
y1 = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "x2");
if (value) x2 = parse_double((const char*)value);
if (value)
{
x2 = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "y2");
if (value) y2 = parse_double((const char*)value);
if (value)
{
y2 = parse_double((const char*)value);
xmlFree(value);
}
path_.begin_path();
parse_attr(reader);
path_.move_to(x1, y1);
path_.line_to(x2, y2);
path_.end_path();
@ -480,19 +522,32 @@ void svg_parser::parse_line(xmlTextReaderPtr reader)
void svg_parser::parse_circle(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
double cx = 0.0;
double cy = 0.0;
double r = 0.0;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cx");
if (value) cx = parse_double((const char*)value);
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cy");
if (value) cy = parse_double((const char*)value);
value = xmlTextReaderGetAttribute(reader, BAD_CAST "r");
if (value) r = parse_double((const char*)value);
if (value)
{
cx = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cy");
if (value)
{
cy = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "r");
if (value)
{
r = parse_double((const char*)value);
xmlFree(value);
}
path_.begin_path();
parse_attr(reader);
if(r != 0.0)
{
@ -506,23 +561,41 @@ void svg_parser::parse_circle(xmlTextReaderPtr reader)
void svg_parser::parse_ellipse(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
double cx = 0.0;
double cy = 0.0;
double rx = 0.0;
double ry = 0.0;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cx");
if (value) cx = parse_double((const char*)value);
if (value)
{
cx = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cy");
if (value) cy = parse_double((const char*)value);
if (value)
{
cy = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "rx");
if (value) rx = parse_double((const char*)value);
if (value)
{
rx = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "ry");
if (value) ry = parse_double((const char*)value);
if (value)
{
ry = parse_double((const char*)value);
xmlFree(value);
}
path_.begin_path();
parse_attr(reader);
if(rx != 0.0 && ry != 0.0)
{
@ -533,11 +606,12 @@ void svg_parser::parse_ellipse(xmlTextReaderPtr reader)
}
path_.end_path();
}
void svg_parser::parse_rect(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
double x = 0.0;
double y = 0.0;
double w = 0.0;
@ -546,18 +620,39 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader)
double ry = 0.0;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "x");
if (value) x = parse_double((const char*)value);
if (value)
{
x = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "y");
if (value) y = parse_double((const char*)value);
if (value)
{
y = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "width");
if (value) w = parse_double((const char*)value);
if (value)
{
w = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "height");
if (value) h = parse_double((const char*)value);
if (value)
{
h = parse_double((const char*)value);
xmlFree(value);
}
bool rounded = true;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "rx");
if (value) rx = parse_double((const char*)value);
if (value)
{
rx = parse_double((const char*)value);
xmlFree(value);
}
else rounded = false;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "ry");
@ -569,6 +664,7 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader)
rx = ry;
rounded = true;
}
xmlFree(value);
}
else if (rounded)
{
@ -581,22 +677,10 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader)
if(h < 0.0) throw std::runtime_error("parse_rect: Invalid height");
if(rx < 0.0) throw std::runtime_error("parse_rect: Invalid rx");
if(ry < 0.0) throw std::runtime_error("parse_rect: Invalid ry");
path_.begin_path();
parse_attr(reader);
if(rounded)
{
//path_.move_to(x + rx,y);
//path_.line_to(x + w - rx,y);
//path_.arc_to (rx,ry,0,0,1,x + w, y + ry);
//path_.line_to(x + w, y + h - ry);
//path_.arc_to (rx,ry,0,0,1,x + w - rx, y + h);
//path_.line_to(x + rx, y + h);
//path_.arc_to(rx,ry,0,0,1,x,y + h - ry);
//path_.line_to(x,y+ry);
//path_.arc_to(rx,ry,0,0,1,x + rx,y);
//path_.close_subpath();
agg::rounded_rect r;
r.rect(x,y,x+w,y+h);
r.radius(rx,ry);
@ -623,14 +707,18 @@ void svg_parser::parse_rect(xmlTextReaderPtr reader)
*/
void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
double offset = 0.0;
mapnik::color stop_color;
double opacity = 1.0;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "offset");
if (value) offset = parse_double((const char*)value);
if (value)
{
offset = parse_double((const char*)value);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "style");
if (value)
@ -658,6 +746,7 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
opacity = parse_double(kv.second.c_str());
}
}
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "stop-color");
@ -671,12 +760,14 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
{
MAPNIK_LOG_ERROR(svg_parser) << ex.what();
}
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "stop-opacity");
if (value)
{
opacity = parse_double((const char *) value);
xmlFree(value);
}
@ -695,7 +786,7 @@ void svg_parser::parse_gradient_stop(xmlTextReaderPtr reader)
bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
{
const xmlChar *value;
xmlChar *value;
std::string id;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
@ -705,6 +796,7 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
gradient new_grad;
id = std::string((const char *) value);
temporary_gradient_ = std::make_pair(id, new_grad);
xmlFree(value);
}
else
{
@ -714,36 +806,44 @@ bool svg_parser::parse_common_gradient(xmlTextReaderPtr reader)
// check if we should inherit from another tag
value = xmlTextReaderGetAttribute(reader, BAD_CAST "xlink:href");
if (value && value[0] == '#')
if (value)
{
std::string linkid = (const char *) &value[1];
if (gradient_map_.count(linkid))
if (value[0] == '#')
{
//MAPNIK_LOG_DEBUG(svg_parser) << "\tLoading linked gradient properties from " << linkid;
temporary_gradient_.second = gradient_map_[linkid];
std::string linkid = (const char *) &value[1];
if (gradient_map_.count(linkid))
{
temporary_gradient_.second = gradient_map_[linkid];
}
else
{
MAPNIK_LOG_ERROR(svg_parser) << "Failed to find linked gradient " << linkid;
}
}
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "gradientUnits");
if (value)
{
if (xmlStrEqual(value, BAD_CAST "userSpaceOnUse"))
{
temporary_gradient_.second.set_units(USER_SPACE_ON_USE);
}
else
{
MAPNIK_LOG_ERROR(svg_parser) << "Failed to find linked gradient " << linkid;
temporary_gradient_.second.set_units(OBJECT_BOUNDING_BOX);
}
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "gradientUnits");
if (value && std::string((const char*) value) == "userSpaceOnUse")
{
temporary_gradient_.second.set_units(USER_SPACE_ON_USE);
}
else
{
temporary_gradient_.second.set_units(OBJECT_BOUNDING_BOX);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "gradientTransform");
if (value)
{
agg::trans_affine tr;
mapnik::svg::parse_transform((const char*) value,tr);
temporary_gradient_.second.set_transform(tr);
xmlFree(value);
}
return true;
@ -766,7 +866,7 @@ void svg_parser::parse_radial_gradient(xmlTextReaderPtr reader)
if (!parse_common_gradient(reader))
return;
const xmlChar *value;
xmlChar *value;
double cx = 0.5;
double cy = 0.5;
double fx = 0.0;
@ -775,26 +875,43 @@ void svg_parser::parse_radial_gradient(xmlTextReaderPtr reader)
bool has_percent=true;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cx");
if (value) cx = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
cx = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "cy");
if (value) cy = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
cy = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "fx");
if (value)
{
fx = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
else
fx = cx;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "fy");
if (value)
{
fy = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
else
fy = cy;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "r");
if (value) r = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
r = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
// this logic for detecting %'s will not support mixed coordinates.
if (has_percent && temporary_gradient_.second.get_units() == USER_SPACE_ON_USE)
{
@ -814,7 +931,7 @@ void svg_parser::parse_linear_gradient(xmlTextReaderPtr reader)
if (!parse_common_gradient(reader))
return;
const xmlChar *value;
xmlChar *value;
double x1 = 0.0;
double x2 = 1.0;
double y1 = 0.0;
@ -822,17 +939,32 @@ void svg_parser::parse_linear_gradient(xmlTextReaderPtr reader)
bool has_percent=true;
value = xmlTextReaderGetAttribute(reader, BAD_CAST "x1");
if (value) x1 = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
x1 = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "x2");
if (value) x2 = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
x2 = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "y1");
if (value) y1 = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
y1 = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
value = xmlTextReaderGetAttribute(reader, BAD_CAST "y2");
if (value) y2 = parse_double_optional_percent((const char*)value, has_percent);
if (value)
{
y2 = parse_double_optional_percent((const char*)value, has_percent);
xmlFree(value);
}
// this logic for detecting %'s will not support mixed coordinates.
if (has_percent && temporary_gradient_.second.get_units() == USER_SPACE_ON_USE)
{

View File

@ -316,7 +316,8 @@ SOURCES += \
OTHER_FILES += \
../SConstruct \
../config.py
../config.py \
../CHANGELOG.md
include(agg.pri)
include(plugins.pri)