GIMP Developer Site now have improved navigation!
Script-Fu Programmer's Reference

Script-Fu Programmer's Reference

This describes version 3 of Script-Fu, a language for scripting or writing plugins for the GIMP application.

The Script-Fu language is interpreted. An embedded interpreter underlies each plugin written in Script-Fu. Architecturally, the Script-Fu interpreter wraps another interpreter, the TinyScheme interpreter.

This is a reference. You can find a definition of what is a GIMP plugin and on what Script-Fu differs from other interpreted plugins on About Plug-ins and Filters.

Versions

Script-Fu itself is not versioned and has not changed much in GIMP version 3, but the bound PDB API has.

A document Changes in ScriptFu v3 explains the changes needed to port a script from GIMP version 2.X to 3.

References to underlying languages

Script-Fu language is a dialect or extension of underlying languages. The language descends from TinyScheme from Scheme from Lisp.

This documents what is atop or special or different from the underlying languages. See also:

ScriptFu more or less conforms to the R5RS standard, with the notable exception that it lacks hygenic macros.

Features of the Script-Fu language

These are features beyond simple Scheme or TinyScheme:

Script-Fu special functions

These declare a plugin to the PDB. These functions are not in the Scheme language proper, and not in the PDB. They are implemented in C language and bound as foreign functions to Scheme. The special functions are:

Calls to these functions are usually located towards the end of a plugin script file. Order is important; they are usually in an order like above.

The first argument to these functions is a string and it is the declaration of a plugin’s signature. The declaration of a plugin’s signature describes both the signature registered in the PDB and the signature of the run function defined in Scheme at the top of a script, and it should be the same for both.

The name should have prefix “plug-in-”, by convention. We recommend not using the prefix “script-fu-” in the name.

The rest of the arguments after the signature are metadata arguments.

The signature of the run function in a Script-Fu script does not have a run mode argument. Script-Fu hides it from a script since a script should not implement GUI directly. Only if it calls other plugins (in the PDB), it should usually pass run mode NON-INTERACTIVE so the called plugin does not present its dialog.

script-fu-register-procedure

Use script-fu-register-procedure to declare PDB procedures that are not filters or renderers. “Procedure” denotes the general case. Plugins that are filters or renerers, taking an image and drawables, are special and you instead declare them using script-fu-register-filter.

script-fu-register-procedure declares a script that:

  • is always enabled
  • can save its settings between sessions

Here is an abbreviated example:

Scheme
(define script-fu-my-plugin (radius)
    body)

(script-fu-register-procedure "script-fu-my-plugin"
  "My plugin..."
  "Example plugin."
  "author/copyright holder"
  "copyright dates"
  SF-ADJUSTMENT "Radius" (list 100 1 5000 1 10 0 SF-SPINNER)
)

script-fu-menu-register

Another example. A plugin may define a menu item appearing in a context menu. This is a common use case for script-fu-register-procedure. The context is the set of choices in GIMP that affect drawing operations, for example, the current Brush.

Note that the plugin does NOT receive the choice in context but must get it from the context before operating with/on it.

Using the same registration as above:

Scheme
(define script-fu-my-plugin (radius)
    ; do something with the current brush
    (gimp-context-get-brush))

(script-fu-register-procedure "script-fu-my-brush-plugin"
   ...same registration as above...)

(script-fu-menu-register "script-fu-my-brush-plugin"
                     "<Brushes>/Brushes Menu")

In this example, the menu item “My plugin…” appears in the context menu (pops up with right mouse button) in the Brushes dockable window, and is always enabled. The script run func gets the current brush and does something to or with it.

One more example. A plugin may want to use a file that is not open as an image.

Scheme
(define script-fu-my-plugin (filename)
    ; open and do something with the file
    )

(script-fu-register-procedure "script-fu-my-plugin"
  "My plugin..."
  "Example plugin."
  "author/copyright holder"
  "copyright dates"
  SF-FILENAME "Image to do something with" ""
)

(script-fu-menu-register "script-fu-my-plugin"
                     "<Image>/File")

In this example, the menu item My plugin… appears in the File menu on the menubar. It is always enabled.

When a user chooses the menu item, a dialog appears that lets a user choose a file. When the user clicks OK, the plugin opens the file and does something with it.

