kentwest.neocities.org

Scripting the GIMP

Kent West, 15June2024

You've heard that the GNU Image Manipulation Program (GIMP) is scriptable, but you have no clue how to begin.

Well, here's your beginning.

Hello, World!

Scripting is just the giving of command-line commands to the GIMP engine. There are three basic ways of giving a command-line command:

  1. From a text file containing one or more scripts that are registered into GIMP's Procedural DataBase (PDB), which are added as menu items into the GIMP GUI.
  2. From a text file containing one or more scripts that are not registered into the PDB, but that are instead fed to GIMP at GIMP's command-line.
  3. From the Script-Fu console, within GIMP.

We'll look at each of these, in reverse-order.

3. From the Script-Fu console

Fire up the GIMP like you normally would. (I'm using version 2.10, on Debian GNU/Linux 12; if you're using Windows or Mac, I'm sorry. But don't be ashamed; not everyone can run Linux.) You should see a screen something like this:

The GIMP screen.

Click on the Filters menu, and near the bottom of the pulldown menu you should see Script-Fu.

You may also see Python-Fu. This is a newer Python-based scripting system. Because of issues with the Python2 to Python3 conversion, the Python-Fu system is not installable on Debian 12 systems using the common and usual Debian methods. This tutorial uses the Script-Fu method rather than the Python-Fu method. If you decide to move to Python-Fu at some point, it'll be good for you to be familiar with Script-Fu first.

Script-Fu is a scripting system/language that is based on Tiny-Fu, and both are based on the Scheme programming language, or more accurately, TinyScheme, a subset of Scheme. Neither Script-Fu nor Python-Fu are particularly intuitive. That's why you're going through this tutorial.

Select the Script-Fu menu item, and then the Console item. This will open a new window like so:

The Script-Fu console.

This console window is like a console/terminal window wherein you'd type commands, but this console window only understands Script-Fu commands. Like as is the case with most tutorials, we'll generate a "Hello, World" message. In the smaller window within the console (next to "Browse..."), type the following, but don't yet press ENTER:

(gimp-message "Hello, World!")

Look at the bottom-left area of the center pane of the main GIMP window; currently it is empty. But when you press ENTER (go ahead and do so now), you'll see an alert icon appear along with the message, "Hello, World!". Watch it for about five seconds, and the alert and message will disappear.

The "Hello, World!" alert.

The console will also print out the command you just entered, along with what "result" that command generated, in this case a "(#t)". We won't worry about that returned value in the console; but eventually you may find that information helpful in troubleshooting your commands.

You have written your first Script-Fu command.

Just like with a terminal window, you can press the Up arrow to recall previous commands, and edit them, and again press ENTER to execute them. Try recalling your last message, and editing it to something like "Howdy, Terrans!"

A feature (cough gag ahem) of Script-Fu is that everything is surrounded by parentheses. Seems a little overkill for my tastes, but ... meh.

If you want to see what other Script-Fu commands are available, or need a little help remembering their syntax, you can click on the Browse... button at the end of the command-line field. In the pop-up that appears (see below), you can search for a portion of a command you vaguely suspect might exist, or you can just scroll through the entire (relatively short) list. In the second image below you can see that I've started searching for "message", and that three hits are found, the first of which is highlighted, with a short synopsis of the command in the right-hand pane. If you click on Apply, the highlighted commnd will be pasted in the previous console window, or you can manually switch to the console and type in the command now that you know how to spell it.

Browsing through the Script-Fu commands.

Browsing for "message".

2. From the GIMP command-line

In order to feed scripts to the GIMP from the command-line, GIMP needs to know where to look for script files. This is set in GIMP's preferences. This is found in the menu item Edit | Preferences:

Opening GIMP's preferences.

In the left-hand pane, click the little plus sign next to "Folders" to expand it, then scroll down to and click on "Scripts". Then in the right-hand pane you'll see where GIMP expects to find script files.

Locating script directories.

The scripts that come with GIMP are likely in /usr/share/gimp/2.0/scripts, and your personal scripts are likely expected to be in your profile directory's .config/GIMP/2.10/scripts directory.

Open up your favorite file manager and browse to the indicated system's script directory (probably /usr/share/gimp/2.0/scripts. Here you'll see a collection of script (and other) files.

