diff --git a/.travis.yml b/.travis.yml index 15e8ad11e..d0ae0c5c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,10 @@ before_install: - echo 'yes' | sudo add-apt-repository ppa:mapnik/boost - echo 'yes' | sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq - - sudo apt-get install -qq gcc-4.7 g++-4.7 libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-python-dev libboost-regex-dev libboost-system-dev libboost-thread-dev python-nose libicu-dev libpng-dev libjpeg-dev libtiff-dev libwebp-dev libz-dev libfreetype6-dev libxml2-dev libproj-dev + - sudo apt-get install -qq gcc-4.7 g++-4.7 make libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-python-dev libboost-regex-dev libboost-system-dev libboost-thread-dev python-nose libicu-dev libpng-dev libjpeg-dev libtiff-dev libwebp-dev libz-dev libfreetype6-dev libxml2-dev libproj-dev libcairo-dev python-cairo-dev libsqlite3-dev postgresql-server-dev* script: - - if [ "${CXX}" = 'g++' ]; then export CXX="g++-4.7" && export CC="gcc-4.7"; fi; ./configure CXX=${CXX} CC=${CC} DEMO=False BINDINGS=python CPP_TESTS=True CAIRO=False FAST=True || cat config.log + - if [ "${CXX}" = 'g++' ]; then export CXX="g++-4.7" && export CC="gcc-4.7"; fi; ./configure CXX=${CXX} CC=${CC} DEMO=False BINDINGS=python CPP_TESTS=True CAIRO=True FAST=True || cat config.log - JOBS=1 make - make test-local diff --git a/CHANGELOG.md b/CHANGELOG.md index 30eda2629..1bdf0e468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ Released ... Summary: TODO +- Fixed crash when rendering to cairo context from python (#2031) + - Moved `label-position-tolerance` from unsigned type to double - Default PNG encoding method when `png` is supplied is now `png8:m=h`, so paletted png using hextree color quantization (#2028) diff --git a/README.md b/README.md index 7ddca1790..ec2945db1 100644 --- a/README.md +++ b/README.md @@ -12,19 +12,18 @@ _/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/ # What is Mapnik? -Mapnik is an open source toolkit and API for developing mapping applications. At the core is a C++ shared library providing algorithms and patterns for spatial data access and visualization. High-level bindings for Java, JavaScript, Python, and Ruby facilitate rapid application development in a variety of environments. +Mapnik is an open source toolkit for developing mapping applications. At the core is a C++ shared library providing algorithms and patterns for spatial data access and visualization. High-level bindings for JavaScript, Python, and Ruby facilitate rapid application development in a variety of environments. # Overview Mapnik is basically a collection of geographic objects like maps, layers, datasources, features, and geometries. The library doesn't rely on any OS specific "windowing systems" and it can be deployed to any server environment. It is intended to play fair in a multi-threaded environment and is aimed primarily, but not exclusively, at web-based development. - For further information see [http://mapnik.org](http://mapnik.org) and also our [wiki documentation](https://github.com/mapnik/mapnik/wiki) here on GitHub. # Installation -See [INSTALL.md](https://github.com/mapnik/mapnik/blob/master/INSTALL.md) for installation instructions. +See [INSTALL.md](https://github.com/mapnik/mapnik/blob/master/INSTALL.md) for installation instructions and the [Install](https://github.com/mapnik/mapnik/wiki/Mapnik-Installation) page on the wiki for guides. # License -Mapnik software is free and is released under LGPL ([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html_)). Please see [COPYING](https://github.com/mapnik/mapnik/blob/master/COPYING) for more information. +Mapnik software is free and is released under the LGPL ([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html_)). Please see [COPYING](https://github.com/mapnik/mapnik/blob/master/COPYING) for more information. diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 6481463a6..17b4a96bf 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -38,6 +38,7 @@ #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) #include #include +#include #endif using mapnik::image_32; @@ -208,7 +209,7 @@ void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, fl #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) std::shared_ptr from_cairo(PycairoSurface* py_surface) { - mapnik::cairo_surface_ptr surface(py_surface->surface, mapnik::cairo_surface_closer()); + mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); std::shared_ptr image_ptr = std::make_shared(surface); return image_ptr; } diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 7d731677e..52c537df1 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -117,6 +117,7 @@ void clear_cache() #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) #include +#include static Pycairo_CAPI_t *Pycairo_CAPI; #endif @@ -201,7 +202,7 @@ void render5(const mapnik::Map& map, unsigned offset_y = 0) { python_unblock_auto_block b; - mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer()); mapnik::cairo_renderer ren(map,context,scale_factor,offset_x, offset_y); ren.apply(); } @@ -209,7 +210,7 @@ void render5(const mapnik::Map& map, void render6(const mapnik::Map& map, PycairoContext* py_context) { python_unblock_auto_block b; - mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer()); mapnik::cairo_renderer ren(map,context); ren.apply(); } @@ -220,7 +221,7 @@ void render_with_detector2( std::shared_ptr detector) { python_unblock_auto_block b; - mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer()); mapnik::cairo_renderer ren(map,context,detector); ren.apply(); } @@ -234,7 +235,7 @@ void render_with_detector3( unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer()); mapnik::cairo_renderer ren(map,context,detector,scale_factor,offset_x,offset_y); ren.apply(); } diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index 20416c8a3..5ecb72f23 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -301,7 +301,7 @@ int main ( int argc , char** argv) cairo_image_surface_create(CAIRO_FORMAT_ARGB32,m.width(),m.height()), cairo_surface_closer()); double scale_factor = 1.0; - cairo_ptr image_context = (create_context(image_surface)); + cairo_ptr image_context(create_context(image_surface)); mapnik::cairo_renderer png_render(m,image_context,scale_factor); png_render.apply(); // we can now write to png with cairo functionality diff --git a/demo/test/charplacement.py b/demo/test/charplacement.py deleted file mode 100644 index b3a9f4555..000000000 --- a/demo/test/charplacement.py +++ /dev/null @@ -1,82 +0,0 @@ -# $Id: rundemo.py 577 2008-01-03 11:39:10Z artem $ -# -# This file is part of Mapnik (c++ mapping toolkit) -# Copyright (C) 2005 Jean-Francois Doyon -# -# Mapnik is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# Import everything. In this case this is safe, in more complex systems, you -# will want to be more selective. - -try: - from mapnik import * -except: - print '\n\nThe mapnik library and python bindings must have been compiled and \ -installed successfully before running this script.\n\n' - raise - -m = Map(690,690,"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") - -m.background = Color(255,100,100,255) - -road_style = Style() - -#Road -road_rule = Rule() -road_stroke = Stroke(Color('white'), 1) -road_stroke.opacity = 0.7 -#road_rule.filter = Filter("[CLASS] = 'BENDUNDER' or [CLASS] = 'BENDOVER'") -road_rule.symbols.append(LineSymbolizer(road_stroke)) -road_style.rules.append(road_rule); - -#Road text -text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 20, Color('black')) -text_symbolizer.label_placement=label_placement.LINE_PLACEMENT -text_symbolizer.minimum_distance = 0 -#text_symbolizer.max_char_angle_delta = 40 -#text_symbolizer.force_odd_labels = 1 -text_symbolizer.label_spacing = 20 -text_symbolizer.label_position_tolerance = 50 -text_symbolizer.minimum_distance = 5 -text_symbolizer.avoid_edges = 0 -text_symbolizer.halo_fill = Color('yellow') -text_symbolizer.halo_radius = 1 -road_rule = Rule() -#road_rule.filter = Filter("[CLASS] = 'BENDUNDER' or [CLASS] = 'BENDOVER'") -road_rule.symbols.append(text_symbolizer) -road_style.rules.append(road_rule) - - -road_layer = Layer('road') -road_layer.datasource = Shapefile(file='../data/test/charplacement') - -m.append_style('road', road_style) -road_layer.styles.append('road') -m.layers.append(road_layer) - -# Draw map - -# Set the initial extent of the map. -m.zoom_to_box(Box2d(0,0,14,-14)) - - -# Render -im = Image(m.width,m.height) -render(m, im) - -# Save image to file -im.save('output.png') # true-colour RGBA - -print "Done\n" diff --git a/demo/test/displacement.py b/demo/test/displacement.py deleted file mode 100644 index 185a5f8b0..000000000 --- a/demo/test/displacement.py +++ /dev/null @@ -1,83 +0,0 @@ -# $Id: rundemo.py 577 2008-01-03 11:39:10Z artem $ -# -# This file is part of Mapnik (c++ mapping toolkit) -# Copyright (C) 2005 Jean-Francois Doyon -# -# Mapnik is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# Import everything. In this case this is safe, in more complex systems, you -# will want to be more selective. - -try: - from mapnik import * -except: - print '\n\nThe mapnik library and python bindings must have been compiled and \ -installed successfully before running this script.\n\n' - raise - -m = Map(690,690,"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") - -m.background = Color(255,100,100,255) - -road_style = Style() - -#Road -road_rule = Rule() -road_stroke = Stroke(Color('white'), 1) -road_stroke.line_cap = line_cap.ROUND_CAP -road_stroke.line_join = line_join.ROUND_JOIN -#road_rule.filter = Filter("[CLASS] = 'CROSS'") -road_rule.symbols.append(LineSymbolizer(road_stroke)) -road_style.rules.append(road_rule); - -#Road text -text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 10, Color('black')) -text_symbolizer.label_placement=label_placement.LINE_PLACEMENT -text_symbolizer.minimum_distance = 0 -#text_symbolizer.max_char_angle_delta = 40 -#text_symbolizer.force_odd_labels = 1 -#FIXME: Displacement cannot be set from python so we can't set it here, lol! -text_symbolizer.label_spacing = 60 -text_symbolizer.label_position_tolerance = 5 -text_symbolizer.avoid_edges = 0 -text_symbolizer.halo_fill = Color('yellow') -text_symbolizer.halo_radius = 1 -road_rule = Rule() -#road_rule.filter = Filter("[CLASS] = 'CROSS'") -road_rule.symbols.append(text_symbolizer) -road_style.rules.append(road_rule) - - -road_layer = Layer('road') -road_layer.datasource = Shapefile(file='../data/test/displacement') - -m.append_style('road', road_style) -road_layer.styles.append('road') -m.layers.append(road_layer) - -# Draw map - -# Set the initial extent of the map. -m.zoom_to_box(Box2d(0,0,14,-14)) - - -# Render -im = Image(m.width,m.height) -render(m, im) - -# Save image to file -im.save('output.png') # true-colour RGBA - -print "Done\n" diff --git a/demo/test/overlap.py b/demo/test/overlap.py deleted file mode 100644 index 291159eb7..000000000 --- a/demo/test/overlap.py +++ /dev/null @@ -1,84 +0,0 @@ -# $Id: rundemo.py 577 2008-01-03 11:39:10Z artem $ -# -# This file is part of Mapnik (c++ mapping toolkit) -# Copyright (C) 2005 Jean-Francois Doyon -# -# Mapnik is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# Import everything. In this case this is safe, in more complex systems, you -# will want to be more selective. - -try: - from mapnik import * -except: - print '\n\nThe mapnik library and python bindings must have been compiled and \ -installed successfully before running this script.\n\n' - raise - -m = Map(690,690,"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") - -m.background = Color(255,100,100,255) - -road_style = Style() - -#Road -road_rule = Rule() -road_stroke = Stroke(Color('white'), 12) -road_stroke.opacity = 0.7 -#road_stroke.line_cap = line_cap.ROUND_CAP -#road_stroke.line_join = line_join.ROUND_JOIN -#road_rule.filter = Filter("[CLASS] = 'CROSS'") -road_rule.symbols.append(LineSymbolizer(road_stroke)) -road_style.rules.append(road_rule); - -#Road text -text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 10, Color('black')) -text_symbolizer.label_placement=label_placement.LINE_PLACEMENT -text_symbolizer.minimum_distance = 0 -#text_symbolizer.max_char_angle_delta = 40 -#text_symbolizer.force_odd_labels = 1 -text_symbolizer.label_spacing = 60 -text_symbolizer.label_position_tolerance = 50 -text_symbolizer.minimum_distance = 5 -text_symbolizer.avoid_edges = 0 -text_symbolizer.halo_fill = Color('yellow') -text_symbolizer.halo_radius = 1 -road_rule = Rule() -#road_rule.filter = Filter("[CLASS] = 'CROSS'") -road_rule.symbols.append(text_symbolizer) -road_style.rules.append(road_rule) - - -road_layer = Layer('road') -road_layer.datasource = Shapefile(file='../data/test/overlap') - -m.append_style('road', road_style) -road_layer.styles.append('road') -m.layers.append(road_layer) - -# Draw map - -# Set the initial extent of the map. -m.zoom_to_box(Box2d(0,0,14,-14)) - - -# Render -im = Image(m.width,m.height) -render(m, im) - -# Save image to file -im.save('output.png') # true-colour RGBA - -print "Done\n" diff --git a/demo/test/textspacing.py b/demo/test/textspacing.py deleted file mode 100644 index 0d01e149f..000000000 --- a/demo/test/textspacing.py +++ /dev/null @@ -1,82 +0,0 @@ -# $Id: rundemo.py 577 2008-01-03 11:39:10Z artem $ -# -# This file is part of Mapnik (c++ mapping toolkit) -# Copyright (C) 2005 Jean-Francois Doyon -# -# Mapnik is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -# Import everything. In this case this is safe, in more complex systems, you -# will want to be more selective. - -try: - from mapnik import * -except: - print '\n\nThe mapnik library and python bindings must have been compiled and \ -installed successfully before running this script.\n\n' - raise - -m = Map(690,690,"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") - -m.background = Color(255,100,100,255) - -road_style = Style() - -#Road -road_rule = Rule() -road_stroke = Stroke(Color('white'), 12) -road_stroke.line_cap = line_cap.ROUND_CAP -road_stroke.line_join = line_join.ROUND_JOIN -#road_rule.filter = Filter("[CLASS] = 'STRAIGHT'") -road_rule.symbols.append(LineSymbolizer(road_stroke)) -road_style.rules.append(road_rule); - -#Road text -text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 10, Color('black')) -text_symbolizer.label_placement=label_placement.LINE_PLACEMENT -text_symbolizer.minimum_distance = 0 -#text_symbolizer.max_char_angle_delta = 40 -#text_symbolizer.force_odd_labels = 1 -text_symbolizer.label_spacing = 80 -text_symbolizer.label_position_tolerance = 5 -text_symbolizer.avoid_edges = 0 -text_symbolizer.halo_fill = Color('yellow') -text_symbolizer.halo_radius = 1 -road_rule = Rule() -#road_rule.filter = Filter("[CLASS] = 'STRAIGHT'") -road_rule.symbols.append(text_symbolizer) -road_style.rules.append(road_rule) - - -road_layer = Layer('road') -road_layer.datasource = Shapefile(file='../data/test/textspacing') - -m.append_style('road', road_style) -road_layer.styles.append('road') -m.layers.append(road_layer) - -# Draw map - -# Set the initial extent of the map. -m.zoom_to_box(Box2d(0,0,14,-14)) - - -# Render -im = Image(m.width,m.height) -render(m, im) - -# Save image to file -im.save('output.png') # true-colour RGBA - -print "Done\n" diff --git a/tests/python_tests/cairo_test.py b/tests/python_tests/cairo_test.py index 467f17df8..d35a3a5ff 100644 --- a/tests/python_tests/cairo_test.py +++ b/tests/python_tests/cairo_test.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import os +import shutil import mapnik from nose.tools import * from utilities import execution_path, run_all @@ -10,53 +11,182 @@ def setup(): # from another directory we need to chdir() os.chdir(execution_path('.')) -if mapnik.has_pycairo() and 'sqlite' in mapnik.DatasourceCache.plugin_names(): +def make_tmp_map(): + m = mapnik.Map(512,512) + m.background_color = mapnik.Color('steelblue') + ds = mapnik.MemoryDatasource() + context = mapnik.Context() + context.push('Name') + f = mapnik.Feature(context,1) + f['Name'] = 'Hello' + f.add_geometries_from_wkt('POINT (0 0)') + ds.add_feature(f) + s = mapnik.Style() + r = mapnik.Rule() + sym = mapnik.MarkersSymbolizer() + sym.allow_overlap = True + r.symbols.append(sym) + s.rules.append(r) + lyr = mapnik.Layer('Layer') + lyr.datasource = ds + lyr.styles.append('style') + m.append_style('style',s) + m.layers.append(lyr) + return m - def _pycairo_surface(type,sym): - import cairo - test_cairo_file = '/tmp/test.%s' % type - m = mapnik.Map(256,256) - mapnik.load_map(m,'../data/good_maps/%s_symbolizer.xml' % sym) - if hasattr(cairo,'%sSurface' % type.upper()): - surface = getattr(cairo,'%sSurface' % type.upper())(test_cairo_file, m.width,m.height) - mapnik.render(m, surface) - surface.finish() - if os.path.exists(test_cairo_file): +def draw_title(m,ctx,text,size=10,color=mapnik.Color('black')): + """ Draw a Map Title near the top of a page.""" + middle = m.width/2.0 + ctx.set_source_rgba(*cairo_color(color)) + ctx.select_font_face("DejaVu Sans Book", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + ctx.set_font_size(size) + x_bearing, y_bearing, width, height = ctx.text_extents(text)[:4] + ctx.move_to(middle - width / 2 - x_bearing, 20.0 - height / 2 - y_bearing) + ctx.show_text(text) + +def draw_neatline(m,ctx): + w,h = m.width, m.height + ctx.set_source_rgba(*cairo_color(mapnik.Color('black'))) + outline = [ + [0,0],[w,0],[w,h],[0,h] + ] + ctx.set_line_width(1) + for idx,pt in enumerate(outline): + if (idx == 0): + ctx.move_to(*pt) + else: + ctx.line_to(*pt) + ctx.close_path() + inset = 6 + inline = [ + [inset,inset],[w-inset,inset],[w-inset,h-inset],[inset,h-inset] + ] + ctx.set_line_width(inset/2) + for idx,pt in enumerate(inline): + if (idx == 0): + ctx.move_to(*pt) + else: + ctx.line_to(*pt) + ctx.close_path() + ctx.stroke() + +def cairo_color(c): + """ Return a Cairo color tuple from a Mapnik Color.""" + ctx_c = (c.r/255.0,c.g/255.0,c.b/255.0,c.a/255.0) + return ctx_c + +if mapnik.has_pycairo(): + import cairo + + def test_passing_pycairo_context_svg(): + m = make_tmp_map() + m.zoom_to_box(mapnik.Box2d(-180,-90,180,90)) + test_cairo_file = '/tmp/mapnik-cairo-context-test.svg' + surface = cairo.SVGSurface(test_cairo_file, m.width, m.height) + expected_cairo_file = './images/pycairo/cairo-cairo-expected.svg' + context = cairo.Context(surface) + mapnik.render(m,context) + draw_title(m,context,"Hello Map",size=20) + draw_neatline(m,context) + surface.finish() + if not os.path.exists(expected_cairo_file): + print 'generated expected cairo surface file %s' % expected_cairo_file + shutil.copy(test_cairo_file,expected_cairo_file) + diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size) + msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file) + eq_( diff < 1500, True, msg) + os.remove(test_cairo_file) + + def test_passing_pycairo_context_pdf(): + m = make_tmp_map() + m.zoom_to_box(mapnik.Box2d(-180,-90,180,90)) + test_cairo_file = '/tmp/mapnik-cairo-context-test.pdf' + surface = cairo.PDFSurface(test_cairo_file, m.width, m.height) + expected_cairo_file = './images/pycairo/cairo-cairo-expected.pdf' + context = cairo.Context(surface) + mapnik.render(m,context) + draw_title(m,context,"Hello Map",size=20) + draw_neatline(m,context) + surface.finish() + if not os.path.exists(expected_cairo_file): + print 'generated expected cairo surface file %s' % expected_cairo_file + shutil.copy(test_cairo_file,expected_cairo_file) + diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size) + msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file) + eq_( diff < 1500, True, msg) + os.remove(test_cairo_file) + + def test_passing_pycairo_context_png(): + m = make_tmp_map() + m.zoom_to_box(mapnik.Box2d(-180,-90,180,90)) + test_cairo_file = '/tmp/mapnik-cairo-context-test.png' + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, m.width, m.height) + expected_cairo_file = './images/pycairo/cairo-cairo-expected.png' + expected_cairo_file2 = './images/pycairo/cairo-cairo-expected-reduced.png' + context = cairo.Context(surface) + mapnik.render(m,context) + draw_title(m,context,"Hello Map",size=20) + draw_neatline(m,context) + surface.write_to_png(test_cairo_file) + reduced_color_image = test_cairo_file.replace('png','-mapnik.png') + im = mapnik.Image.from_cairo(surface) + im.save(reduced_color_image,'png8') + surface.finish() + if not os.path.exists(expected_cairo_file): + print 'generated expected cairo surface file %s' % expected_cairo_file + shutil.copy(test_cairo_file,expected_cairo_file) + diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size) + msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file) + eq_( diff < 500, True, msg) + os.remove(test_cairo_file) + if not os.path.exists(expected_cairo_file2): + print 'generated expected cairo surface file %s' % expected_cairo_file2 + shutil.copy(reduced_color_image,expected_cairo_file2) + diff = abs(os.stat(expected_cairo_file2).st_size-os.stat(reduced_color_image).st_size) + msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,reduced_color_image,'tests/python_tests/'+ expected_cairo_file2) + eq_( diff < 500, True, msg) + os.remove(reduced_color_image) + + if 'sqlite' in mapnik.DatasourceCache.plugin_names(): + def _pycairo_surface(type,sym): + test_cairo_file = '/tmp/mapnik-cairo-surface-test.%s.%s' % (sym,type) + expected_cairo_file = './images/pycairo/cairo-surface-expected.%s.%s' % (sym,type) + m = mapnik.Map(256,256) + mapnik.load_map(m,'../data/good_maps/%s_symbolizer.xml' % sym) + m.zoom_all() + if hasattr(cairo,'%sSurface' % type.upper()): + surface = getattr(cairo,'%sSurface' % type.upper())(test_cairo_file, m.width,m.height) + mapnik.render(m, surface) + surface.finish() + if not os.path.exists(expected_cairo_file): + print 'generated expected cairo surface file %s' % expected_cairo_file + shutil.copy(test_cairo_file,expected_cairo_file) + diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size) + msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file) + eq_( diff < 2100, True, msg) os.remove(test_cairo_file) return True else: - # Fail, the file wasn't written - return False - else: - print 'skipping cairo.%s test since surface is not available' % type.upper() - return True + print 'skipping cairo.%s test since surface is not available' % type.upper() + return True - def test_pycairo_svg_surface1(): - eq_(_pycairo_surface('svg','point'),True) + def test_pycairo_svg_surface1(): + eq_(_pycairo_surface('svg','point'),True) - def test_pycairo_svg_surface2(): - eq_(_pycairo_surface('svg','building'),True) + def test_pycairo_svg_surface2(): + eq_(_pycairo_surface('svg','building'),True) - def test_pycairo_svg_surface3(): - eq_(_pycairo_surface('svg','polygon'),True) + def test_pycairo_svg_surface3(): + eq_(_pycairo_surface('svg','polygon'),True) - def test_pycairo_pdf_surface1(): - eq_(_pycairo_surface('pdf','point'),True) + def test_pycairo_pdf_surface1(): + eq_(_pycairo_surface('pdf','point'),True) - def test_pycairo_pdf_surface2(): - eq_(_pycairo_surface('pdf','building'),True) + def test_pycairo_pdf_surface2(): + eq_(_pycairo_surface('pdf','building'),True) - def test_pycairo_pdf_surface3(): - eq_(_pycairo_surface('pdf','polygon'),True) - - def test_pycairo_ps_surface1(): - eq_(_pycairo_surface('ps','point'),True) - - def test_pycairo_ps_surface2(): - eq_(_pycairo_surface('ps','building'),True) - - def test_pycairo_ps_surface3(): - eq_(_pycairo_surface('ps','polygon'),True) + def test_pycairo_pdf_surface3(): + eq_(_pycairo_surface('pdf','polygon'),True) if __name__ == "__main__": setup() diff --git a/tests/python_tests/images/pycairo/cairo-cairo-expected-reduced.png b/tests/python_tests/images/pycairo/cairo-cairo-expected-reduced.png new file mode 100644 index 000000000..6c3bfc9a7 Binary files /dev/null and b/tests/python_tests/images/pycairo/cairo-cairo-expected-reduced.png differ diff --git a/tests/python_tests/images/pycairo/cairo-cairo-expected.pdf b/tests/python_tests/images/pycairo/cairo-cairo-expected.pdf new file mode 100644 index 000000000..7c654aee4 Binary files /dev/null and b/tests/python_tests/images/pycairo/cairo-cairo-expected.pdf differ diff --git a/tests/python_tests/images/pycairo/cairo-cairo-expected.png b/tests/python_tests/images/pycairo/cairo-cairo-expected.png new file mode 100644 index 000000000..1c31f0e0c Binary files /dev/null and b/tests/python_tests/images/pycairo/cairo-cairo-expected.png differ diff --git a/tests/python_tests/images/pycairo/cairo-cairo-expected.svg b/tests/python_tests/images/pycairo/cairo-cairo-expected.svg new file mode 100644 index 000000000..ae1e90b7a --- /dev/null +++ b/tests/python_tests/images/pycairo/cairo-cairo-expected.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/python_tests/images/pycairo/cairo-surface-expected.building.pdf b/tests/python_tests/images/pycairo/cairo-surface-expected.building.pdf new file mode 100644 index 000000000..21d0661ff Binary files /dev/null and b/tests/python_tests/images/pycairo/cairo-surface-expected.building.pdf differ diff --git a/tests/python_tests/images/pycairo/cairo-surface-expected.building.svg b/tests/python_tests/images/pycairo/cairo-surface-expected.building.svg new file mode 100644 index 000000000..48cf24115 --- /dev/null +++ b/tests/python_tests/images/pycairo/cairo-surface-expected.building.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/python_tests/images/pycairo/cairo-surface-expected.point.pdf b/tests/python_tests/images/pycairo/cairo-surface-expected.point.pdf new file mode 100644 index 000000000..667a2adbc Binary files /dev/null and b/tests/python_tests/images/pycairo/cairo-surface-expected.point.pdf differ diff --git a/tests/python_tests/images/pycairo/cairo-surface-expected.point.svg b/tests/python_tests/images/pycairo/cairo-surface-expected.point.svg new file mode 100644 index 000000000..ba37cb7fe --- /dev/null +++ b/tests/python_tests/images/pycairo/cairo-surface-expected.point.svg @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/python_tests/images/pycairo/cairo-surface-expected.polygon.pdf b/tests/python_tests/images/pycairo/cairo-surface-expected.polygon.pdf new file mode 100644 index 000000000..2621730f4 Binary files /dev/null and b/tests/python_tests/images/pycairo/cairo-surface-expected.polygon.pdf differ diff --git a/tests/python_tests/images/pycairo/cairo-surface-expected.polygon.svg b/tests/python_tests/images/pycairo/cairo-surface-expected.polygon.svg new file mode 100644 index 000000000..886e24b08 --- /dev/null +++ b/tests/python_tests/images/pycairo/cairo-surface-expected.polygon.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/visual_tests/test.py b/tests/visual_tests/test.py index dd5c0e8eb..4cd15cd3a 100755 --- a/tests/visual_tests/test.py +++ b/tests/visual_tests/test.py @@ -30,7 +30,7 @@ if 'Linux' == os.uname()[0]: # which is older than the 1.12.14 version we used on OS X # to generate the expected images, so we'll rachet back the threshold # https://github.com/mapnik/mapnik/issues/1868 - cairo_threshold = 120 + cairo_threshold = 181 def render_cairo(m, output, scale_factor): mapnik.render_to_file(m, output, 'ARGB32', scale_factor)