script-fu-register-filter

Use script-fu-register-filter to declare a PDB procedure that take an image and drawable components of images.

script-fu-register-filter declares a script that:

  • is a filter or renderer: taking a user selected image and its selected components
  • is multi-layer capable, processing one or more drawables
  • can save its settings between sessions
  • has a menu item that is enabled/sensitized when a user selects image components
You don’t specify the first two arguments “image” and “drawables”. Those arguments are implicit. As a convenience, ScriptFu registers those arguments in the PDB for you. If you do, see: The SF- enumeration of plugin capabilities

The run func that you define in your script must have those formal arguments (and the PDB Browser will show those arguments). For example:

Scheme
(define script-fu-my-plugin (image drawables arg1 arg2) body)

The Script-Fu binding to the PDB

The binding from Scheme to GIMP is part of the Script-Fu system.

Unlike bindings for other languages of plugins (such as the Python binding) the binding is not automatic using GObject Introspection (GIR.) Instead, the binding is mostly hand-coded in C.

The binding is to the PDB API, instead of the libgimp API. The binding defines a symbol into the Scheme language for each procedure in the GIMP PDB. The binding also marshalls arguments to and return values from calls to the PDB and marshalls C types to Lisp types and vice versa. That way, a Script-Fu plugin script can call a PDB procedure.

  • On a successful call to the PDB, Script-Fu binds the normal returned values into a Scheme data structure. The call yields that Scheme data structure, which is a list in v2 dialect and the single value itself on v3 dialect. See: Using the version 3 dialect for PDB values
  • On a failed call to the PDB, the calling script usually does not continue. Instead, the plugin returns, propagating the error. In Scheme terminology, the script’s call to the PDB throws a Scheme exception, which if not caught calls the error function which terminates the plugin script that is calling the PDB. See also Exceptions and the *error-hook*

This table shows the corresponding Scheme type for each declared C type in the PDB documentation.

Declared C type Scheme type
int Integer
double Float
char* String
gboolean #t or #f
GStrv List of String
Gimp objects e.g. GimpImage Integer (ID)
GimpCoreObjectArray Vector of Numeric (ID)

To understand the signatures of Script-Fu’s binding of calls to the PDB, read the C signatures in the Procedure Browser and mentally convert to a Scheme type. For example, a C integer converts to a Scheme numeric and a C string converts to a Scheme string.

The document Adapting scripts to PDB version 3 describes other conversions from GIMP types to Scheme types.

Keyword arguments in calls to plugins in the PDB

On v3 scripts, you should call plug-in procedures using keyword syntax.

This is supported for calls to plugins, but not for calls to internal procedures.

Keyword syntax is also known as “named arguments” so all arguments must have names, not just trailing arguments. The syntax is like the syntax from other Scheme implementations. The characters “#:” precede the name of the argument (as given in the PDB API). Example:

