Skip to content


In GIMP we can use script-fu or, more generally, any other GIMP scripting-language to re-create an effect over a drawable we already tested in a manual way.
We can create an effect in two ways.
One - the static one - is like using a macro-events scripting language, as someone could have seen under Windows in Photoshop or Word; instructions are sequential and the result is straight-forward. In this case the programming flow is linear, i.e. the program interpreter parses one code line after the other until the end of the script.
A more complex and interactive way - the other way - of programming a filter for GIMP is taking decisions dynamically, in other words controlling the programming flow.
One of the simplest way of using such a method is, for example, to check whether the image is in a particular mode (RGB, Indexed,...) and prompt the user an error message, or modifying the image mode.

  (if (= (gimp-drawable-type InLayer) RGBA)
  (gimp-message "error"))
As we can see the only super-type of LISP (the script-fu mother language) is the list and we can consider all the other LISP programming elements as sub-types of it.
In fact the LISP parser takes its decisions based on a list of sub-types; the first element of this list determines the action to be taken, the rest of the list is (usually) a collection of options.
In our case the IF clause has this general syntax:

  (if (control-statement) expression(s))
We should be aware that the LISP-parser, once it encounters the IF clause, evaluates the second element of this list (usually enclosed in brackets). The control-statement should return a boolean value and if it is TRUE the parser executes the expression(s) (the remaining elements of the list) otherwise it will skip them. So the control-statement can be any equivalence expression like

  (< x y)
or

  (= x y)
or any boolean value or any function that returns a boolean value (TRUE or 1; FALSE or any not-1 number).
As we saw the if clause creates a sort of diversion in the programming flow that will execute once a code segment.
But what to do if we need to repeat an action 'n' times?
Any programming language has several methods to create a LOOP. Here we will take a look at WHILE loops.
The general syntax for it, is something like:

  (while (control-statement) expression(s) )
where the expression(s) will be executed until the control-statement is true.

  (let* (
    (k 0)
    (rv 0))
    (while (k <= 10)
      (set! rv (+ rv 2))
      (set! k (+ k 1))))
In this classical example we first inizialize two values, k and rv, to 0, the first is used as a control-value (a sort of counter) for the iteration, the other is just an example purpouse value we could need later in our ipothetical script.The variable
k is incremented every iteration until it equals 10; we should keep in mind to try to avoid infinite loops, like a k control-value that will never reach a value of 10. As we saw for the if clause, the control-statement could be any boolean value or any function that returns a boolean value.
At the end of this loop rv will have the value of 20.
Now let's take a look at this more complex code segment:

(let* (
  (x-topleft 0)
  (y-topleft 0))
  (while (< y-topleft height)
    (while (< x-topleft width)
      (...)
      (set! x-topleft (+ x-topleft block-w)))
    (if (= x-topleft width) (set! x-topleft 0))
    (set! y-topleft (+ y-topleft block-h))))
where the undefined variables are: height is the drawable height, width is the drawable width, block-h is the height of a sub-rectangle of the drawable, block-w is the sub-rectangle width.
Here we move a point of coords (x-topleft ; y-topleft) inside the drawable from its inizial position of (0 ; 0) until the far end of the right bottom corner. This point can be thought as the topleft corner of a sub-rectangle whose block-h and block-w are just a fraction of the height and width of the drawable.
The two nested iteration loops move the point from left to right, and once encountered the right end of the drawable (= x-topleft width), the point will be shifted to the next row at (0 ; (+ y-topleft block-w)) until y-topleft equals the height of the drawable.