The system scripts.

The files with a .scm extension are script files. Note that these files are not themselves the scripts, but only contain the scripts. There could be more than one script in each file.

When GIMP starts up, it scans the script files for scripts; when a script is found, it is added to GIMP's Procedural DataBase (PDB), a database of procedures that GIMP knows about. If GIMP is started from the command-line with a script name attached, GIMP will run that script if it's found in the PDB.

Go ahead and close GIMP now; we want to make sure it opens properly from the command-line.

Now that you have GIMP closed, open a terminal window; if you're running Linux, this will probably be a Bash shell, but pretty much any terminal shell should work. At the (Bash?) prompt, enter "gimp" to start GIMP. You should see lots of text fly by in the terminal window, and the normal GIMP GUI open up. Don't worry about any errors you might see in the text that flies by, as long as GIMP opens properly. It is during this start-up process that GIMP scans the *.scm files in the script file directories, adding the scripts to its PDB.

If that worked, and I suspect it did, we're ready to create a text file that contains our Script-Fu script, and to feed it to the GIMP engine when we next start GIMP. Go ahead and close GIMP.

Use your favorite text editor (vim, nano, Kate, whatever) to create the following file in your user's script folder (probably .config/GIMP/2.10/scripts in your home directory), naming it greetings.scm:

greetings.scm
(define (howdy) (gimp-message "How do, Buckaroo?"))

And then, at your command prompt, run GIMP like this:

$ gimp -b "(howdy)"

If everything is right, you should see GIMP open up, and then a small pop-up window with your message, like in the image below.

The result of the "howdy" script.

Several things you may notice:

What if you wanted GIMP to open, do its thing, and then close? Do you reckon there's a Script-Fu command to close GIMP?

While you have GIMP open, re-open the Script-Fu console (it's under the Filters menu item). Once in the console, click on the "Browse..." button and search for, say, "close".

Well, there are several "close" commands, but nothing that looks like it would close GIMP. Clear the search field and try a different search, for "exit".

Still no success. Try "quit".

Hey, "gimp-quit" looks promising. Let's try that. Click on the "Apply" button to paste it into the console's command line field. You'll see that instead of pasting only "(gimp-quit)" (in parentheses, 'cause, you know, everything in Script-Fu is in parentheses), it pasted "(gimp-quit force)". That's because the command, as explained in the blurb in the "Browse" window, expects a "boolean" (essentially a yes/no, or true/false, or 1/0, value) to tell GIMP if it should force itself to quit, or to quit gracefully, asking the user if he wants to save unsaved work, etc. This word "force" is just a reminder to you to use the correct value; "force" itself is not a correct value, but only a reminder. If you run the command as-is, you'll get an error. Press ENTER to see that error.

So we need to replace "force" with either "TRUE" or "FALSE" (or "1" or "0"). Since we don't care about saving our work, we can just use "(gimp-quit TRUE"), which means to quit GIMP, truly with force. Go ahead and execute this command from the Script-Fu console to quit GIMP.

To run a script and then quit GIMP, we can put the quit command either in our script, or on the command-line, as if it is a second script. Let's try it first on the command-line. Restart GIMP with this command:

$ gimp -b "(howdy)" -b "(gimp-quit TRUE)"

If your computer is not blindingly fast, you should see GIMP open, display your message, then close everything, without waiting for you to close the message pop-up. You can up-arrow the last command and replace "TRUE" with "1", and see the same thing happen.

Let's rearrange our code a bit. We're not actually changing anything except the format, from a one-liner to multiple lines.

greetings.scm
(define (howdy)
    (gimp-message "How do, Buckaroo?")
)

Now let's put the quit command in our script:

greetings.scm
(define (howdy)
  (gimp-message "How do, Buckaroo?")
  (gimp-quit TRUE)
)

and then run the shorter command-line command:

$ gimp -b "(howdy)" -b "(gimp-quit TRUE)"

You should still get the same results as before: GIMP opens, displays the message (maybe, before GIMP quits), and then quits, all in rapid succession.

Let's remove the "quit" command, and add a second message:

greetings.scm
(define (howdy)
  (gimp-message "How do, Buckaroo?")
  (gimp-quit TRUE)
  (gimp-message "This is Message #2.")
)

