Skip to content

Commit

Permalink
fix cairo reference counting and add more cairo context tests - closes
Browse files Browse the repository at this point in the history
  • Loading branch information
Dane Springmeyer committed Oct 28, 2013
1 parent 986f47e commit 86dfa07
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 41 deletions.
3 changes: 2 additions & 1 deletion bindings/python/mapnik_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <mapnik/cairo_context.hpp>
#include <pycairo.h>
#include <cairo.h>
#endif

using mapnik::image_32;
Expand Down Expand Up @@ -207,7 +208,7 @@ void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, fl
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
boost::shared_ptr<image_32> 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());
boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(surface);
return image_ptr;
}
Expand Down
9 changes: 5 additions & 4 deletions bindings/python/mapnik_python.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ void clear_cache()

#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <pycairo.h>
#include <cairo.h>
static Pycairo_CAPI_t *Pycairo_CAPI;
#endif

Expand Down Expand Up @@ -200,15 +201,15 @@ 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<mapnik::cairo_ptr> ren(map,context,scale_factor,offset_x, offset_y);
ren.apply();
}

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<mapnik::cairo_ptr> ren(map,context);
ren.apply();
}
Expand All @@ -219,7 +220,7 @@ void render_with_detector2(
boost::shared_ptr<mapnik::label_collision_detector4> 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<mapnik::cairo_ptr> ren(map,context,detector);
ren.apply();
}
Expand All @@ -233,7 +234,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<mapnik::cairo_ptr> ren(map,context,detector,scale_factor,offset_x,offset_y);
ren.apply();
}
Expand Down
2 changes: 1 addition & 1 deletion demo/c++/rundemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<cairo_ptr> png_render(m,image_context,scale_factor);
png_render.apply();
// we can now write to png with cairo functionality
Expand Down
199 changes: 164 additions & 35 deletions tests/python_tests/cairo_test.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,53 +11,181 @@ 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 _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 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 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)
eq_(os.stat(expected_cairo_file).st_size,os.stat(test_cairo_file).st_size)
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)
eq_(os.stat(expected_cairo_file).st_size,os.stat(test_cairo_file).st_size)
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)
eq_(os.stat(expected_cairo_file).st_size,os.stat(test_cairo_file).st_size)
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)
eq_(os.stat(expected_cairo_file2).st_size,os.stat(reduced_color_image).st_size)
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)
eq_(os.stat(expected_cairo_file).st_size,os.stat(test_cairo_file).st_size)
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_pdf_surface3():
eq_(_pycairo_surface('pdf','polygon'),True)

def test_pycairo_ps_surface1():
eq_(_pycairo_surface('ps','point'),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_surface2():
eq_(_pycairo_surface('ps','building'),True)

def test_pycairo_ps_surface3():
eq_(_pycairo_surface('ps','polygon'),True)
def test_pycairo_ps_surface3():
eq_(_pycairo_surface('ps','polygon'),True)

if __name__ == "__main__":
setup()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 86dfa07

Please sign in to comment.