Combining PySide and PyGObject introspection bindings

Some while back I added basic GObject Introspection support to GEGL and GEGL-GTK master a while back. This will* allow application developers to write their Gegl + Gtk based applications in any language supported by GObject Introspection, like Python, Vala and Javascript. For GeglQt, the Qt integration library for using Gegl in Qt based applications, it was natural to use PySide to provide Python bindings for it. The initial setup was quick and easy, thanks to the binding tutorial, but there was one challenge.

The current widgets provided by GeglQt are for displaying the output of a node in the GEGL graph. Therefore they have methods with the following signature to hook up it up:

From gegl-qt/nodeviewwidget.h
GeglNode *inputNode() const;
void setInputNode(GeglNode *node);

GeglNode is a GObject (from the C based glib) subclass, and without help the bindings generator (Shiboken) does not know what to do with it so the method cannot be bound. PySide could have been used to also generate bindings for Gegl itself, but what we actually want to do is to make use of the existing PyGObject based bindings.

Marcelo Lira on #pyside let me know that this should be possible by adding some annotations to the typesystem.xml file, and implementing a Shiboken::Converter<T>. It is indeed possible, and for the above type looks something like this:

From typesystem_gegl-qt.xml
<primitive-type name="GeglNodePtr">
      <conversion-rule file="geglnode_conversions.h"/>
      <include file-name="pygobject.h" location="global"/>
</primitive-type>

From geglnode_conversions.h
namespace Shiboken {
template<>
struct Converter<GeglNodePtr>
{
    static inline bool checkType(PyObject* pyObj)
    {
        return GEGL_IS_NODE(((PyGObject *)pyObj)->obj);
    }

    static inline bool isConvertible(PyObject* pyObj)
    {
        return GEGL_IS_NODE(((PyGObject *)pyObj)->obj);
    }

    static inline PyObject* toPython(void* cppObj)
    {
        return pygobject_new(G_OBJECT((cppObj)));
    }

    static inline PyObject* toPython(const GeglNodePtr geglNode)
    {
        return pygobject_new(G_OBJECT(geglNode));
    }

    static inline GeglNodePtr toCpp(PyObject* pyObj)
    {
        return GEGL_NODE(((PyGObject *)pyObj)->obj);
    }
};
}

The PyGObject C API and the GObject type system is here being used to implement what Shiboken needs. The attentive reader will note that GeglNodePtr is used and not GeglNode*. This is a simple “typedef GeglNode * GeglNodePtr“, which looks to be neccesary with current PySide (1.0.6) to avoid it being confused by the pointer. Hopefully that is fixable and won’t be necessary in the future.

With this solved, I committed the initial Python support to GeglQt master yesterday. It contains a trivial Python example showing the usage. Some build cleanups, binding generator tweaks and testing remains to be done, but expect Python support to be a prominent feature for GeglQt 0.1.0

 

* There are still a lot of GObject Introspection annotations missing in Gegl. See the tracking bug. Help wanted!

Making GEGL easier to use in graphical applications

So, in the last couple of months I’ve been working a bit on GEGL. Some of the work has already been covered by LWN, so I guess it is time that I blog about it…

GEGL is a generic image processing library which is used by applications like GIMP, (and in the future maybe MyPaint and DarkTable). It provides applications with a graph based image processing backend that can do non-destructive processing of high-bitdepth images, among other things.

One of the problems that I think has been limiting adaptation of GEGL has been the entry barrier to starting to use it in a graphical application. While GEGL provides the image processing backend, it did not provide good and easy ways of displaying the output on screen. Now it does!

GTK+, Clutter and Qt integration libraries

Some code for integrating GEGL in GTK+ based applications has existed in the GEGL tree for a long time, but it was not well maintained and there was no public API. After brushing up the code to use Cairo for rendering and to support both GTK+ 2 and 3, it was split out to a separate library and repository: gegl-gtk. This library now provides a GtkWidget for displaying the output of a node in the GEGL graph, with basic support for scaling and translations. Any change in the GEGL graph will be reflected in the view widget. This makes it trivial for applications using a GTK+ based user interface to get started using GEGL, see for instance the provided examples in C or in Python.

The same functionality is provided for Clutter based user interfaces by gegl-clutter in form of a ClutterActor. This code was previously available as clutter-gegl, but has now been renamed and moved to be a part of the GEGL project, and is maintained by Øyvind Kolsås. Example code in C.

Last but not least, gegl-qt was created to serve the needs of applications using Qt based user interfaces. The different widget systems (QWidget-, QGraphicsWidget- and QML-based) are all supported. In addition to the features currently available in the GTK+ and Clutter versions, the Qt view widgets also support auto-scaling and auto-centering. Python bindings via PySide is planned, but blocking on a PySide issue at the moment.

A pretty boring screenshot showing two QWidget based examples (code: 1, 2) for transformations:

Artwork: “Wanted“, speedpainting by David Revoy

The first stable release of gegl-qt and gegl-gtk will hopefully be available soon. The list of tasks can be found in the README files.

Display operations

In GEGL, image processing is described as a graph of operations. “gegl:display” and “gegl:gtk-display” operations existed in the gegl tree, and by attaching one of these to a node in the graph one could display the output of the graph at the given node in a window . Such display operations are useful for applications that just want to show the output of a graph without having to use a GUI library directly.

The problem was that both of these operations were optional, so applications could not rely on this functionality to be present. This is solved by letting the “gegl:display” operation be a meta-operation, which uses other operations as a handler to actually display the output. Such display handler operations are now provided by gegl (optional, using SDL), gegl-gtk (using GTK+) and gegl-qt (using Qt). In addition a fallback operation that will export a PNG file and launch an external application to display it will be provided in GEGL.

More to GEGL stuff to come soon, hopefully.