ScriptFu Tools

The ScriptFu tools are:

  1. Console
  2. Eval
  3. Server
  4. Text Console

The ScriptFu tools let you interpret Scheme scripts. They are plugins that have more general purpose than image filter plugins.

You use them to develop plugins and to process images in batches.

Audience

This document is for plugin authors using the ScriptFu Scheme language.

It is a user manual for the ScriptFu tools.

This is also for developers of the tools. The tools are all plugins. They are all written in the C language. Their source code is in the “plug-ins/script-fu” directory of the repo. Along with the source for parts of ScriptFu that interpret filter plugins.

Terminology

ScriptFu’s language is a dialect of the Scheme programming language, augmented with functions to call the Gimp PDB. The tools interpret “snippets” of that language. By “snippet” we mean a short text in ScriptFu’s dialect of the Scheme language. Snippets can be long, or can load longer files of the language.

A snippet can call any procedure in the PDB. Some of the procedures in the PDB are plugins. A snippet can’t itself be a plugin, since a snippet can’t register in the PDB.

A snippet can be part of an intended plugin. A snippet can be unrelated to image processing.

Summary of the tools

  1. The ScriptFu Console is a graphical IDE letting plugin authors edit and test snippets.

  2. ScriptFu Eval is a PDB procedure that lets other languages call the ScriptFu interpreter to execute snippets. It is not an application program, but a function.

  3. ScriptFu Server is a plugin that runs a server background process that evaluates snippets, submitted over the network by clients. It is not an application program, but a daemon. The server can run in a host computer and a client in a separate computer can access the remote server.

  4. ScriptFu Text Console is a textual command line similar to the graphical ScriptFu Console. It is an application program.

ScriptFu Console

The ScriptFu Console seems to be the most popular ScriptFu tool.

The ScriptFu Console is a graphical IDE letting plugin authors edit and test snippets.

It is application program; with its own window, open for a long time

It is most like a command-line program in a terminal: you type some text, hit the Return key, and see the result scroll by. But it has a graphical user interface, using a mouse.

It is primitive, and doesn’t have the features of a full-fledged IDE, such a command completion and syntax highlighting.

Starting the console

Start the Gimp app.

Choose the menu Filters>Development>Script-Fu>Console. Expect a window to appear.

(Currently, the window will not stay on top, and may get hidden behind the main Gimp window.)

If you are debugging a snippet, you might start Gimp in a terminal so you can see debugging messages from the ScriptFu interpreter.

Using the console

The pane at the bottom is a text editor. Click the cursor into it, type some text, and press the Return key. You can also cut and paste, or drag-and-drop, into the text editor.

ScriptFu interprets the text and appends the result to the history in the top pane.

The displayed result is:

  1. what the snippet writes to stdout (the default output port of Scheme language)
  2. and what the ScriptFu Interpreter writes to stdout as the yielded value of each top level expression in the snippet.
  3. and any error message

Note that the ScriptFu Console prints all results for a snippet in one multi-line tranche, not each line in real time as generated. The yielded values of the top-level expressions are often concatenated in a one line string, when the snippet itself does not insert newlines.

Scrolling the history

The Up and Down Arrow keys will scroll through the history. Pressing the Up Arrow key will put the prior command into the editor pane.

The history of commands, but not the history of results, is persistent across sessions of Gimp.

The history is finite; the editor discards the oldest commands.

Browsing

The Browse button opens a new window showing the PDB Browser. Then choose the Apply button of the PDB Browser. That will insert a template of a call to the selected PDB procedure, into the editor pane. You will usually need to substitute actual argument values for formal argument names in the template.

(You can also start a PDB Browser from the Help menu, but it won’t have an Apply button.)

Other limitations

You can’t completely write a plugin in the console, because you can’t register a plugin from the console. You can only test the “run function” of a plugin, or snippets thereof, in the console.

Currently, the text editor is only one line tall, and shows line breaks as a character glyph.

Printed results: ScriptFu Console versus plugin

The ScriptFu Console redirects the stdout stream of a snippet to itself and shows it in the history window.

When a snippet is in an installed plugin, it’s stdout will be printed in the terminal in which Gimp was started, if any. That is, a call such as ‘(display “Hello world”)’ will write to any terminal in which Gimp was started (unless the snippet itself redirects the Scheme output port.) So you can debug a ScriptFu script by harnessing it with calls to display.

In Gimp v2, the stdout of ScriptFu plugins was discarded, or only the prefix of any error message.

ScriptFu Eval

ScriptFu Eval is a PDB procedure that lets other languages call the ScriptFu interpreter to execute snippets. It is not an application program, but a PDB procedure.

As a plugin, it has no user interface and cannot be called except in run mode NONINTERACTIVE.

Calling ScriptFu Eval from Python

