Making Gimp 3.0 GEGL calls a bit less verbose in Python

Calling GEGL ops is a bit verbose but you can hide a lot of the complexity in a single function. And in Python, keyword arguments can be retrieved as a dictionary in the callee, so can be iterated. So, a first shot:

# Sample function to apply a GEGL operation on one drawable
def applyGeglOnBuffers(bufferIn,bufferOut,opName,**kwargs):
    graph=Gegl.Node()
    source=graph.create_child("gegl:buffer-source")
    source.set_property('buffer',bufferIn)
    sink=graph.create_child("gegl:write-buffer")
    sink.set_property('buffer',bufferOut)
    operation=graph.create_child(opName)
    # Iterate named arguments, converting names_with_underscores to names-with-dashes
    for name,value in kwargs.items():
        operation.set_property(name.replace('_','-'),value)
    source.link(operation)
    operation.link(sink)
    sink.process()
    bufferOut.flush()

Used like this in the code:

    sizeX=config.get_property('sizeX')
    sizeY=config.get_property('sizeY')

    Gegl.init()
    layer=drawables[0]
    selected,x,y,w,h=layer.mask_intersect()
    if selected:
        # kwarg names should match the GEGL properties (_/- conversion done in the function)
        applyGeglOnBuffers(layer.get_buffer(),layer.get_shadow_buffer(),'gegl:gaussian-blur',std_dev_x=sizeX,std_dev_y=sizeY)
        layer.merge_shadow(True)
        layer.update(x,y,w,h)
1 Like

Thanks a lot for that.
Just tried it out and find it very useful. :clap:

1 Like

Yes, thanks for that. Just used your suggestion to resurrect edge detection using gegl:edge and it worked beautifully. I realised that since we are are using kwargs it was possible to set default arguments for the parameters which for some operations would reduce the verbosity even more eg here it was just “border_behaviour” which defaults to “Clamp”.

Thought about that but

  • the GEGL ops already have default args, so you don’t need to provide those for which the default is OK
  • the same arg (by name) could need different default values in different ops anyway.

I’m working on a slightly more powerful version of this that allows chaining of several ops and starting from a “render” (ie, no source layer),

I prefer JSON format for the arguments

**{"name1":value1, "name2":value2}

The advantage is you can use a hyphen in the name and don’t have to change it to underscore.

applyGeglOnBuffers(drawable.get_buffer(), drawable.get_shadow_buffer(), 'gegl:color-to-alpha', **{"color":color, "transparency-threshold":0.0, "opacity-threshold":1.0})

Yes, but that’s more quoting, and since you are using a dictionary explicitly the keys can be arbitrary so the IDE can’t even do a sanity check.