[cairo] Cairo and layered application

Daniel Amelang daniel.amelang at gmail.com
Wed Feb 28 17:00:47 PST 2007

On 2/27/07, Gauthier Quesnel <quesnel at lil.univ-littoral.fr> wrote:
> Hi all,
> I want to build an application which display some layers on a
> gtk.drawingarea like gimp or inkscape for instance, where each layer
> have an opacity value. Their is three types of layer:
> Background (to fill the pixmap with a colour):
>         cairo.save()
>         cairo.set_source_rgb(self.__red, self.__green, self.__blue)
>         cairo.set_operator(cairo.OPERATOR_SOURCE)
>         cairo.paint()
>         cairo.set_operator(cairo.OPERATOR_OVER);
>         cairo.restore()
> A Grid (to draw a grid on the background layer):
>         cairo.save()
>         cairo.set_source_rgb(self.__red, self.__green, self.__blue)
>         cairo.set_line_width(1)
>         cellwidth = width / self.column
>         cellheight = height / self.row
>         for j in range(self.row):
>             for i in range(self.column):
>                 cairo.rectangle(i * cellwidth, j * cellheight, width /
>                         self.column, height / self.row)
>         cairo.stroke()
>         cairo.restore()
> And the Matrix layer (a numpy array of float) which can be modified by
> the user (mouse click):
>         cellwidth = width / self.table.column
>         cellheight = height / self.table.row
>         cairo.save()
>         for j in range(self.table.row):
>             for i in range(self.table.column):
>                 value = self.table.get(i, j)
>                 cairo.set_source_rgb(self.r * value, self.g * value,
>                         self.b * value)
>                 cairo.rectangle(i * cellwidth, j * cellheight,
>                         cellwidth, cellheight)
>                 cairo.fill()
>         cairo.stroke()
>         cairo.restore()
> With this technique, renders are very slow with five matrix of
> 40x40. I have added a gdk.pixmap to make a double buffer (all layers
> are only redraw on configure event and not expose event).
> I would liked to attach every cairo_context a gdk.pixmap object in
> order to compute only the layer modified by the user. But it seems not
> possible with the gdk.pixmap object.
> Have-you a solution to optimize this type of application?

Hello Gauthier,

The gimp-like layers that you're describing are usually implemented as
cairo surfaces, which can then be composed together as needed. It
sounds like you could draw the background color and the grid just once
to an intermediate cairo surface (a cache of sorts) that is painted
onto the window each time you need to draw it. No need for a gdk
pixmap here, just a cairo surface. Look into
cairo_surface_create_similar as the means for creating this
intermediate surface.

Now, if for whatever reason you have to redraw your grid each time,
you could get some speedup by drawing your grid using lines instead of
drawing each cell as a rectangle. Also, moving the cairo_stroke call
into the inner-most part of your loop will get you a minor speed up,
too. It may seem counter-intuitive, but it actually does help.

I don't really follow what you're doing with your matrix drawing
code...it could be possible to get the same effect without so many
rectangle calls. Do you really expect to draw that many different
colored rectangles? Maybe so, but I'd need to have a better overall
picture of what you're doing.

You seem to have an unecessary cairo_stroke at the end of your matrix
drawing code. Not that it should affect performance at all.

Having said all that, for drawing as simple as yours, I wouldn't
expect the need for any optimization. Would you care to share your
code with us? If you give us something that we can run, it makes it
easier to analyze where the performance problems are.


More information about the cairo mailing list