Cairo: using a SVG as a shape (or Cairo Groups)
In this recipe, we will create a shape, or a Surface using Cairo verbs, from an image in SVG format.
Ingredients
You’ll need:
- python
- python-cairo
This packages are very common, so you may probably have them installed.
First of all: the Gtk skeleton
This code is very simple. If you aren’t used to working with Gtk, please, see one of the manuals on the Internet…
The target is to have a Cairo Context, the main object to draw things on Cairo. This is easy, as we have an useful method on gtk.gdk.window that does the work for us: cairo_create(). The window we are going to use is inside a DrawingArea, so:
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
import gtk
import cairo
class Test:
def __init__(self):
mw = gtk.Window(gtk.WINDOW_TOPLEVEL)
mw.connect("delete-event", gtk.main_quit)
mw.set_size_request(400, 400)
da = gtk.DrawingArea()
da.connect("expose_event", self.on_expose)
mw.add(da)
# Source image, loaded as a pixbuf
self._img = gtk.gdk.pixbuf_new_from_file("photos.svg")
mw.show_all()
if __name__ == "__main__":
t = Test()
try:
gtk.main()
except KeyboardInterrupt:
gtk.main_quit()
Ok. Nothing new until here. I’ve loaded the SVG using a gtk.gdk.pixbuf because Cairo can use this as a source, so drawing it is simple. Moreover, I’ve connected the expose_event of the drawing area to a method of Test.
Now, drawing time
Take a look into the method on_expose():
def on_expose(self, widget, event):
cr = widget.window.cairo_create()
# Normal image
cr.set_source_pixbuf(self._img, 175, 50)
cr.paint()
# Black shape of same image
cr.push_group()
cr.set_source_pixbuf(self._img, 175, 150)
cr.paint()
src = cr.pop_group()
cr.set_source_rgb(0, 0, 0)
cr.mask(src)
# Blue shape of same image, with alpha
cr.set_source_pixbuf(self._img, 175, 250)
cr.paint()
cr.push_group()
cr.set_source_pixbuf(self._img, 175, 250)
cr.paint()
src = cr.pop_group()
cr.set_source_rgba(.5, .5, 1, .4)
cr.mask(src)
As you can see, there are three drawn things. The first one is the SVG as is, using a plain paint() method. Easy. The result may be:

Of course, without the border and the shadows… :p The second item we see is more interesting. I’m going to use the alpha channel in the original SVG as a mask: where the image is transparent, nothing is drawn, so only the opaque pixels are used to paint. To achieve this, I’m using a feature of Cairo called groups. A group is like a layer where you can draw things. The difference is that this ‘layer’ can be used later as a pattern or as a surface.
This time, I’ll only paint in black, which gives this:

¡Voilá! As you can imagine, if you use other color, blue for example, and paint with alpha enabled, you could get something like a shinning effect, like this:

which is the third item in our example. :) And that’s all, folks!
Thanks for reading.
PD: This is my first post in English, please, don’t take this into account…