You can call plug-in-script-fu-eval from the Gimp Python Console, or from a Gimp plugin in the Python language.

In the Gimp Python Console:

proc = Gimp.get_pdb().lookup_procedure('plug-in-script-fu-eval')
# A Config is a set of arguments
config = proc.create_config()
# Arguments to the procedure are each a property of the config.
# Here, the arg is the snippet to be evaluated, a string text
# and the name of the argument is "script".
config.set_property('script', '(quit 1)')
result = proc.run(config)
print (result)
print (result.index[0])

This prints:

<Gimp.ValueArray object at 0x7f3847b4b1d0 (GimpValueArray at 0x2520640)>
<enum GIMP_PDB_EXECUTION_ERROR of type Gimp.PDBStatusType>

In this example, the evaluated Scheme snippet does nothing but quit with error code 1. Again, most snippets are executed for their side effects.

Here the result of the call to plug-in-script-fu-eval is a GimpValueArray, like all calls to a PDB procedure. The first element is of type GimpPDBStatus, with value GimpPDBExecution Error, since the evaluated snippet called quit to indicate an error.

Note that the Gimp Python Console does not show what the ScriptFu interpreter printed or what the snippet output. That output goes to the terminal where Gimp was started, expect:

script quit with code: 1

Also, since the snippet returned an error, expect in the Gimp Error Console:

GIMP Error Calling error for procedure 'pug-in-script-fu-eval': Unknown error.

An obsolete example of Python code: Gimp.get_pdb().run(“script-fu-eval” “(quit 1)”).

Calling ScriptFu Eval in batch mode

A more frequent use is to run a snippet in batch mode. You can’t just execute ScriptFu Eval from a command line, because it is not a program, it is a plugin that must be invoked from within Gimp.

>gimp --no-interface --batch-interpreter=script-fu-eval
  --batch="(gimp-message \"foo\")"

Note the escaped quotes around the string “foo”, so that the command line shell doesn’t process the quotes.

Expect in the terminal:

script-fu-Warning: foo
batch command executed successfully

Here the first line is due to the snippet’s call to gimp-message, which prints to stdout when Gimp is in batch mode. Here the second line is printed by Gimp as the result of the batch.

A more useful example is to evaluate a file of Scheme language:

>gimp --no-interface --batch-interpreter=script-fu-eval --batch="(load \"my.scm\")"

This also will print to the terminal.

Comparison to the ScriptFu Server

The ScriptFu Server also evaluates snippets. ScriptFu Eval is unlike the server:

  1. the process starts and stops for every evaluated snippet.
  2. it has no long running interpreter state
  3. it runs in the current Gimp context of the calling plugin.

ScriptFu Server

You start the server, then send snippets using a client, and receive results in the client.

You should only have one client at a time, since all clients share the same execution environment. A client can define objects such as images into the serving interpreter’s environment.

The server is:

  1. is a long-running process
  2. has persistent interpreter state
  3. starts in the context of the Gimp app at the time the server is started.

Starting the server

Start the Gimp app. Start it from a console i.e. terminal when you want the server to log to a terminal instead of a file.

Choose the menu Filters>Development>Script-Fu>Start Server. Expect a dialog to appear.

Choose the OK button. Expect the dialog to disappear. Also expect the server to be a running process and for it to write log messages to the console in which Gimp was started.

Alternatively, in the dialog for the server, you choose a file for the server to log to. Then you can “tail -f” the file to see the log.

Monitoring the server

The server logs to stdout i.e. the terminal where it was started, or to a file.

Gimp’s Client for the ScriptFu Server

The Python 2 program plug-ins/script-fu/server/servertest.py is a simple client. It prompts you for snippets.

It is Python 2 and needs revision for Python 3.

Start it:

python2 gimp/plug-ins/script-fu/server/servertest.py

Expect a banner and a prompt:

Script-Fu-Remote - Testclient
>

Enter a snippet and press the Return key. Expect a result to be printed. Repeat.

Enter Control-D to quit the client.

Usage: servertest.py <host> <port>
       (if omitted connect to localhost, port 10008)

Third party clients for the ScriptFu Server

A third-party provides “gimp-exec.c”. You can download and build the gimp-exec client application. The gimp-exec client is a command line app run from a terminal.

!!! The gimp-exec client has flaws: it doesn’t wait for all the bytes of response!!!

The gimp-exec client is not a REPL, that is, does not repetetively let you enter a line then print the response. You need to invoke the client again for each snippet. But each snippet has a persistent effect on the Gimp context of the server.

The gimp-exec client can send a file containing a Scheme snippet to the server. The usage for gimp-exec client is:

Usage: gimp-exec filename [IP adress] [port]

Example client/server interaction

Suppose you have installed the gimp-exec client and have a file named test.scm whose contents are:

(+ 2 3)
(gimp-message "test")

Invoking the client and submitting the file to the server:

