pyrsvg

How to use librsvg from Python

It finally took me an entire installation of a new O/S and "locate .py | grep rsvg"(*) on my drive to find what I could not find via google : how to open an SVG file and draw it from PyCairo.

I had to upgrade my O/S (to Gnu/Linux Kubuntu 7.10) in order to get the latest Python-gnome2-* packages for, buried in there, is a Python wrapper for librsvg. I don't know why it's not a stand-alone wrapper like PyCairo, but that's the way it is.

The first demo is directly from the example I found on my drive.

(*) You can find this demo in /usr/share/doc/python-gnome2-desktop/examples/rsvg on *buntu Gutsy 7.10

#!/usr/bin/env python

import sys
import cairo
import rsvg
import gtk


BORDER_WIDTH = 10


def delete_cb(win, event):
    gtk.main_quit()


def expose_cairo(win, event, svg):

    x, y, w, h = win.allocation
    cr = win.window.cairo_create()
    cr.set_source_color(win.style.fg[win.state])
    cr.rectangle(BORDER_WIDTH, BORDER_WIDTH,
                w - 2*BORDER_WIDTH, h - 2*BORDER_WIDTH)
    cr.set_line_width(5.0)
    cr.set_line_join(cairo.LINE_JOIN_ROUND)
    cr.stroke()

    if svg != None:
        matrix = cairo.Matrix(3,0,0,3,0, 0)
        #cairo.Matrix.rotate( matrix, prop.rot )
        cr.transform (matrix)
        svg.render_cairo(cr)

    return True

def main():
    win = gtk.Window ()
    win.connect("delete-event", delete_cb)

    svg = None
    if (len (sys.argv) > 1):
        svg = rsvg.Handle(file=sys.argv[1])
    else:
        raise SystemExit("need svg file")

    win.connect("expose-event", expose_cairo, svg)

    print svg.props.width, svg.props.height, svg.props.em, svg.props.ex

    win.show_all()
    win.connect("destroy", lambda w: gtk.main_quit())
    gtk.main()

if __name__ == '__main__':
    main()

Writing an SVG file

I thought I'd see how writing out an SVG file from Cairo works, this is a short example.

import cairo
import rsvg
import math

fo = file('test.svg', 'w')

WIDTH, HEIGHT  = 256, 256

## Prepare a destination surface -> out to an SVG file!
surface = cairo.SVGSurface (fo, WIDTH, HEIGHT)

## draw something - this taken from the web.
ctx = cairo.Context (surface)
ctx.scale (WIDTH/1.0, HEIGHT/1.0) # Normalizing the canvas
pat = cairo.LinearGradient (0.0, 0.0, 0.0, 1.0)
pat.add_color_stop_rgba (1, 0.7, 0, 0, 0.5) # First stop, 50% opacity
pat.add_color_stop_rgba (0, 0.9, 0.7, 0.2, 1) # Last stop, 100% opacity
ctx.rectangle (0, 0, 1, 1) # Rectangle(x0, y0, x1, y1)
ctx.set_source (pat)
ctx.fill ()
ctx.translate (0.1, 0.1) # Changing the current transformation matrix
ctx.move_to (0, 0)
ctx.arc (0.2, 0.1, 0.1, -math.pi/2, 0) # Arc(cx, cy, radius, start_angle, stop_angle)
ctx.line_to (0.5, 0.1) # Line to (x,y)
ctx.curve_to (0.5, 0.2, 0.5, 0.4, 0.2, 0.8) # Curve(x1, y1, x2, y2, x3, y3)
ctx.close_path ()
ctx.set_source_rgb (0.3, 0.2, 0.5) # Solid color
ctx.set_line_width (0.02)
ctx.stroke ()

## Do the deed.
surface.finish()

You can use 'svgdisplay' (if you have the binary), Inkscape, Firefox or the first demo app to view test.svg

A feedback loop

What happens when you feed the snake it's tail?

import cairo
import rsvg

fo = file('test.svg', 'w')

WIDTH, HEIGHT  = 256, 256
surface = cairo.SVGSurface (fo, WIDTH, HEIGHT)

ctx = cairo.Context (surface)

svg = rsvg.Handle(file="test2.svg")
svg.render_cairo(ctx)

surface.finish()

Well, it works! test.svg comes in and comes out as test2.svg. I don't think it proves anything, but it's fun.