Cairo: using a SVG as a shape (or Cairo Groups)

gtkPythonArco

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… Sticking out tongue 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. Smiling And that’s all, folks!
Thanks for reading.

PD: This is my first post in English, please, don’t take this into account…

Sources

References

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Lk2's picture

What is going up? Have you

What is going up? Have you finished writting recipes in Spanish? Sticking out tongue

oscarah's picture

Nop

But, as a test, I thought that this recipe would be shorter in English than in Spanish... but, as we don't have support for i18n, we'll never know... Sticking out tongue

"aviso: la dereferencia de punteros de tipo castigado romperá las reglas de alias estricto" --GCC 4.3.1

david.villa's picture

Please, fix the

Please, fix the drupal internationalization features so that we are able to create both versions. Smiling

No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.