How to write a GIMP plug-in, part I

Written By Dave Neary.

In this article, I present GIMP plug-ins basics and introduce the libgimp API. I will also show how to use the PDB to make our plug-in available to other script authors.

Introduction

New developers are often intimidated by The GIMP size and its reputation. They think that writing a plug-in would be a difficult task. The goal of these articles is to dumb this feeling down, by showing how easily one can make a C plug-in.

In this part, I present a plug-in’s basic elements. We will see how to install a plug-in and how to get data from an image and directly manipulate it.

Architecture

Architecture

The GIMP script interface is centered on the Procedural database (PDB). At startup, The GIMP looks into a predefined set of places for scripts and plug-ins, and asks each new script to identify itself.

The plug-in declares itself to the PDB at that time, and passes informations like the position it wishes to get in the menu hierarchy, input parameters, and output parameters.

When a script or a plug-in wants to use our plug-in, it gets through the PDB, which manages communicating parameters in one direction and the other in a transparent way.

Internal functions that wish to get exposed to plug-ins have to be packaged first in the core, that will register them in the PDB, and secondly in the libgimp that will allow the function to be called as a normal one.

This was the introduction - now, we will look closer at our first plug-in, a “Hello, world!”.

Compiling the plug-in

To be able to compile simple plug-ins for The GIMP, one needs libgimp headers, as well as an associated utility named gimptool.

With that utility, one can install a plug-in either in a private directory (~/.gimp-2.0/plug-ins), or in the global plug-in directory.

Syntax is

gimptool-2.0 --install plugin.c or gimptool-2.0 --install-admin plugin.c

This utility, with other options, can also be used to install scripts, or uninstall plug-ins.

Behaviour

A GIMP plug-in can typically behave three different ways. It can take image data, modify it, and send back the modified image, like edge detection. It can generate an image and send it back, like some script-fus, or file reading plug-ins like jpeg. Or it can get an image, and process it without modifying its data, like a file saver plug-in.

Essentials

#include <libgimp/gimp.h>

This header makes all basic plug-in elements available to us.

GimpPlugInInfo PLUG_IN_INFO = {
	init,
	quit,
	query,
	run
};

This structure has to have that name. It contains four pointers to functions, which will be called at set times of the plug-in life. init and quit are optional, and thus can hold NULL values, but the last two functions, query and run, are mandatory.

The init() function is called each time The GIMP starts up. This function is not typically used. Some plug-ins use it to make a secondary search that is not done by the core. This function is not used by any standard GIMP plug-in, but could be useful for example for a plug-in that would like to register some procedure conditionally on some files presence.

The quit() function is not used much either. It is called when The GIMP is about to be closed, to allow it to free some resources. It is used in the script-fu plug-in.

The query() function is called the first time the plug-in is present, and then each time the plug-in changes.

The run() function is the plug-in’s centrepiece. It is called when the plug-in is asked to run. It gets the plug-in name (as a plug-in can register several procedures), input parameters, and a pointer to output parameters, then determines if it is launched in a interactive way or by a script, and does all the plug-in processing. Its prototype is

void run (const gchar      *name,
        gint              nparams,
        const GimpParam  *param,
        gint             *nreturn_vals,
        GimpParam       **return_vals);

MAIN ()

MAIN is a C macro that holds a bit of dark magic to initialise arguments. It also calls the appropriate PLUG_IN_INFO function depending on the timing. Your plug-in needs it.

The query() function

query() deals with the procedure registration and input arguments definition. These informations are saved to speed up startup time, and refreshed only when the plug-in is modified.

For our “Hello, world!” plug-in, the query function will look like this:

static void
query (void)
{
  static GimpParamDef args[] = {
    {
      GIMP_PDB_INT32,
      "run-mode",
      "Run mode"
    },
    {
      GIMP_PDB_IMAGE,
      "image",
      "Input image"
    },
    {
      GIMP_PDB_DRAWABLE,
      "drawable",
      "Input drawable"
    }
  };

  gimp_install_procedure (
    "plug-in-hello",
    "Hello, world!",
    "Displays \"Hello, world!\" in a dialog",
    "David Neary",
    "Copyright David Neary",
    "2004",
    "_Hello world...",
    "RGB*, GRAY*",
    GIMP_PLUGIN,
    G_N_ELEMENTS (args), 0,
    args, NULL);

    gimp_plugin_menu_register ("plug-in-hello",
                               "<Image>/Filters/Misc"); 
}

GimpParamDef contains three things - the parameter type, its name, and a string describing the parameter.

gimp_install_procedure declares the procedure name, some description and help strings, menu path where the plug-in should sit, image types handled by the plug-in, and at the end, input and output parameters number, as well as the parameters descriptors.

RGB*, GRAY*” declares the image types handled. It can be RGB, INDEXED or GRAY, with or without Alpha. So “RGB*, GRAY*” describes RGB, RGBA, GRAY or GRAY image type.

GIMP_PLUGIN declares this procedure to be external, and not to be executed in The GIMP core.

By adding a stub run function now, we can check that our plug-in has all the essential elements, and test that it registers itself in the PDB with the “Xtns->Plug-in Details” plug-in.

Plug-in details

Plug-in details

Plug-in menu

Our plug-in is in the menus

The run() function

The other required function for PLUG_IN_INFO is run. The core of the plug-in stands there.

Output values (return_vals in the prototype) must have at least one value associated - the plug-in status. Typically, this parameter will hold “GIMP_PDB_SUCCESS”.

Run-modes

One can run a plug-in in several different ways, it can be run from a GIMP menu if The GIMP is run interactively, or from a script or a batch, or from the “Filters->Repeat Last” shortcut.

The “run_mode” input parameter can hold one of these values: “GIMP_RUN_INTERACTIVE”, “GIMP_RUN_NONINTERACTIVE” or “GIMP_RUN_WITH_LAST_VALS”.

GIMP_RUN_INTERACTIVE” is typically the only case where one creates an options dialog. Otherwise, one directly calls the processing with values from input parameters or from memory.

For our test plug-in, we will simply display a dialog containing a “Hello, world!” message. Thankfully, this is really easy with GTK. Our run function could be:

static void
run (const gchar      *name,
   gint              nparams,
   const GimpParam  *param,
   gint             *nreturn_vals,
   GimpParam       **return_vals)
{
static GimpParam  values[1];
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
GimpRunMode       run_mode;

/* Setting mandatory output values */
*nreturn_vals = 1;
*return_vals  = values;

values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = status;

/* Getting run_mode - we won't display a dialog if 
 * we are in NONINTERACTIVE mode */
run_mode = param[0].data.d_int32;

if (run_mode != GIMP_RUN_NONINTERACTIVE)
  g_message("Hello, world!\n");
}

Now, when we run our plug-in, there is action:

Hello, world!

Have a look at the full hello.c plug-in code.

Next part

In next part we will go on, making a more useful plug-in that will get its hands on image data. We will see how to use The GIMP image architecture to make the plug-in perform better, processing the image tile by tile.

Creative Commons
License

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.