And run it:

$ gimp -b "(howdy)"

You'll notice you get both messages in one pop-up window. The script does not pause for the user to click "OK" on the first message before it continues with the rest of the script.

We can even have multiple scripts in the same script file; add the highlighted portion below:

greetings.scm
(define (howdy)
    (gimp-message "How do, Buckaroo?")
    (gimp-message "This is Message #2.")
)

(define (doody)
    (gimp-message "It's Howdy-Doody Time!")
)

You probably know how to run the new "doody" script:

$ gimp -b "(doody)"

Before moving on to the last method of scripting, let's see what happens if you leave off a pair of parentheses. In the last iteration of our script, remove the parentheses around "howdy" from the "(define (howdy)" line, and then try running the script. The entire file looks like this:

greetings.scm (note the lack of parens around "howdy")
(define howdy
    (gimp-message "How do, Buckaroo?")
    (gimp-message "This is Message #2.")
)

(define (doody)
    (gimp-message "It's Howdy-Doody Time!")
)

And then try running the script first with this command:

$ gimp -b "(howdy)"

and then this one:

$ gimp -b "(doody)"

and then this one (without parentheses here):

$ gimp -b "doody"

Not at all the expected behavior, huh? It looks, sort of, like the program is kinda working....? But if you don't know what you've coded wrongly, it just seems ... inconsistent. It's definitely not working right. All because the parentheses are not right. As mentioned before, Script-Fu is not a forgiving language, and because the existing documentation is less than clear in many ways, errors like this can take hours of banging your head against the wall to figure out. So to make it clear, here's the basic syntax for a script in a script file:

some_file_name.scm
(define (function_name)
  (some Script-Fu command)
  (another Script-Fu command)
)

If your function requires parameters, they go in the parentheses surrounding the function name, like so:

some_file_name.scm
(define (function_name parameter_1 parameter_2 parameter_3)
  (some Script-Fu command)
  (another Script-Fu command)
)

or, perhaps more clearly:

some_file_name.scm
;Example syntax
;for a simple Script-Fu function with three parameters
;by Kent West
(define (function_name  parameter_1 ;Comments are prefixed by a semi-colon.
                        parameter_2
                        parameter_3
        )
  (some Script-Fu command)
  (another Script-Fu command)
)

2.5 A Bonus Method

Here's a bonus method for running Script-Fu commands. It's kind of a mix between running the Script-Fu console within the GIMP GUI, and running terminal commands.

$ gimp -b -

This command runs GIMP in batch mode, but without feeding it any "batches" to run with its Script-Fu script engine, and to instead, start a "console" in the terminal window itself instead of in the GIMP GUI. It looks kind of like this:

In my Debian GNU/Linux bash terminal window
 
$ gimp -b -
script-fu-Warning: How do, Buckaroo?

Welcome to TinyScheme, Version 1.40
Copyright (c) Dimitrios Souflis

ts> 

Oops! I've got a script-fu-warning that tells me about my first message in the existing "greetings.scm" file. This is another "feature" of not having parentheses where they belong. I forgot to restore the parentheses around the "howdy" of the "(define (howdy)" line in that file, which broke the script. Let me fix that, by putting those parentheses back (as seen in the previous sentence), and try again:

In my Debian GNU/Linux bash terminal window

As you can see, the terminal window opens a TinyScheme ("ts>") command-prompt, where you can type in Script-Fu commands. You can get out of this mode by closing the GIMP GUI.

1. Run a script that is registered in GIMP's Procedural Data Base (PDB), from a menu item.

This process is pretty easy. Let's start with our "greetings.scm" file:

greetings.scm
(define (howdy)
    (gimp-message "How do, Buckaroo?")
    (gimp-message "This is Message #2.")
)

(define (doody)
    (gimp-message "It's Howdy-Doody Time!")
)

We have two scripts. Let's add the first one, "howdy", to the "Windows" menu in GIMP. The following code can be added to the top of the script file, or to the bottom, or in the empty space between the two scripts. We'll add it to the bottom.

greetings.scm
(define (howdy)
    (gimp-message "How do, Buckaroo?")
    (gimp-message "This is Message #2.")
)

(define (doody)
    (gimp-message "It's Howdy-Doody Time!")
)

