I use the python rsvg
bindings to render an svg image into cairo and save to file, which mostly works. But if the svg file contains a linked image, like so:
The answer was to process the links to start with file:///
and be a full absolute path.
There are many factors which must be satisfied for LibRsvg to allow an image resource to be loaded. As of v2.40 these include:
xlink:href
attributedata://
or file://
file://
paths must be absolutefile://
paths must be in or below the path of the SVG source file (after any symlinks have been dereferenced)Note that if input is passed to rsvg-convert
via stdin, then no paths count as subdirectories of the input file and all file://
images will be denied.
rsvg-convert < input.svg > output.png # images denied
rsvg-convert -o output.png input.svg # images allowed
The code governing image URL resolution can be found in the LibRsvg source in rsvg-base.c
, function _rsvg_handle_allow_load
.
To add a debugging notification to rsvg-convert when image loading fails, one can append
#define G_ENABLE_DEBUG
to config.h
in the source and recompile.
It seems that, if the file you are including is not on the same path or under the path of the SVG file you want to convert, it will not find it. I regard this as a bug.
I wanted to get librsvg image rendering working on my Mac to speed up SVG rendering. Ian Mackinnon's great answer has all the ingredients but implementing a change to the library is tricky. These steps made librsvg correctly render linked images with relative paths. I hope this saves someone some time.
First, I installed librsvg using:
brew install --build-from-source librsvg
At the time of writing, this installs version 2.40.13 and the necessary libraries to build it. I then downloaded and extracted the source archive into my home directory:
wget https://download.gnome.org/sources/librsvg/2.40/librsvg-2.40.13.tar.xz
tar jxvf librsvg-2.40.13.tar.xz
cd librsvg-2.40.13
I edited the _rsvg_handle_allow_load
function in rsvg-base.c
in this directory to bypass the path loading restrictions by adding this code around line 2275:
2275
2276 goto allow; // Just try and load it!
2277
I also needed to edit the rsvg_cairo_surface_new_from_href
function in rsvg-image.c
and stop it loading using mime types - just replace the function like this:
55 if (mime_type) {
56 // loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error); // This doesn't work on my mac
57 loader = gdk_pixbuf_loader_new (); // This works
58 } else {
59 loader = gdk_pixbuf_loader_new ();
60 }
I needed to use these slightly modified commands to compile and install the modified library:
make clean
make install gdk_pixbuf_binarydir=/usr/local/Cellar/librsvg/2.40.13/lib/gdk-pixbuf-2.0/2.10.0/loaders gdk_pixbuf_moduledir=/usr/local/Cellar/librsvg/2.40.13/lib/gdk-pixbuf-2.0/2.10.0/loaders
Depending on your system, you might need to add sudo to the above commands.
Once this was done, I could render relative SVG links using the rsvg-convert
command line tool that is installed with librsvg:
rsvg-convert test.svg -o test.png
I was also able to use ImageMagick to convert SVGs with relative image links to PNG files if I installed it after installing librsvg in this way:
convert test.svg test.png
This will let you test rsvg function and performance - I found it was 2-3x faster than Inkscape for my application. I recommend changing the code more intelligently if you use this in a production environment.