>gimp-exec test.scm

The client prints what the server returns, and then on a new line prints “Success”, and then the client quits.

>gimp-exec test.scm
5(#t)#<EOF>
Success
>

Note that the server returns whatever the interpreter writes to stdout. The server returns what you might see in a REPL. Here the client has removed newlines. Here the call to gimp-message had invisible side effects and returned “(#t)”

A snippet can also call the Scheme display function to write to stdout.

Many snippets are concerned with side effects on image files, and less concerned with output to stdout, except as indication of success.

When a snippet has an error, the server returns an error message instead of the stdout. The client prints the error message.

>gimp-exec test-error.scm
Error: syntax error: unexpected right parenthesis
>

Note that the client has communicated with the server but does NOT print “Success” because the interpreter returned an error for syntax in the snippet.

The protocol

You can skip this unless you are developing a client.

A client sends a header of three bytes. The first byte is a magic byte indicating the protocol in use. The second and third byte are the length of the subsequent command.

A client then sends the command itself.

The server receives the header and the command, and interprets it as a Scheme text. Then the server responds.

The server first sends a header of four bytes. The first byte is a magic byte indicating the protocol in use. The second byte is a boolean that is true if the interpreter returned an error. The third and fourth bytes encode a 16-bit integer length of the rest of the response.

Then the server sends the rest of the response. Which is either the output to stdout of the interpreted snippet, or an error message.

!!! For both the server and the client, when they use the recv() system call that is non-blocking, the call might use the flag MSG_WAITALL to ensure that all bytes are received, since recv() can return with whatever bytes are available. Or the server and client should use some other strategy for assembling the components of the protocol. The server sends a header and a response body in separate messages, in two sends. The recv() call does not guarantee that a message is complete. When there are network errors, partial messages might be received, or the header message might be received and the response message never received.

Stopping the server

You can stop the server by quitting the Gimp app. The server is a separate process, but a child process of the Gimp app.

Starting the server without a Gimp window

You can start the server without a visible Gimp window by starting Gimp in batch (or headless) mode:

>gimp --no-interface --batch-interpreter=script-fu-eval
  --batch="(plug-in-script-fu-server 1 \"127.0.0.1\" 10008 \"/tmp/SFserver.log\" )"

See below “Headless Gimp on a server”

ScriptFu Text Console

ScriptFu Text Console is a textual command line similar to the graphical ScriptFu Console. It is an application program.

It is rarely used. It lacks the editing and history capabilities of the graphical ScriptFu Console.

Using the Text Console

In a terminal i.e. at a command line:

>gimp --no-interface --batch-interpreter=script-fu-eval --batch=-"

This magic encantation doesn’t name “plug-in-script-fu-text-console”, the name of the PDB procedure that is the plugin for ScriptFu Text Console. So how does it work? Behind the scenes, that plugin is invoked. Loosely speaking “–batch=-” denotes: read from stdin. Other plugins should not call the PDB procedure “plug-in-script-fu-text-console”; only the magic incantation should call it.

Expect to see in the terminal:

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

ts>

Now you can enter snippets followed by carriage return:

ts> (+ 2 3)
5
ts>

The text console responds with the result of interpretation, and then another prompt.

The prompt is “ts>” but the interpreter is ScriptFu, Gimp’s wrapper of the original TinyScheme interpreter. So you can also call Gimp’s PDB procedures:

ts> (gimp-get-images)
(0 #())
ts>

Control-C will terminate the text console, reverting to the shell prompt.

Headless Gimp on a server

The word “headless” may mean several things, a computer:

  • without an attached display device, also called a monitor
  • without a windowing and desktop environment such as X11 Xorg or Wayland or Cocoa
  • without a graphical toolkit library, such as Gtk or Qt

In other words, serving a stream of bytes as characters. Also known as a “server”.

Starting ScriptFu tools on a headless server

The ScriptFu tools: Text Console, Eval, and Server are in some sense headless. As seen in the examples above, but where the tools were started from a Gimp that has a window.

To be headless in the full sense, you can start the tools using the gimp-console. Gimp-console is a Gimp executable built without Gtk and thus without a display or window.

To serve ScriptFu Text Console fully headless, but locally in a current terminal:

gimp-console-2.99 --batch-interpreter=plug-in-script-fu-eval --batch=-

To serve ScriptFu Server fully headless, on the loopback net:

gimp-console-2.99 --batch-interpreter=plug-in-script-fu-eval
  --batch="(plug-in-script-fu-server 1 \"127.0.0.1\" 10008 \"/tmp/SF.log\" )"

Note some double quotes are escaped from the shell.

Note that the IP address and the filename are strings. You can choose a different IP address to expose the server to an outside network.

Note you don’t need “-i” which is short for “–no-interface” because the gimp-console never tries to open a display or window.