svg tile rendering with cairo_renderer

300 views
Skip to first unread message

Igor Stassiy

unread,
Mar 5, 2014, 3:24:00 PM3/5/14
to map...@googlegroups.com
Hi,

I would like to render tiles in svg using the cairo_renderer. Here is what I have so far:

The code write the svg image to stdout for now, but I would like to get it as a string in the end.

cairo_status_t writeCairo(void * closure, const unsigned char* data, unsigned int length){
    cout << string((const char*)data, length) << endl;
    return CAIRO_STATUS_SUCCESS;
}

cairo_svg_surface_create_for_stream(writeCairo,NULL,width,height),mapnik::cairo_surface_closer();
mapnik::cairo_surface_ptr surface =
    mapnik::cairo_surface_ptr(cairo_svg_surface_create_for_stream(writeCairo,NULL,width,height),
    mapnik::cairo_surface_closer());
mapnik::cairo_ptr image_context(mapnik::create_context(surface));
mapnik::cairo_renderer<mapnik::cairo_ptr> svg_render(map_, image_context, 1.0);

The problem with the code is that the writeCairo function is called multiple times per tile and gives the 
output in chunks. Is this behavior normal and can it be prevented? Any suggestions about the code above are
more than welcome.

Thanks
Igor


Igor Stassiy

unread,
Mar 6, 2014, 10:29:11 AM3/6/14
to map...@googlegroups.com
Looks like I didn't put all the code

cairo_svg_surface_create_for_stream(writeCairo,NULL,width,height);

mapnik::cairo_surface_ptr surface = 
    mapnik::cairo_surface_ptr(cairo_svg_surface_create_for_stream(writeCairo,NULL,width,height),
                              mapnik::cairo_surface_closer());
mapnik::cairo_ptr image_context(mapnik::create_context(surface));
mapnik::cairo_renderer<mapnik::cairo_ptr> svg_render(map_, image_context, 1.0);

svg_render.apply();
cairo_surface_flush(&*surface);
cairo_surface_finish(&*surface);

Igor Stassiy

unread,
Mar 8, 2014, 5:42:10 PM3/8/14
to map...@googlegroups.com
This is a follow up on the question. I gave up rendering svg to a string and now I write it to a file instead with

        mapnik::save_to_cairo_file(map_, canonicalName);

I attach an example svg that was rendered this way. It seems that the letter's geometry is represented with a path, 
as a result the file is pretty big. I wonder if there is support to represent text in a more efficient way as described here:


Thanks,
Igor

On Wednesday, March 5, 2014 9:24:00 PM UTC+1, Igor Stassiy wrote:
label-8513-5612-14.svg

Dane Springmeyer

unread,
Mar 11, 2014, 7:55:50 PM3/11/14
to map...@googlegroups.com
> The problem with the code is that the writeCairo function is called multiple times per tile and gives the 
output in chunks.

This is a cairo thing. I've noticed this as well. I implemented Vector Tile -> SVG output with Cairo in node-mapnik a while back and the way it works is by building up the string each time the callback is called. If I recall correctly you have to be careful not to finish the surface more than once otherwise you'll end up with duplicated SVG. You can see the code at https://github.com/mapnik/node-mapnik/blob/ff5048c07e5a7725f45ab5bc46eada68f36e181b/src/mapnik_vector_tile.cpp#L1761-L1770 and https://github.com/mapnik/node-mapnik/blob/ff5048c07e5a7725f45ab5bc46eada68f36e181b/src/mapnik_cairo_surface.hpp#L31-L45.

Dane Springmeyer

unread,
Mar 11, 2014, 8:06:13 PM3/11/14
to map...@googlegroups.com


On Saturday, March 8, 2014 2:42:10 PM UTC-8, Igor Stassiy wrote:
I attach an example svg that was rendered this way. It seems that the letter's geometry is represented with a path, 
as a result the file is pretty big.

This is correct. Another problem with representing text as paths is this uncovers bugs in Adobe Illustrator's SVG support: https://github.com/mapbox/tilemill/issues/2225

The reason this is done is two fold:

  - Mapnik lays out text glyph by glyph and vectorizing text this way is critical to ensure that text display in Cairo rendered surfaces is identical across cairo formats and compared to the AGG renderer
  - Also, I'm not aware of a way to do text with Cairo any other way: in short Cairo offers a generic API you write to and I'm not aware of a way to ask Cairo to use <text> instead of vectorizing in paths. 
 
I wonder if there is support to represent text in a more efficient way as described here:



Right, this is worth experimentation. We have a native svg_renderer backend in Mapnik that could do this, but it would need to be added. Currently the svg_renderer supports lines and polygons and is able to maintain layer grouping, which is a big requested feature than Cairo lacks. But we have not added support for labeling yet in this renderer and my intension has been to try using `<text>`. I imagine the drawback will be that we'll loose the fine-grained control of layout, but for some usecases (expecially post-processing) this is less important than just keeping text as editable text.

What is your particular usecase?

Dane
Reply all
Reply to author
Forward
0 new messages