(script-fu-register
            "howdy"                                       ;function name
            "A 'Howdy!' Message"                          ;menu label
            "Creates a pop-up alert window that\
            says howdy."                                  ;description
            "Kent West"                                   ;author
            "2047                                         ;copyright notice
            "October 12, 2048                             ;date created
            ""                                            ;image type that the script will work with
)
(script-fu-menu-register "howdy" "<Image>/Windows/Howdy")

There are a couple of ways to register this script into GIMP's Procedural Data Base. The easiest is simply to [re]start GIMP; as it reads the script files in the specified script directories, it will see the above code and register the script into its database. Another way, from within GIMP without restarting it, is to go to the Filters | Script-Fu menu and select Refresh Scripts.

If you have no errors in your code, you should now see in the Windows menu a new item named "Howdy". And in that menu is "A 'Howdy!' Message". And if you click on that, you'll see ....

Oh. You expected to see a pop-up window, huh? Instead, we're back to displaying the alerts in the lower notification area. And only for about five seconds. And you only see the last message of the script's two messages, which overwrites the first one so quickly you never see it.

So our script isn't exactly what we expected, but it's close enough to get you started.

The seven items in the first "script-fu-register" section are required. (The "image type" specifies what types of images - RGB, RGBA, GRAY, etc - that the script works with. In our case, we're not working with an image, so we leave that field empty, but we include the empty field because the field is required.) You should be able to figure out what each item does. From within GIMP, click on the Help | Procedure Browser menu item. The window that pops up shows you all the procedures that are registered in the PDB. You can scroll down to (or search for) "howdy" to see the copyright information and author and etc.

The second "script-fu-register" section specifies where in the menu system the menu item will be placed. The "<images>" prefix is one of several options, but for a simple menu item like what we're doing here, "<images>" is the correct choice.

Let's add the second script. We could put the registration at the end again, but this time I'll put it in the middle of the script file, before the actual script.

greetings.scm
(define (howdy)
    (gimp-message "How do, Buckaroo?")
    (gimp-message "This is Message #2.")
)

(script-fu-register
            "doody"                                     ;function name
            "Doody, Dude!"                              ;menu label
            "Surprise!"                                 ;description
            "Kent West"                                 ;author
            "2024"                                      ;copyright notice
            "Mayvember 52nd, 41999"                     ;date created
            ""                                          ;image type that the script will work with
)
(script-fu-menu-register "doody" "<Image>/Windows/Howdy")


(define (doody)
    (gimp-message "It's Howdy-Doody Time!")
)

(script-fu-register
            "howdy"                                     ;function name
            "A 'Howdy!' Message"                        ;menu label
            "Creates a pop-up alert window that\
            says howdy."                                ;description
            "Kent West"                                 ;author
            "2047                                       ;copyright notice
            "October 12, 2048                           ;date created
            ""                                          ;image type that the script will work with
)
(script-fu-menu-register "howdy" "<Image>/Windows/Howdy")

Again, to load this into the PDB, either restart GIMP, or run Filters | Script-Fu | Refresh Scripts.

To move the menu item out of the "Howdy" sub-menu", but leave it in the "Windows" menu, just take out the "/Howdy" portion from the line, (script-fu-menu-register "doody" "<Image>/Windows/Howdy"), and refresh the scripts.

To remove a script from the menus altogether, just delete or comment out the line in the script file that registers the menu item, and then refresh the scripts again. If you do not remove/comment out the registration of the script, but only the registration of the menu item for the script, then the script is still available in the Procedural DataBase; you can verify this by looking in the PDB as mentioned above.

As you look in the PDB, you might find it more aesthetic to group your scripts together in this list; this can be done by starting the name of your scripts with an identical prefix. Many scripters prefix their script names with "script-fu-", as in "script-fu-do-something". You might also consider a prefix that refers to yourself, such as "kent-do-something". Then you can search the PDB for "script-fu" for all the scripts starting with "script-fu-", or you can search for "kent" to find "kent-howdy" and "kent-doody", etc.

You should now have a fairly good grasp on the basics of scripting in GIMP. There's a lot yet to learn, but hopefully this will get you started.

Comments? kent.west at that search company that used to vow to do no evil.