Text and images Copyright (C) 2002 Dov Grobgeld and may not be used without permission of the author.
Editor’s note: since this tutorial was published, the old GIMP Script-Fu interpreter (SIOD) has been replaced by a newer and better one (TinyScheme). A Script-Fu migration guide is available.
One of the wonderful features of GIMP is that it all its functionality may be accessed through scripting. The major scripting language for GIMP that has been attached to it today is Scheme. This document will try to be a brief introduction to Scheme, just teaching the essentials in order to write Script-Fu scripts, without getting into the programming language theory that is so typical of other Scheme references.
Scheme is a Lisp variant and all expressions are surrounded by parentheses. E.g. a list which will calculate the sum of 3 and 4 is written
(+ 3 4)
The + sign is the addition function and 3 and 4 are the first and second parameters to this function. Expressions may be nested, so the expression (3+4)*(5/6) would in Scheme be written
(* (+ 3 4) (/ 5 6))
White space has no importance so the above expression may as well be written:
(*
(+ 3 4)
(/ 5 6))
Aside from the four arithmetic functions that are represented through the symbols + - * / there are lots of other functions built into the language. All of them have the form
(foo param1 param2 ...)
Additional functions may be defined by the user through the define keyword. E.g. a function that calculates the square value of its single argument may be declared like this
(define (square x) (* x x))
and this function may be called through
(square 5)
Variables may be declared and set through the set! command. (These variables will be global but this should not bother the casual GIMP programmer). Here are a couple of assignments:
(set! grey_value 85)
(set! angle (* (/ 30 180) 3.141)
Lisp and its variants make heavy use of lists. Script-Fu is no exception and it uses e.g. a list of three elements to write a RGB color. E.g. the color orange would be written
'(255 127 0)
The ‘ sign is necessary in order to tell Scheme that this is a literal list. If the ‘ was omitted Scheme would try to look up a function with the name 255 and send it the two parameters 127 and 0, which is obviously not what we want.
To create a variable called orange with the above value and then set the background color to it we may do
(set! orange '(255 127 0))
(gimp-set-background-color orange)
A list in Scheme is always composed of a head and a tail. The head is the first entry in the list, and the tail is the rest of the elements in the list. This means that the list (255 127 63) really means (255 (127 (63 ()))) but Scheme allows the previous form as a shortcut. The car function is used to return the head of the list and the cdr (usually pronounced cudder) is used to get the tail of the list.
[The following is a test of the above functions which may be interactively conducted in the Script-Fu console.]
=> (set! color '(255 127 63))
(255 127 63)
=> (car color)
255
=> (cdr color)
(127 63)
To get the blue component of a color it is necessary to apply the cdr function twice and then the car function.
=> (car (cdr (cdr color)))
63
This is very inconvenient to write. Therefore there have been defined abreviations of the form cadr, cddr, caddr, etc that concatenate the operations described above. The previous expression may therefore be much more conveniently written:
=> (caddr color)
63
For the Script-Fu writer one of the most important uses of the car function is to access the returned values from the built-in GIMP functions. All gimp-functions return a list, and even if the list contains only one element it must be accessed by car. This is e.g. the case for the important functions gimp-new-image and gimp-new-layer used below.
More experienced Scheme programmers mostly use local variables instead of the global variables described above. This is considered better programming practice and this construct should be recognized in order to be able to read others Script-Fu scripts.
Local variables are declared through the the let keyword as in the following example:
(let* ((a 3)
(b 4))
((* a b)))
Here a and b have a local scope and retain their values only up to the closing paren matching the one before let* .
All functionality of GIMP is available through the procedural database (PDB). Each procedural database function has a corresponding Scheme function mapping. E.g.
(gimp-image-new 100 150 RGB)
produces a new GIMP image of type RGB and size 100x150.
All the functions of the PDB may be accessed through the Procedure Browser that is available from the main menu through Xtns ->Procedure Browser…. E.g. the Procedure Browser entry for uni-img, which we will define in the example below looks like this:
For the Script-Fu programmer this information shows that uni-img may be called with three parameters of the types INT32, STRING and COLOR. The different types will be explained below.
After a function has been written it has to be registered with Script-Fu before it can be used. This is done through the Scheme function script-fu-register. The registering has following purposes:
The last point above actually means that a script is from Gimp’s viewpoint in no way different from a built-in command or a plugin command. As long as a command is registered in the PDB it can be called by any script or plugin.
The parameters of script-fu-register may be divided into two groups. The first group of seven parameters must always be given. These are:
After these seven parameters have been given, a list of the parameters required by the script follows. Each parameter is given as a group of three items:
The type of the parameter. Some of the valid types are:
A label for Script-Fu to display when querying for the parameter.
The following script uni.scm receives two parameters from the user, the size of the image and a color, and goes on to produce a uniform image of the requested size and the requested color. Not very useful, but it shows the essential steps in producing a Script-Fu script.
; Define the function of the script and list its parameters
; The parameters will be matched with the parameters listed
; below in script-fu-register.
(define (uni-img size color)
; Create an img and a layer
(set! img (car (gimp-image-new size size RGB)))
(set! layer (car (gimp-layer-new img size size
RGB "layer 1" 100 NORMAL)))
; The following is done for all scripts
(gimp-image-undo-disable img)
(gimp-image-add-layer img layer 0)
; Here is where the painting starts. We now have an image
; and layer and may paint in the layer through the PDB functions.
(gimp-palette-set-background color)
(gimp-edit-fill layer BG-IMAGE-FILL)
; The following is also done for all script
(gimp-display-new img)
(gimp-image-undo-enable img))
; Finally register our script with script-fu.
(script-fu-register "uni-img"
"Uniform image"
"Creates a uniform image"
"Dov Grobgeld <dov@imagic.weizmann.ac.il>"
"Dov Grobgeld"
"2002-02-12"
""
SF-VALUE "size" "100"
SF-COLOR "color" '(255 127 0))
(script-fu-menu-register "uni-img" "<Toolbox>/Xtns/Script-Fu/Tutorials")
To test the script save it in $HOME/.gimp-2.2/scripts/uni.scm and then select Xtns -> Script-Fu -> Refresh:
The script Uniform image should now appear in the pulldown menu Xtns -> Script-Fu -> Tutorials -> Uniform image. Selecting this script results in the following popup:
Accepting these default parameters through the OK button gives us the following new image:
It is also possible to access this script through the Script-Fu console by typing the command
(uni-img 100 '(0 255 127))
In the uni-img script it was placed under Xtns/… in the main Gimp window. This is done to create a new image that is independant of earlier images. It is also possible to create a script which works on an already existing image. If in script-fu-menu-register the second argument is written:
<Image>/Script-Fu/…
then the script will be available through the GIMP menu that is launched by the right mouse button over an image. Such script must also have as their first and second argument a SF-IMAGE and a SF-DRAWABLE.
Here is an example script which copies the current layer to a new layer, blurs it and inverts it.
; An example script that blurs an image according to a blur radius.
; It illustrates how to hang a script in the image menu, and
; how a plug-in may be called.
(define (script-fu-copy-blur img
drawable
blur-radius)
; Create a new layer
(set! new-layer (car (gimp-layer-copy drawable 0)))
; Give it a name
(gimp-layer-set-name new-layer "Gauss-blurred")
; Add the new layer to the image
(gimp-image-add-layer img new-layer 0)
; Call a plugin to blur the image
(plug-in-gauss-rle 1 img new-layer blur-radius 1 1)
; Invert the new layer
(gimp-invert new-layer)
; Flush the display
(gimp-displays-flush)
)
(script-fu-register "script-fu-copy-blur"
"Copy and Blur"
"Copy and blur a layer"
"Dov Grobgeld"
"Dov Grobgeld"
"2002"
"RGB*, GRAY*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Layer to blur" 0
SF-VALUE "Blur strength" "5")
(script-fu-menu-register "script-fu-copy-blur"
"<Image>/Script-Fu/Tutorials")
In uni-img we called the procedure gimp-edit-fill to fill the whole image. Looking at the info for gimp-edit-fill in the Procedure Browser we find the following:
Name: | gimp-edit-fill | ||
---|---|---|---|
Blurb: | Fill selected area of drawable | ||
In: | DRAWABLE | drawable | The drawable to fill from |
INT32 | fill_type | The type of fill: FG-IMAGE-FILL (0), BG-IMAGE-FILL (1), WHITE-IMAGE-FILL (2), TRANS-IMAGE-FILL (3), NO-IMAGE-FILL (4) | |
Help: | This procedure fills the specified drawable with the fill mode. If the fill mode is foreground, the current foreground color is used. If the fill mode is background, the current background color is used. Other fill modes should not be used. This procedure only affects regions within a selection if there is a selection active. |
Thus, if we have a selection active when gimp-edit-fill is called, then only the selection is painted. There are lots of ways of choosing a selection as can be seen when searching for a “select” in the PDB. We will use gimp-rect-select, whose entry in the PDB looks as follows:
Name: | gimp-rect-select | ||
---|---|---|---|
Blurb: | Create a rectangular selection over the specified image | ||
In: | IMAGE | image | The image |
FLOAT | x | x coordinate of upper-left corner of rectangle | |
FLOAT | y | y coordinate of upper-left corner of rectangle | |
FLOAT | width | the width of the rectangle: width > 0 | |
FLOAT | height | the height of the rectangle: width > 0 | |
INT32 | operation | the selection operation: {ADD (0), SUB(1), REPLACE (2), INTERSECT (3) } | |
INT32 | feather | feather option for selections | |
FLOAT | feather_radius | radius for feather operation | |
Help: | This tool creates a rectangular selection over the specified image. The rectangular region can be either added to, subtracted from, or replace the contents of the previous selection mask. If the feather option is enabled, the resulting selection is blurred before combining. The blur is a gaussian blur with the specified feather radius. |
A simple use of this function which selects the rectangle (x,y,width,height) = (0,25,100,50), paints this region blue, and releases the selection looks as follows:
(gimp-rect-select img 0 25 100 50 REPLACE 0 0)
(gimp-palette-set-background '(0 0 255))
(gimp-edit-fill layer BG-IMAGE-FILL)
(gimp-selection-none img)
The only looping construct that exists in Script-Fu is while
[Note: this constraint is due to the current Scheme interpreter SIOD used for Script-Fu.] The while loop looks as follows:
(while (condition)
(statement1)
(statement2)
:
)
Here’s an example which draws horizontal lines, 16 pixels high, on an image:
(set! y 0)
(while (< y size)
(gimp-rect-select img 0 y size 16 REPLACE 0 0)
(gimp-edit-fill layer-one BG-IMAGE-FILL)
(set! y (+ y 32)))
When pasting an image from the clipboard, or when creating text in a a drawable, the result is not put directly in the drawable. Instead it is put into a special temporary layer known as a floating selection. The floating selection may be manipulated in several ways, and finally it is merged into its associated layer, a process known as anchoring.
When creating text through the gimp-text command, the text is always put into a temporary layer. This temporary layer then has to be anchored. Here is an example of creating some text which is pasted into the current drawable:
; An example script that writes a fixed string in the current
; image.
(define (script-fu-hello-world img drawable)
; Start an undo group. Everything between the start and the end will
; be carried out if an undo command is issued.
(gimp-undo-push-group-start img)
; Create the text. See the Procedure Browser for parameters of gimp-text.
(set! text-float (car (gimp-text-fontname img drawable
10 10 "Hello world" 0 1 50 0
"Sans")))
; Anchor the selection
(gimp-floating-sel-anchor text-float)
; Complete the undo group
(gimp-undo-push-group-end img)
; Flush output
(gimp-displays-flush))
(script-fu-register "script-fu-hello-world"
"Hello World"
"Write Hello World in the current image"
"Dov Grobgeld <dov@imagic.weizmann.ac.il>"
"Dov Grobgeld"
"2002-02-12"
"RGB*, GRAY*"
SF-IMAGE "Input Image" 0
SF-DRAWABLE "Input Drawable" 0)
(script-fu-menu-register "script-fu-hello-world"
"<Image>/Script-Fu/Tutorials")
This script shows another feature we haven’t mentioned before. The possibility of creating an undo group. All the commands between the commands gimp-undo-push-group-begin and gimp-undo-push-group-end are undone together if the undo command is issued.
To copy a selection, the command gimp-edit-copy is used. It places a copy of the selection contents in the cut-buffer. The contents of the cut-buffer may then be pasted into a layer, the same layer or another one, and it is then pasted as a floating layer.
In the following example the selection is copied, pasted into the same layer, offset a fixed distance, finally anchored. Try it by drawing a small blob in the middle of the image, select the blob, and then call this script.
; An example of how to create a floating layer and how to ancor it.
(define (script-fu-sel-copy img
drawable)
(gimp-undo-push-group-start img)
(gimp-edit-copy drawable)
(set! sel-float (car (gimp-edit-paste drawable FALSE)))
(gimp-layer-set-offsets sel-float 100 50)
; Anchor the selection
(gimp-floating-sel-anchor sel-float)
; Complete the undo group
(gimp-undo-push-group-end img)
; Flush output
(gimp-displays-flush))
(script-fu-register "script-fu-sel-copy"
"Selection Copy"
"Copy the selection into the same layer"
"Dov Grobgeld"
"Dov Grobgeld"
"2002-02-12"
"RGB*, GRAY*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Layer" 0)
(script-fu-menu-register "script-fu-sel-copy"
"<Image>/Script-Fu/Tutorials")
The original tutorial can be found here.