Scheme
(plug-in-tile #:run-mode   RUN-NONINTERACTIVE
              #:image      testImage
              #:drawables  testLayers
              #:new-width  10
              #:new-height 20
              #:new-image  #f)

Using keyword arguments is optional, but it is all-or-nothing within a call: all arguments must have keywords, or none.

We recommend you use keyword style arguments for calls to plugins. It future-proofs a script from changes to plugin signatures. It also lets you omit arguments inside the sequence of args (not just omit trailing arguments.) It also lets you pass arguments in an order different from the order declared in the PDB.

Pre-defined symbols

Script-Fu defines many symbols over and above TinyScheme and Scheme.

These symbols are immutable and you cannot globally redefine them although you could redefine them in a let block.

Pre-defined symbols for GIMP constants i.e. enumerations

Specially, the Script-Fu language defines symbols for each enumeration value of the GIMP library and the GEGL library. You often pass these symbols as arguments to calls to the PDB. These symbols are in upper case. These symbols match the symbols in the respective libraries, except they omit the “GIMP_” or “GEGL_” prefix.

For example, RUN-INTERACTIVE is the symbol for one of the enumerated values in the GimpRunMode enumeration.

Script-Fu specific pre-defined symbols for constants

Script-Fu defines these symbols:

  • TRUE: alias for 1
  • FALSE: alias for 0
  • NULL: alias for 0
These are C-isms that you should not use in new code, only for SF-TOGGLE and boolean arguments. See also: FALSE and TRUE symbols are deprecated

Symbols for strings about the filesystem:

  • gimp-directory: the path to the directory where GIMP is installed, aka PREFIX
  • gimp-data-directory
  • gimp-plug-in-directory
  • gimp-locale-directory
  • gimp-sysconf-directory
  • script-fu-sys-init-directory: the directory containing init.scm that ScriptFu reads
  • script-fu-user-init-director: the directory where users install .scm files read at init time
  • DIR-SEPARATOR: the ASCII character used as separator in filesystem paths, e.g. forward slash
  • SEARCHPATH-SEPARATOR: the ASCII character used as separator in PATH lists, e.g. colon

The SF- enumeration of IN argument types

Script-Fu defines symbols used to declare types of arguments to a plugin. You declare each IN argument in a sequence of three values, and you can declare many arguments. For example, SF-ADJUSTMENT:

Scheme
(script-fu-register-procedure "script-fu-test-sphere"
  ... metadata arguments...
  SF-ADJUSTMENT "Radius (in pixels)" (list 100 1 5000 1 10 0 SF-SPINNER)
  ... more triples, one for each additional argument ...
)

The three values in a triple are:

  • a SF- constant (see below)
  • a string label to appear alongside a widget in the plugin’s dialog
  • a value that defines a default or further constrains the argument (a list for some argument types)
The corresponding type in Scheme and C is not well documented, but you can easily infer it. When you browse the PDB to study the signature of a plugin, you will see the declared types as the corresponding bound C types.

The SF- enumeration declares not only the type of the argument, but the kind of widget used in a dialog for the plugin. For example, Script-Fu defines symbols SF-SLIDER and SF-SPINNER used to declare widget types for arguments of type SF-ADJUSTMENT.

SF-BRUSH, SF-FONT, SF-GRADIENT, SF-PALETTE, and SF-PATTERN all specify an argument of type GIMP Resource. Resources are data installed with GIMP.

Similarly, SF-IMAGE, SF-LAYER, SF-CHANNEL, SF-DRAWABLE, and SF-VECTORS all specify an argument having one of GIMP’s object type. When you declare an argument having the type of a GIMP object, the third argument is usually just an ignored place holder “-1”.

In ScriptFu, resources and objects are represented by their integer ID’s. A script should treat these opaquely, receiving them and passing them unaltered to other functions.

The SF- enumeration of plugin capabilities

Since GIMP version 3, a plugin can declare its capabilities re whether it can process multiple drawables (usally layers) with an argument called “multilayer-capability” (SF-*-DRAWABLE). Then a plugin’s menu item is enabled in the GIMP GUI only when the user has selected an appropriate count of drawables.

These are valid only for new-style, version 3 plugins that register by script-fu-register-filter.

The argument follows the “image types” argument, which declares the capability of the plugin to process various image modes. Here is an example:

Scheme
(script-fu-register-filter "script-fu-test-sphere-v3"
  "Sphere v3..."
  "Test script-fu-register-filter: needs 2 selected layers."
  "authors"
  "copyright holders"
  "copyright dates"
  "*"  ; image modes: any
  SF-TWO-OR-MORE-DRAWABLE  ; multi-layer capability argument
  SF-ADJUSTMENT "Radius" (list 100 1 5000 1 10 0 SF-SPINNER)
)

The “multilayer-capability” argument can have the following values:

  • SF-ONE-DRAWABLE: expects exactly one drawable (will still receives a vector of drawables, but the vector should be of length one)
  • SF-ONE-OR-MORE-DRAWABLE: expects and will process one or more drawables (typically means a script will filter the given drawables independently and sequentially)
  • SF-TWO-OR-MORE-DRAWABLE: expects and will process two or more drawables (typically means a script will combine the given drawables, say into another drawable by a binary operation)

This is only a declaration, a contract; whether your defined run func does what it promises is another matter. A well-written script should throw an error when it is not passed the declared number of drawables, either more or fewer than declared. See: Respect multi-selected layers

Unicode support

Unlike some Scheme dialects and unlike the original TinyScheme, the Script-Fu interpreter implements Unicode strings. All data of string type in Script-Fu are sequences of Unicode characters, i.e. wide characters.

Script-Fu encodes Unicode character using UTF-8, so a character is one to three bytes. The length of a string is the length in characters, not bytes. See: string length

In a Lisp script, you represent certain literals by a sharp constant. In Script-Fu, you can represent Unicode characters by sharp character constants :

Scheme
#\a ;represents lower case ASCII "a".

You can also represent Unicode characters by sharp numeric constants, for example:

Scheme
#\x3bb ;represents the two byte encoding of the Greek character called lambda, whose codepoint is hexadecimal 3bb.

Symbols are not Unicode but ASCII. (Here symbol has the Lisp meaning of a name in the script.) So a script’s text must be ASCII. Evaluation of string data that is Unicode might not work.

i18n internationalization/localization

In a Script-Fu plugin script, you can annotate with _ a string literal for translation:

Scheme
_"To be translated."

Any string literal so annotated will usually appear in the user’s native language in the GUI dialog for a plugin.

In Lisp terminology, the “_” character marks a special form that the Script-Fu interpreter recognizes. It is not part of the Scheme language. It is not in the form of a function call in Lisp.

Script-Fu does not support translation of strings generated at run time. For internationalization to succeed, a translator must translate annotated strings, into a .po file. At install time, the build system must compile and install the translations. See Internationalizing GIMP Scheme Plugins for more information.

ftx and re extensions

Script-Fu includes the ftx (OS and filesystem) and re (regular expression) extensions. An extension in Scheme is C code that defines more functions into the language.

See the gimp repo for more information:

Byte IO

Since characters are Unicode in Script-Fu, you can’t use characters as bytes. Also, Byte IO is not part of the RSR5 standard.

Since version 3, however, ScriptFu has functions to read and write streams a byte at a time. See: Type byte

Other defined functions

Script-Fu has some functions not in Scheme and not specific to GIMP. Some are implemented in the TinyScheme interpreter itself, and some in Scheme scripts in the usual init.scm for a Scheme interpreter.

The print function is not in RSR5 but is defined in ScriptFu.

The quit function is usually defined in Scheme but with implementation dependent meaning re a process.

The cond-eval function is defined but in a limited way. That function lets you evaluate conditionally on the prior loading of other Scheme modules following the SRFI conventions.

The Script-Fu interpreter

If you are an “advanced” user, who might want to understand the implementation of some built-in Scheme function, this loosely describes how the interpreter works.

Initilization of the interpreter

We use the words “Script-Fu loads” to mean similar to the Scheme load function, which reads a script file and evaluates it. Often a loaded file contains only definitions, i.e. calls to “(define …)”, which is similar to an import in other languages. But a loaded file may have more than just defines. See the special case for Script-Fu below.

The initialization process can provide some backward compatibility. Any backward compatibility in Script-Fu might change in the future. For forward compatibility or future-proofing, a script author should not use deprecated functions in newly written scripts.
  1. Script-Fu initializes the embedded TinyScheme interpreter. This defines core Lisp functions into the interpreter state. The embedded TinyScheme interpreter and these core functions are written in C.

  2. Script-Fu makes extensions ftx and re define their functions into the interpreter. These extensions are in C.

  3. Script-Fu defines its special functions into the interpreter. The special functions are written in C.

  4. Script-Fu introspects or queries the PDB and defines into the interpreter each procedure in the PDB. A Scheme call to the PDB passes through wrapper functions written in C.

  5. Script-Fu defines into the interpreter aliases for PDB procedures whose name has changed from prior versions of GIMP. A table in C associates alias names to new names. For backward compatibility, only in Script-Fu are the old names deprecated, i.e. aliased and still useable, and this might change in the future.

  6. Script-Fu loads all the scripts in the directory /scripts/script-fu-init. This directory is part of a GIMP installation. This directory always contains the conventional script file: init.scm, as in other Scheme implementations. The file init.scm defines more core functions into the interpreter, such as cadr. This step is typical of Lisp interpreters. But the file is slightly altered from the usual TinyScheme init.scm.

  7. Script-Fu loads /scripts/script-fu-init/script-fu-compat.scm This file is a Scheme script. For backward compatibility, it might define certain deprecated Scheme functions from earlier versions of Script-Fu that used the SIOD dialect of Lisp (not anymore on GIMP 3.0). It also defines the not-deprecated random function for random number generation.

  8. Script-Fu loads /scripts/script-fu-init/plug-in-compat.scm This file is a Scheme script. For backward compatibility, it might define functions for certain deprecated PDB procedures from earlier versions of the GIMP PDB (not anymore on GIMP 3.0). The functions are written in Scheme and wrap calls to newer PDB procedures. They are not just aliases for renamed PDB procedures, the wrappers may do more or convert signatures.

  9. Script-Fu loads each script file in two /scripts directories, the user owned /scripts directory and the system-wide /scripts directory. This defines (temporarily) into the interpreter state all the PDB functions that are old-style plugin written in the Script-Fu language (thanks to the extension protocol) as well as any other defined functions in those files!

    So, any Scheme files (.scm) in those directories that do not define plugins can never-the-less define into the interpreter state. For example, the file /scripts/script-fu-util.scm defines several “utility” functions into the interpreter state. Thus every instance of the Script-Fu interpreter locally has the body of the functions defined in those files. In other words, script files in those directories can serve as libraries.

A script can also load Scheme text files, even one whose suffix is not .scm, by explicitly calling load passing a path to a file. You can form a path to the standard script directories with the string constant gimp-directory.

Errors

Plugins written in Script-Fu language do not return a value, other than an error status, because Script-Fu discards the value of the last evaluation in the run function. So, a Script-Fu plugin returns a success error status unless

  • the interpreter throws an error in Scheme code (see many kinds of interpreting-related errors below)
  • or a called PDB procedure returns an error (see “Run-time PDB” below)
  • or the plugin calls the quit or error functions (see “Script data” below)

There are some errors only detected in newly installed scripts, i.e. at query time:

  • Syntax Discovered at query time i.e. after the first install, by the embedded TinyScheme interpreter. For example, unmatched parenthesis.

  • Registration Discovered at query time i.e. after the first install, by Script-Fu. The data for registration in a call to script-fu-register* is flawed, e.g. not a sequence of triplets.

These two errors are only printed to stderr/stdout and the menu item will not be in the GIMP app so you can’t invoke the plugin.

Other error kinds will not be detected until run time of the plugin’s run function, when a user invokes the plugin.

  • Binding Discovered at run time, by the embedded TinyScheme interpreter. A name i.e. symbol is not bound. Typically a typo. Or, a function name that is in Scheme but not TinyScheme, or a named procedure that is no longer in the PDB. Also known as “unbound variable.”

  • Scheme Type Discovered at run time, by the embedded TinyScheme interpreter. Some Scheme functions dynamically check the type of their arguments.

  • PDB Type Discovered at run time, by the Script-Fu wrapper. Script-Fu checks the Scheme type of arguments in calls to a PDB procedure, and the PDB checks the C type of arguments in calls to a PDB procedure. The PDB also range checks some arguments. Also know as a “calling error.”

  • Run-time PDB Discovered at run time, by a called PDB procedure. For example, passed an image type that the procedure cannot handle. Also known as an “execution error.”

  • Script data Discovered at run time, by a script, in some data. A script should call throw, quit, or error to declare such an error. See: Messaging functions

  • System error Discovered at run time, by the OS or by the embedded TinyScheme interpreter. For example, a runaway script exhausted memory allocated by the interpreter, or a file operation failed.

Exceptions and the *error-hook*

Errors are usually fatal i.e. stop evaluation of a plugin script.

Errors are Scheme exceptions. On an exception, the interpreter unwinds call frames to the first catch Scheme function or finally calls the error Scheme function which is fatal. An example of a script that uses catch is contact-sheet.scm which catches file opening errors and ignores them.

They symbol *error-hook* is a hook in the embedded TinyScheme interpreter. ScriptFu has a standard definition of the *error-hook* symbol on the usual init.scm script, named script-fu.init. The standard definition is equivalent to just Scheme throw.

Advanced users can redefine the *error-hook* symbol. Typically used in test frameworks. When they do, the behavior of the error function can be changed by the new *error-hook*. A call to error generates an exception which the *error-hook* catches.

(There are other hook symbols in the embedded TinyScheme interpreter, e.g. *sharp-hook* which you can redefine to alter the parsing of sharp constants.)

Old and new styles of Script-Fu plugins

After reading Features of the Script-Fu language, you are ready to write a Script-Fu plugin.

Since the language is interpreted, there is no compilation step. There is an install and registration step. Installation is just copying a script file to a certain directory. Registration happens when GIMP runs and queries the files in the directory.

There are two styles of Script-Fu plugins that can be installed and registered:

Old-style plugins (in version 2 and version 3):

  • are installed scattered in /scripts
  • are served by the Script-Fu extension process (that can crash cripple the GIMP app)
  • call deprecated script-fu-register, declaring all arguments
  • have a limited GUI implemented by the Script-Fu system

New-style plugins (only in version 3):

  • are installed in /plug-ins like other plugins
  • are interpreted each in a separate process
  • can call script-fu-register-filter, not declaring standard args
  • have a GUI provided by the GimpProcedureDialog class of libgimp

Installation of such new-style scripts must follow rules for interpreted plugins. A script file must:

  1. be in a directory having the same base name, for example: ~/.config/GIMP/0.0/plug-ins/script-fu-my/script-fu-my.scm

    It is only a convention to name scripts starting with “script-fu-”.

  2. have a file suffix corresponding to an interpreter (in this case, .scm)

  3. have executable permission (relevant for Unixes like Linux and macOS)

  4. have a shebang on the first line, for example:

    Scheme
    #!/usr/bin/env gimp-script-fu-interpreter-3.0
    ;!# Close comment started on first line.
    If the script has translatable strings, it should also have a second line as above, to accomodate parsing by gettext. (Note that ScriptFu doesn’t actually support multi-line comments using #!, and this is a trick to fool gettext, which parses a script as if it did support multi-line comments.)

The advantage of installing a script in the /plug-ins directory is that, as said, such a script will execute in its own process. If it crashes, it doesn’t affect GIMP or other scripts.

Templates for a Script-Fu plugin

Minimal, hello-world plugin

This is a minimal old-style plugin (not recommended for new scripts):

Scheme
(define (script-fu-basic-plug-in) (gimp-message " hello world "))
(script-fu-register "script-fu-basic-plug-in" "Basic" "test" "me" "free" "2023" "")
(script-fu-menu-register "script-fu-basic-plug-in" "<Image>/Fu-plug-in")

The first line defines the “run function” of the plugin. Here the run function has no arguments and just says “hello world.” You would craft a run function to do something useful.

The second and third lines are special functions of Script-Fu.

The second line declares metadata and the signature of the plugin. Here, the plugin has no arguments, and empty signature.

The third line declares the plugin’s appearance in the GIMP app menus, which is optional.

This text would be in a file named “hello-world.scm” installed in the /scripts directory.

Version 3 filter plugin

This is a minimal plugin in the new style of version 3:

Scheme
#!/usr/bin/env gimp-script-fu-interpreter-3.0
(define (script-fu-basic-plug-in
          image
          drawables)
        (gimp-message " hello world "))
(script-fu-register-filter "script-fu-basic-plug-in" "Basic" "test" "me" "free" "2023" ""
                            SF-ONE-DRAWABLE)
(script-fu-menu-register "script-fu-basic-plug-in" "<Image>/Fu-plug-in")

One difference is the shebang in the first line. This means the standalone Script-Fu interpreter will interpret the script, independently from other plugins.

Another difference is the run function has formal arguments for the standard arguments for a filter: image and drawables, but the call to script-fu-register-filter does not declare them.

Another difference is the call to script-fu-register-filter has the argument SF-ONE-DRAWABLE to specify the capability of the plugin re multi layers. This example is contrived, because the plugin actually ignores the drawables and actually could work no matter how many layers the user selected.

This text would be in a file named “hello-world.scm” installed in the /plug-ins/hello-world directory (a directory having the same name as the plugin script file.) The file must have executable permissions.

Other example plugins

A more elaborate hello-world in the Gimp repo illustrates a version 3 plugin, installed to the /plug-ins directory and independently interpreted, but not registering as a filter.

A script in the Gimp repo illustrates all types of arguments that you can declare in the signature of a plugin and demonstrates the corresponding widgets.

Last updated on