diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 0695e7577..15bf2505e 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -196,19 +196,40 @@ void render_to_file1(const mapnik::Map& map, const std::string& filename, const std::string& format) { - mapnik::image_32 image(map.getWidth(),map.getHeight()); - render(map,image,0,0); - mapnik::save_to_file(image,filename,format); + if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24") + { +#if defined(HAVE_CAIRO) + mapnik::save_to_cairo_file(map,filename,format); +#else + throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); +#endif + } + else + { + mapnik::image_32 image(map.getWidth(),map.getHeight()); + render(map,image,0,0); + mapnik::save_to_file(image,filename,format); +} } -void render_to_file2(const mapnik::Map& map, - const std::string& filename) +void render_to_file2(const mapnik::Map& map,const std::string& filename) { - mapnik::image_32 image(map.getWidth(),map.getHeight()); - render(map,image,0,0); - mapnik::save_to_file(image,filename); + std::string format = mapnik::guess_type(filename); + if (format == "pdf" || format == "svg" || format =="ps") + { +#if defined(HAVE_CAIRO) + mapnik::save_to_cairo_file(map,filename,format); +#else + throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); +#endif + } + else + { + mapnik::image_32 image(map.getWidth(),map.getHeight()); + render(map,image,0,0); + mapnik::save_to_file(image,filename); +} } - double scale_denominator(mapnik::Map const &map, bool geographic) { diff --git a/demo/python/rundemo.py b/demo/python/rundemo.py index cdab8f77f..77a60a1b8 100644 --- a/demo/python/rundemo.py +++ b/demo/python/rundemo.py @@ -23,12 +23,20 @@ # Import everything. In this case this is safe, in more complex systems, you # will want to be more selective. +import sys + try: import mapnik except: print '\n\nThe mapnik library and python bindings must have been compiled and \ installed successfully before running this script.\n\n' - raise + sys.exit(1) + +try: + import cairo + HAS_PYCAIRO_MODULE = True +except ImportError: + HAS_PYCAIRO_MODULE = False # Instanciate a map, giving it a width and height. Remember: the word "map" is # reserved in Python! :) @@ -317,38 +325,55 @@ im = mapnik.Image(m.width,m.height) mapnik.render(m, im) # Save image to files -images = [] +images_ = [] im.save('demo.png', 'png') # true-colour RGBA -images.append('demo.png') +images_.append('demo.png') im.save('demo256.png', 'png256') # save to palette based (max 256 colours) png -images.append('demo256.png') -im.save('demo.jpg', 'jpeg') -images.append('demo.jpg') +images_.append('demo256.png') +im.save('demo_high.jpg', 'jpeg100') +images_.append('demo_high.jpg') +im.save('demo_low.jpg', 'jpeg50') +images_.append('demo_low.jpg') # Render cairo examples -if mapnik.has_pycairo(): +if HAS_PYCAIRO_MODULE and mapnik.has_pycairo(): - import cairo svg_surface = cairo.SVGSurface('demo.svg', m.width,m.height) mapnik.render(m, svg_surface) svg_surface.finish() - images.append('demo.svg') + images_.append('demo.svg') pdf_surface = cairo.PDFSurface('demo.pdf', m.width,m.height) mapnik.render(m, pdf_surface) - images.append('demo.pdf') + images_.append('demo.pdf') pdf_surface.finish() postscript_surface = cairo.PSSurface('demo.ps', m.width,m.height) mapnik.render(m, postscript_surface) - images.append('demo.ps') + images_.append('demo.ps') postscript_surface.finish() -else: - print '\n\nSkipping cairo examples as Mapnik Pycairo support not available' -print "\n\n", len(images), "maps have been rendered in the current directory:" -for image in images: - print "-", image +else: + print '\n\nPycairo not available...', + if mapnik.has_cairo(): + print ' will render Cairo formats using alternative method' + + mapnik.render_to_file(m,'demo.pdf') + images_.append('demo.pdf') + mapnik.render_to_file(m,'demo.ps') + images_.append('demo.ps') + mapnik.render_to_file(m,'demo.svg') + images_.append('demo.svg') + mapnik.render_to_file(m,'demo_cairo_rgb.png','RGB24') + images_.append('demo_cairo_rgb.png') + mapnik.render_to_file(m,'demo_cairo_argb.png','ARGB32') + images_.append('demo_cairo_argb.png') + +print "\n\n", len(images_), "maps have been rendered in the current directory:" + +for im_ in images_: + print "-", im_ + print "\n\nHave a look!\n\n" mapnik.save_map(m,"map.xml") diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index b7484a7b7..a1f8844c4 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -27,6 +27,7 @@ // mapnik #include +#include #include // boost @@ -55,6 +56,10 @@ namespace mapnik { } }; + MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + std::string const& type); + template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, @@ -93,18 +98,37 @@ namespace mapnik { return boost::algorithm::iends_with(filename,std::string(".tif")) || boost::algorithm::iends_with(filename,std::string(".tiff")); } - -inline boost::optional type_from_filename(std::string const& filename) -{ - typedef boost::optional result_type; - if (is_png(filename)) return result_type("png"); - if (is_jpeg(filename)) return result_type("jpeg"); - if (is_tiff(filename)) return result_type("tiff"); - return result_type(); -} -inline std::string guess_type( const std::string & filename ) -{ + inline bool is_pdf (std::string const& filename) + { + return boost::algorithm::iends_with(filename,std::string(".pdf")); + } + + inline bool is_svg (std::string const& filename) + { + return boost::algorithm::iends_with(filename,std::string(".svg")); + } + + inline bool is_ps (std::string const& filename) + { + return boost::algorithm::iends_with(filename,std::string(".ps")); + } + + inline boost::optional type_from_filename(std::string const& filename) + + { + typedef boost::optional result_type; + if (is_png(filename)) return result_type("png"); + if (is_jpeg(filename)) return result_type("jpeg"); + if (is_tiff(filename)) return result_type("tiff"); + if (is_pdf(filename)) return result_type("pdf"); + if (is_svg(filename)) return result_type("svg"); + if (is_ps(filename)) return result_type("ps"); + return result_type(); + } + + inline std::string guess_type( const std::string & filename ) + { std::string::size_type idx = filename.find_last_of("."); if ( idx != std::string::npos ) { return filename.substr( idx + 1 ); diff --git a/src/image_util.cpp b/src/image_util.cpp index 32a91bd69..7916b85ca 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -35,6 +35,10 @@ extern "C" #include #include +#ifdef HAVE_CAIRO +#include +#endif + // stl #include #include @@ -104,8 +108,10 @@ namespace mapnik } else throw ImageWriterException("unknown file type: " + type); } + else throw ImageWriterException("Could not write file to " + filename ); } + template void save_to_file(T const& image,std::string const& filename) { @@ -115,7 +121,63 @@ namespace mapnik save_to_file(image,filename,*type); } } - + +#if defined(HAVE_CAIRO) + // TODO - move to separate cairo_io.hpp + void save_to_cairo_file(mapnik::Map const& map, std::string const& filename) + { + boost::optional type = type_from_filename(filename); + if (type) + { + save_to_cairo_file(map,filename,*type); + } + } + + void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + std::string const& type) + { + std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); + if (file) + { + Cairo::RefPtr surface; + unsigned width = map.getWidth(); + unsigned height = map.getHeight(); + if (type == "pdf") + surface = Cairo::PdfSurface::create(filename,width,height); + else if (type == "svg") + surface = Cairo::SvgSurface::create(filename,width,height); + else if (type == "ps") + surface = Cairo::PsSurface::create(filename,width,height); + else if (type == "ARGB32") + surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32,width,height); + else if (type == "RGB24") + surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24,width,height); + else + throw ImageWriterException("unknown file type: " + type); + Cairo::RefPtr context = Cairo::Context::create(surface); + + // TODO - expose as user option + /* + if (type == "ARGB32" || type == "RGB24") + { + context->set_antialias(Cairo::ANTIALIAS_NONE); + } + */ + + + mapnik::cairo_renderer ren(map, context); + ren.apply(); + + if (type == "ARGB32" || type == "RGB24") + { + surface->write_to_png(filename); + } + surface->finish(); + } + } + +#endif template void save_to_file(image_data_32 const&, std::string const&,