Calling Filters from Plug-Ins

[Theory] Introduction

If you also read the How to write a filter tutorial, you know that filters in GIMP are GEGL operations.

There are a few ways to work with these in a plug-in. One of these ways is to request a GeglBuffer with gimp_drawable_get_buffer() and directly use GEGL API on this buffer. This is very powerful as you have the full API access. You can not only run filters, but also iterate directly through the buffer, in any color format you wish to.

Now it also has limitations regarding the specific usage in GIMP:

  • It requires working on the plug-in side;
  • It may not be as efficient;
  • You don’t have access to some specific filters which are only available in our codebase, such as "gimp:curves", "gimp:color-balance", "gimp:levels", all layer mode operations, and many more;
  • You cannot create non-destructive filters.

Therefore this tutorial will not talk much further about this possibility. You may look up a GEGL tutorial if you want to do this. Instead we will show specific libgimp API to run filters, especially for the non-destructive use cases.

[Code] Applying a Filter Non-Destructively in C

Let’s say I want to run "zemarmot:hello-world-meta" filter we created in the filter tutorial.

In C, this is basically a one-liner with the variable-length arguments function gimp_drawable_append_new_filter():

  gimp_drawable_append_new_filter (drawable, "zemarmot:hello-world-meta",
                                   "Hello World", GIMP_LAYER_MODE_REPLACE, 1.0,
                                   "text",         "Hello World!",
                                   "compute-size", FALSE,
                                   "font-size",    100.0,
                                   NULL);

As expected, when not setting an argument, the default value is implied.

The return value is the appended GimpDrawableFilter, which can be further edited if needed.

You may also be interested into the counterpart function gimp_drawable_merge_new_filter() which immediately merge the render onto the drawable, hence works destructively. As a consequence, no GimpDrawableFilter object is returned.

[Code] Applying a Filter Non-Destructively in Python

Now you probably already guessed that this won’t work in Python because of the lack of introspection for varargs functions. This is the slightly longer variant for Python:

  filter = Gimp.DrawableFilter.new(drawable, "zemarmot:hello-world-meta", "Hello World")
  filter.set_blend_mode(Gimp.LayerMode.REPLACE)
  filter.set_opacity(1.0)
  config = filter.get_config()
  config.set_property('text', 'Hello World!')
  config.set_property('compute-size', False)
  config.set_property('font-size', 100.0)
  filter.update()
  drawable.append_filter(filter)

You may recognize a very similar logic as how we would run PDB procedures. The config object is again from a subclass of GimpDrawableFilterConfig generated on-the-fly with all the arguments of the called filter.

Note that any argument update to this config object is not immediately transmitted to the core process. Instead all the changes are sent at once when calling gimp_drawable_filter_update().

This doesn’t really change anything here, but it would if the filter had already been applied and you want to update its arguments without re-rendering at every argument change.

[Code] Applying a Filter Non-Destructively in Script-Fu

Script-Fu has its own special binding around the gimp_drawable_append_new_filter() function:

(gimp-drawable-append-new-filter 2 "zemarmot:hello-world-meta" "hello world" LAYER-MODE-REPLACE 1.0
                                 #:text         "Hello World!"
                                 #:compute-size 0
                                 #:font-size    100.0)

You may recognize the special named argument syntax (#:arg), as for calling plug-in PDB procedures which mainly implies that you do not have to set all arguments and can set them in any order. And just as the C function, this returns a GimpDrawableFilter which you may further work on. This makes it quite similar to the libgimp C function!

Very similarly a (gimp-drawable-merge-new-filter) binding exists, which does not return any GimpDrawableFilter.

Conclusion

The simplicity on running any type of filter in the 3.0 API is one of the huge improvements over libgimp v2 API, as we used to only be able to work directly with GEGL API on plug-in side.

Furthermore it used to be only available to compiled plug-ins. Now it works for any GObject-Introspected binding and even in Script-Fu.

To go further, the libgimp API reference will help you figure out all advanced usage.

(H)API hacking!