diff --git a/SConstruct b/SConstruct index 34c7c241b..2b1d2e3ec 100644 --- a/SConstruct +++ b/SConstruct @@ -275,6 +275,7 @@ opts.AddVariables( ('WARNING_CXXFLAGS', 'Compiler flags you can set to reduce warning levels which are placed after -Wall.', ''), # SCons build behavior options + ('HOST', 'Set the target host for cross compiling"', ''), ('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG), BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'), # http://www.scons.org/wiki/GoFastButton @@ -354,7 +355,7 @@ PathVariable.PathAccept), # 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'), - ('DEFAULT_LOG_SEVERITY', 'The default severity of the logger (eg. ' + ', '.join(severities), 'error'), + ('DEFAULT_LOG_SEVERITY', 'The default severity of the logger (eg. ' + ', '.join(severities) + ')', 'error'), # Other variables BoolVariable('SHAPE_MEMORY_MAPPED_FILE', 'Utilize memory-mapped files in Shapefile Plugin (higher memory usage, better performance)', 'True'), @@ -1192,19 +1193,21 @@ if not preconfigured: if env['PRIORITIZE_LINKING']: conf.prioritize_paths(silent=False) - for libname, headers, required, lang in LIBSHEADERS: - if not conf.CheckLibWithHeader(libname, headers, lang): - if required: - color_print(1, 'Could not find required header or shared library for %s' % libname) - env['MISSING_DEPS'].append(libname) - else: - color_print(4, 'Could not find optional header or shared library for %s' % libname) - env['SKIPPED_DEPS'].append(libname) + if not env['HOST']: + for libname, headers, required, lang in LIBSHEADERS: + if not conf.CheckLibWithHeader(libname, headers, lang): + if required: + color_print(1, 'Could not find required header or shared library for %s' % libname) + env['MISSING_DEPS'].append(libname) + else: + color_print(4, 'Could not find optional header or shared library for %s' % libname) + env['SKIPPED_DEPS'].append(libname) - if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: - if not conf.icu_at_least_four_two(): - # expression_string.cpp and map.cpp use fromUTF* function only available in >= ICU 4.2 - env['MISSING_DEPS'].append(env['ICU_LIB_NAME']) + if not env['HOST']: + if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: + if not conf.icu_at_least_four_two(): + # expression_string.cpp and map.cpp use fromUTF* function only available in >= ICU 4.2 + env['MISSING_DEPS'].append(env['ICU_LIB_NAME']) if env['BIGINT']: env.Append(CPPDEFINES = '-DBIGINT') @@ -1239,24 +1242,26 @@ if not preconfigured: if env['PRIORITIZE_LINKING']: conf.prioritize_paths() - # if the user is not setting custom boost configuration - # enforce boost version greater than or equal to BOOST_MIN_VERSION - if not conf.CheckBoost(BOOST_MIN_VERSION): - color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') ) - color_print(1,'Boost version %s or greater is required' % BOOST_MIN_VERSION) - if not env['BOOST_VERSION']: - env['MISSING_DEPS'].append('boost version >=%s' % BOOST_MIN_VERSION) - else: - color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') ) + if not env['HOST']: + # if the user is not setting custom boost configuration + # enforce boost version greater than or equal to BOOST_MIN_VERSION + if not conf.CheckBoost(BOOST_MIN_VERSION): + color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') ) + color_print(1,'Boost version %s or greater is required' % BOOST_MIN_VERSION) + if not env['BOOST_VERSION']: + env['MISSING_DEPS'].append('boost version >=%s' % BOOST_MIN_VERSION) + else: + color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') ) - for count, libinfo in enumerate(BOOST_LIBSHEADERS): - if not conf.CheckLibWithHeader('boost_%s%s' % (libinfo[0],env['BOOST_APPEND']), libinfo[1], 'C++'): - if libinfo[2]: - color_print(1,'Could not find required header or shared library for boost %s' % libinfo[0]) - env['MISSING_DEPS'].append('boost ' + libinfo[0]) - else: - color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0]) - env['SKIPPED_DEPS'].append('boost ' + libinfo[0]) + if not env['HOST']: + for count, libinfo in enumerate(BOOST_LIBSHEADERS): + if not conf.CheckLibWithHeader('boost_%s%s' % (libinfo[0],env['BOOST_APPEND']), libinfo[1], 'C++'): + if libinfo[2]: + color_print(1,'Could not find required header or shared library for boost %s' % libinfo[0]) + env['MISSING_DEPS'].append('boost ' + libinfo[0]) + else: + color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0]) + env['SKIPPED_DEPS'].append('boost ' + libinfo[0]) if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: # http://lists.boost.org/Archives/boost/2009/03/150076.php @@ -1484,9 +1489,10 @@ if not preconfigured: env['BOOST_PYTHON_LIB'] = 'boost_python3%s' % env['BOOST_APPEND'] elif env['BOOST_PYTHON_LIB'] == 'boost_python': env['BOOST_PYTHON_LIB'] = 'boost_python%s' % env['BOOST_APPEND'] - if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'): - color_print(1,'Could not find required header files for boost python') - env['MISSING_DEPS'].append('boost python') + if not env['HOST']: + if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'): + color_print(1,'Could not find required header files for boost python') + env['MISSING_DEPS'].append('boost python') if env['CAIRO']: if conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'): @@ -1558,9 +1564,9 @@ if not preconfigured: # Common debugging flags. # http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.html - debug_flags = '-g -fno-omit-frame-pointer' - debug_defines = '-DDEBUG -DMAPNIK_DEBUG' - ndebug_defines = '-DNDEBUG' + debug_flags = ['-g', '-fno-omit-frame-pointer'] + debug_defines = ['-DDEBUG', '-DMAPNIK_DEBUG'] + ndebug_defines = ['-DNDEBUG'] # Enable logging in debug mode (always) and release mode (when specified) if env['DEFAULT_LOG_SEVERITY']: @@ -1575,7 +1581,7 @@ if not preconfigured: color_print(1,"No logger severity specified, available options are %s." % severities_list) Exit(1) - log_enabled = ' -DMAPNIK_LOG -DMAPNIK_DEFAULT_LOG_SEVERITY=%d' % log_severity + log_enabled = ['-DMAPNIK_LOG', '-DMAPNIK_DEFAULT_LOG_SEVERITY=%d' % log_severity] if env['DEBUG']: debug_defines += log_enabled @@ -1585,8 +1591,8 @@ if not preconfigured: # Enable statistics reporting if env['ENABLE_STATS']: - debug_defines += ' -DMAPNIK_STATS' - ndebug_defines += ' -DMAPNIK_STATS' + debug_defines.append('-DMAPNIK_STATS') + ndebug_defines.append('-DMAPNIK_STATS') # Add rdynamic to allow using statics between application and plugins # http://stackoverflow.com/questions/8623657/multiple-instances-of-singleton-across-shared-libraries-on-linux diff --git a/include/mapnik/projection.hpp b/include/mapnik/projection.hpp index e7c846bee..238280a7b 100644 --- a/include/mapnik/projection.hpp +++ b/include/mapnik/projection.hpp @@ -76,6 +76,15 @@ private: mutable void * proj_ctx_; }; +template +std::basic_ostream & +operator << ( std::basic_ostream & s, mapnik::projection const& p ) +{ + s << "projection(\"" << p.params() << "\")"; + return s; +} + + } #endif // MAPNIK_PROJECTION_HPP diff --git a/plugins/input/sqlite/sqlite_prepared.hpp b/plugins/input/sqlite/sqlite_prepared.hpp index 477759f5d..f10ad7288 100644 --- a/plugins/input/sqlite/sqlite_prepared.hpp +++ b/plugins/input/sqlite/sqlite_prepared.hpp @@ -24,6 +24,7 @@ #define MAPNIK_SQLITE_PREPARED_HPP // mapnik +#include #include #include #include @@ -77,11 +78,13 @@ public: { if (*(*ds_)) { - std::cerr << "ERR:" << sqlite3_errmsg(*(*ds_)) << "\n"; + MAPNIK_LOG_ERROR(sqlite) << "~prepared_index_statement:" + << sqlite3_errmsg(*(*ds_)); } else { - std::cerr << "SQLite Plugin: " << res << "\n"; + MAPNIK_LOG_ERROR(sqlite) << "~prepared_index_statement:" + << res; } } } diff --git a/plugins/input/sqlite/sqlite_resultset.hpp b/plugins/input/sqlite/sqlite_resultset.hpp index 9c10eb0f3..909a4dac4 100644 --- a/plugins/input/sqlite/sqlite_resultset.hpp +++ b/plugins/input/sqlite/sqlite_resultset.hpp @@ -24,6 +24,7 @@ #define MAPNIK_SQLITE_RESULTSET_HPP // mapnik +#include #include #include diff --git a/plugins/input/sqlite/sqlite_utils.hpp b/plugins/input/sqlite/sqlite_utils.hpp index 6caee666c..90f0446a1 100644 --- a/plugins/input/sqlite/sqlite_utils.hpp +++ b/plugins/input/sqlite/sqlite_utils.hpp @@ -29,6 +29,7 @@ #include // mapnik +#include #include #include #include @@ -556,7 +557,7 @@ public: } catch (std::exception const& ex) { - //std::clog << "no: " << ex.what() << "\n"; + MAPNIK_LOG_DEBUG(sqlite) << "has_rtree returned:" << ex.what(); return false; } return false; @@ -609,9 +610,7 @@ public: break; default: -#ifdef MAPNIK_DEBUG - std::clog << "Sqlite Plugin: unknown type_oid=" << type_oid << std::endl; -#endif + MAPNIK_LOG_DEBUG(sqlite) << "detect_types_from_subquery: unknown type_oid=" << type_oid; break; } } @@ -691,20 +690,22 @@ public: desc.add_descriptor(mapnik::attribute_descriptor(fld_name, mapnik::String)); } } -#ifdef MAPNIK_DEBUG else { // "Column Affinity" says default to "Numeric" but for now we pass.. //desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double)); - // TODO - this should not fail when we specify geometry_field in XML file - - std::clog << "Sqlite Plugin: column '" - << std::string(fld_name) - << "' unhandled due to unknown type: " - << fld_type << std::endl; - } +#ifdef MAPNIK_LOG + // Do not fail when we specify geometry_field in XML file + if (field.empty()) + { + MAPNIK_LOG_DEBUG(sqlite) << "Column '" + << std::string(fld_name) + << "' unhandled due to unknown type: " + << fld_type; + } #endif + } } } diff --git a/src/debug.cpp b/src/debug.cpp index f0f4d4540..bebacb4b3 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -27,7 +27,7 @@ #include #ifndef MAPNIK_LOG_FORMAT -#define MAPNIK_LOG_FORMAT "Mapnik LOG> %Y-%m-%d %H:%M:%S:" + #define MAPNIK_LOG_FORMAT Mapnik LOG> %Y-%m-%d %H:%M:%S: #endif #ifndef MAPNIK_DEFAULT_LOG_SEVERITY diff --git a/src/jpeg_reader.cpp b/src/jpeg_reader.cpp index 1b3eab6c1..05dbd66fe 100644 --- a/src/jpeg_reader.cpp +++ b/src/jpeg_reader.cpp @@ -45,6 +45,9 @@ private: std::string fileName_; unsigned width_; unsigned height_; + jpeg_decompress_struct cinfo; + jpeg_error_mgr jerr; + FILE *fp; public: explicit JpegReader(std::string const& fileName); ~JpegReader(); @@ -54,6 +57,8 @@ public: void read(unsigned x,unsigned y,image_data_32& image); private: void init(); + static void on_error(j_common_ptr cinfo); + static void on_error_message(j_common_ptr cinfo); }; namespace @@ -68,27 +73,43 @@ const bool registered = register_image_reader("jpeg",createJpegReader); JpegReader::JpegReader(std::string const& fileName) : fileName_(fileName), width_(0), - height_(0) + height_(0), + fp(NULL) { init(); } -JpegReader::~JpegReader() {} +JpegReader::~JpegReader() { + if (fp) + { + fclose(fp); + } + jpeg_destroy_decompress(&cinfo); +} + +void JpegReader::on_error(j_common_ptr cinfo) +{ + (*cinfo->err->output_message)(cinfo); + jpeg_destroy(cinfo); + throw image_reader_exception("JPEG Reader: libjpeg could not read image"); +} + +void JpegReader::on_error_message(j_common_ptr cinfo) +{ + // used to supress jpeg from printing to stderr +} void JpegReader::init() { - FILE *fp = fopen(fileName_.c_str(),"rb"); + fp = fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + fileName_); - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - + jerr.error_exit = on_error; + jerr.output_message = on_error_message; jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); width_ = cinfo.output_width; height_ = cinfo.output_height; @@ -110,12 +131,9 @@ unsigned JpegReader::height() const void JpegReader::read(unsigned x0, unsigned y0, image_data_32& image) { - struct jpeg_decompress_struct cinfo; - - FILE *fp = fopen(fileName_.c_str(),"rb"); + fp = fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + fileName_); - struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); @@ -129,7 +147,6 @@ void JpegReader::read(unsigned x0, unsigned y0, image_data_32& image) if (cinfo.output_width == 0) { jpeg_destroy_decompress (&cinfo); - fclose(fp); throw image_reader_exception("JPEG Reader: failed to read image size of " + fileName_); } @@ -168,6 +185,5 @@ void JpegReader::read(unsigned x0, unsigned y0, image_data_32& image) } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); - fclose(fp); } } diff --git a/src/map.cpp b/src/map.cpp index f8fddbd77..0e840b030 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -264,8 +264,8 @@ void Map::set_height(unsigned height) void Map::resize(unsigned width,unsigned height) { - if (width != width_ && - height != height_ && + if ((width != width_ || + height != height_) && width >= MIN_MAPSIZE && width <= MAX_MAPSIZE && height >= MIN_MAPSIZE && diff --git a/src/projection.cpp b/src/projection.cpp index abe871c9c..53ffce126 100644 --- a/src/projection.cpp +++ b/src/projection.cpp @@ -68,13 +68,16 @@ projection::projection(projection const& rhs) proj_(NULL), proj_ctx_(NULL) { - if (!rhs.defer_proj_init_) init_proj4(); + if (!defer_proj_init_) init_proj4(); } projection& projection::operator=(projection const& rhs) { projection tmp(rhs); swap(tmp); + proj_ctx_ = 0; + proj_ = 0; + if (!defer_proj_init_) init_proj4(); return *this; } @@ -210,6 +213,8 @@ std::string projection::expanded() const void projection::swap(projection& rhs) { std::swap(params_,rhs.params_); + std::swap(defer_proj_init_,rhs.defer_proj_init_); + std::swap(is_geographic_,rhs.is_geographic_); } } diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 43a3beac1..9c1897b68 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -82,6 +82,7 @@ private: void read_stripped(unsigned x,unsigned y,image_data_32& image); void read_tiled(unsigned x,unsigned y,image_data_32& image); TIFF* load_if_exists(std::string const& filename); + static void on_error(const char* /*module*/, const char* fmt, va_list argptr); }; namespace @@ -107,11 +108,18 @@ tiff_reader::tiff_reader(std::string const& file_name) init(); } +void tiff_reader::on_error(const char* /*module*/, const char* fmt, va_list argptr) +{ + char msg[10240]; + vsprintf(msg, fmt, argptr); + throw image_reader_exception(msg); +} void tiff_reader::init() { // TODO: error handling TIFFSetWarningHandler(0); + TIFFSetErrorHandler(on_error); TIFF* tif = load_if_exists(file_name_); if (!tif) throw image_reader_exception( std::string("Can't load tiff file: '") + file_name_ + "'"); diff --git a/tests/cpp_tests/data/blank.jpg b/tests/cpp_tests/data/blank.jpg new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cpp_tests/data/blank.png b/tests/cpp_tests/data/blank.png new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cpp_tests/data/blank.tiff b/tests/cpp_tests/data/blank.tiff new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp new file mode 100644 index 000000000..f42718d85 --- /dev/null +++ b/tests/cpp_tests/image_io_test.cpp @@ -0,0 +1,75 @@ +#include +#include +namespace fs = boost::filesystem; +using fs::path; +namespace sys = boost::system; + +#include +#include +#include +#include + + +int main( int, char*[] ) +{ + std::string blank; + boost::optional type; + try + { + blank = "./tests/cpp_tests/data/blank.jpg"; + BOOST_TEST( fs::exists( blank ) ); + type = mapnik::type_from_filename(blank); + BOOST_TEST( type ); + try + { + std::auto_ptr reader(mapnik::get_image_reader(blank,*type)); + BOOST_TEST( false ); + } + catch (std::exception const&) + { + BOOST_TEST( true ); + } + + blank = "./tests/cpp_tests/data/blank.png"; + BOOST_TEST( fs::exists( blank ) ); + type = mapnik::type_from_filename(blank); + BOOST_TEST( type ); + try + { + std::auto_ptr reader(mapnik::get_image_reader(blank,*type)); + BOOST_TEST( false ); + } + catch (std::exception const&) + { + BOOST_TEST( true ); + } + + blank = "./tests/cpp_tests/data/blank.tiff"; + BOOST_TEST( fs::exists( blank ) ); + type = mapnik::type_from_filename(blank); + BOOST_TEST( type ); + try + { + std::auto_ptr reader(mapnik::get_image_reader(blank,*type)); + BOOST_TEST( false ); + } + catch (std::exception const&) + { + BOOST_TEST( true ); + } + } + catch (std::exception const & ex) + { + std::clog << "C++ image i/o problem: " << ex.what() << "\n"; + BOOST_TEST(false); + } + + if (!::boost::detail::test_errors()) { + std::clog << "C++ image i/o: \x1b[1;32m✓ \x1b[0m\n"; +#if BOOST_VERSION >= 104600 + ::boost::detail::report_errors_remind().called_report_errors_function = true; +#endif + } else { + return ::boost::report_errors(); + } +} diff --git a/tests/visual_tests/images/simple-400-100-2.0-agg-reference.png b/tests/visual_tests/images/simple-400-100-2.0-agg-reference.png index 9d412144f..b9efaa379 100644 Binary files a/tests/visual_tests/images/simple-400-100-2.0-agg-reference.png and b/tests/visual_tests/images/simple-400-100-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/simple-800-100-2.0-agg-reference.png b/tests/visual_tests/images/simple-800-100-2.0-agg-reference.png index cde42dbf6..d1f9fcdf9 100644 Binary files a/tests/visual_tests/images/simple-800-100-2.0-agg-reference.png and b/tests/visual_tests/images/simple-800-100-2.0-agg-reference.png differ