[cairo] Cairo and layered application

Gauthier Quesnel quesnel at lil.univ-littoral.fr
Fri Mar 2 03:34:07 PST 2007


Le Wed, 28 Feb 2007 17:00:47 -0800,
"Daniel Amelang" <daniel.amelang at gmail.com> a écrit :

> 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,

Hello !

> 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.

I look for a method or a functionality to save the layers between two
calls of the gtk expose_event. I wanted to attach, to each layer, a
gdk.pixmap but the fusion of gdk.pixmap does not manage
transparency. The cairo_surface seems to be a solution thank you :)

> 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.

As users can change the colours or the visibility of each surfaces (ie.
the grid and the background), all of them must be different layers.

For grid, move_to() and line_to() are better, thx :)

> 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.

Each matrix layer represent a field of values:

- coast zone, 0 for the sea (transparent) and 1 to the earth (black
rectangle),
- fish concentration, value from 0.0 (transparent) to 1.0 with gradient
of colour,
- etc.

The user can display information by:
- fusion of various layers,
- display or not a layer.

For certain layers, the user can modify information (colours, or add
value directly into a cell).

For instance: http://www.epic.noaa.gov/java/ncBrowse/screen-6_full.gif

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

It's fixed, thx :)

> 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.

Yep, my sources are GPL (require pygtk 2.10 and numpy):
http://vle.univ-littoral.fr/gitweb?p=goo.git;a=summary

With Cogito/Git tools:
cg-clone http://vle.univ-littoral.fr/goo.git
git-clone http://vle.univ-littoral.fr/goo.git

> Dan

Gauthier.


More information about the cairo mailing list