Saving the image drawn with Cairo on a GtkLayout or GtkDrawingArea using a pixbuf

In my previous post, I discussed how to get the draw() event to fire for Gtk3 widgets in order to draw on them using cairo, specifically the GtkLayout and GtkDrawingArea widgets. Since that time I’ve had some success writing code to plot data from a connected source meter (through the RS232 port) in real time. I got stuck again trying to save the image drawn on the GtkLayout to a file. Most of the material I found on the internet wasn’t up to date and not relevant for the GTK3 framework. Finally I figured out how to save the image and it’s pretty easy to do too.

The solution is to get a GdkPixbuf from the widget’s GdkWindow and use the GdkPixbuf’s .savev() method to write the image to disk. For some reason, when I use the .get_window() method of GtkWidget’s, I don’t get a GdkWindow returned but rather a GdkX11Window object (gtk.gdk.X11Window). I’m not sure why there’s a difference but it seems to be ok to feed this into the Gdk.pixbuf_get_from_window() function. Please note that you must use the .savev() method of the pixbuf. Most sources online use the .save() method but that seems to be gone in Gtk3 (or perhaps there is no python binding?).

For example, assume you have a GtkLayout stored in the variable layout (I find mine with layout = self.builder.get_object(‘mylayout’) – because I’m using Glade). To capture an image of the layout and whatever you’ve drawn on it, you would do the following:

pixbuf = Gdk.pixbuf_get_from_window(layout.get_window(), 0, 0, width, height)
pixbuf.savev("foobar.png","png", [], [])

In this example, width and height need to be the width and height of the widget. The rectangular area defined by (0,0) to (width, height) is saved. In my case, I did something like this:

rect = layout.get_allocation()
width = rect.width
height = rect.height

In the .savev() method, the first argument is the file name, the second is the type, and the third and forth options are arrays of options and their settings. I pass empty arrays because I don’t set any options.

Note that this works with GtkLayout and should work with GtkDrawingArea and GtkWindow. For other widgets, the window returned by .get_window() seems to be that of the parent GtkWindow. If you want to capture an image of those wigdets, you’ll need to specify the x,y position of their top left corners in the Gdk.pixbuf_get_from_window() call.

layout

Leave a Reply

Your email address will not be published. Required fields are marked *