Difference between revisions of "Hacking:ScriptFu"

From GIMP Developer Wiki
Jump to: navigation, search
(Initial page for ScriptFu)
 
(Discuss console, debugging, object ID's, future directions, architecture)
Line 138: Line 138:
 
[https://schemers.org/Documents/Standards/R5RS/HTML/ Revised5 Report on the Algorithmic Language Scheme]
 
[https://schemers.org/Documents/Standards/R5RS/HTML/ Revised5 Report on the Algorithmic Language Scheme]
  
Early versions of GIMP used a different dialect of Lisp for ScriptFu plugins.  You may occasionally find ancient scripts in that dialect.
+
Early versions of GIMP used a different dialect of Lisp for ScriptFu plugins (called SIOD.) You may occasionally find ancient scripts in that dialect.
  
 
[https://www.gimp.org/docs/script-fu-update.html A history and porting guide for GIMP TinyScheme plugins]
 
[https://www.gimp.org/docs/script-fu-update.html A history and porting guide for GIMP TinyScheme plugins]
 +
 +
[https://gitlab.gnome.org/GNOME/gimp/-/blob/master/plug-ins/script-fu/tinyscheme/Manual.txt The language manual for TinyScheme as used by GIMP.]
  
 
Lisp is beautiful because it is can be interpreted by a small program (an interpreter for Lisp written in Lisp can be a few tens of lines.)
 
Lisp is beautiful because it is can be interpreted by a small program (an interpreter for Lisp written in Lisp can be a few tens of lines.)
Line 156: Line 158:
  
 
Getting people to translate your strings is another matter.
 
Getting people to translate your strings is another matter.
 +
 +
 +
== The ScriptFu Console ==
 +
 +
You can open a '''ScriptFu Console''' using the menu item '''Filters>Development>Script-Fu>Script-Fu Console'''.
 +
 +
The console is a window executing a REPL, a read-evaluate-print-loop.
 +
That is, you enter a construct in the ScriptFu language, enter Return, and see a printed result.
 +
 +
The console executes in the current context of the GIMP app.
 +
Thus for example, in the console:
 +
 +
<code>  (gimp-get-images) </code>
 +
 +
will return, and print the representation of, a list whose first element is the number of images, and whose second element is a vector of image ID's.
 +
 +
The '''ScriptFu Console''' lets you browse the PDB.
 +
It shows the signature of PDB procedures in terms of C language types,
 +
so you must mentally translate into Scheme language.
 +
 +
The '''Apply''' button in the '''Script-Fu Procedure Browser''' will translate for you and paste a construct into the '''Script-Fu Console'''.
 +
Then you can enter Return in the console to execute the pasted construct.
 +
 +
 +
== Debugging ScriptFu scripts==
 +
 +
=== Print GIMP messages ===
 +
 +
You can print to the message bar of the GIMP app using:
 +
 +
<code>  (gimp-message "my message") </code>
 +
 +
The messages are ephemeral, only visible until the next message overwrites it.
 +
 +
=== Enable tracing ===
 +
 +
You can enable the tracing feature of the interpreter using:
 +
 +
<code>  (trace 1) </code>
 +
 +
usually at the start of your script.
 +
This will make the interpreter print many messages about its execution,
 +
to the console (terminal, i.e. to stdout/stderr) where the GIMP app was started.
 +
The trace is not easy to understand,
 +
it shows the nested or recursive nature of Lisp interpretation.
 +
The trace is most useful to explain any errors in Scheme syntax.
 +
The trace is less useful to explain errors in calls to PDB procedures.
 +
 +
=== Write to a console ===
 +
 +
You can write to the console using:
 +
 +
<code> (write "my message" (open-output-file "/dev/stderr")) </code>
 +
 +
That will write to the console where the GIMP app was started.
 +
 +
You can also use other Scheme I/O functions to say write to a file.
 +
Scheme uses "port" objects.
 +
The call above to open-output-file returns a port object.
 +
 +
=== Enable ScriptFu logging of PDB calls ===
 +
 +
Starting with GIMP 3, the ScriptFu interpreter uses GLib logging.
 +
You can enable it by setting an environment variable before starting the GIMP app in a console:
 +
 +
<code> export G_MESSAGES_DEBUG=scriptfu  </code>
 +
 +
Then the ScriptFu interpreter will print many messages about its interpretation of calls to the PDB.
 +
 +
For example:
 +
 +
(<code> script-fu:102): scriptfu-DEBUG: 12:50:33.159: In script_fu_marshal_procedure_call() </code>
 +
 +
 +
=== ScriptFu warnings go to a console ===
 +
 +
If you suspect errors in a script, it it important to start GIMP in a console,
 +
since ScriptFu prints warnings to the console.
 +
 +
For example, you may see:
 +
 +
<code> (script-fu:102): scriptfu-WARNING **: 12:45:44.166: in script, permitting too few args to gimp-edit-copy </code>
 +
 +
These warnings do not depend on setting the environment variable G_MESSAGES_DEBUG.
 +
 +
 +
== ScriptFu uses numeric GIMP object ID's ==
 +
 +
GIMP identifies its objects with numeric ID's (as well as with C pointers.)
 +
ScriptFu uses the numeric ID's internally.
 +
 +
This is opaque to scripts.  That is, ordinarily you need not think about it.
 +
You store returned objects in Scheme variables without worrying about it.
 +
However, a printed representation of a GIMP object appears as a numeral.
 +
And you could use a literal numeral when a reference to a GIMP object is required (in extraordinary circumstances.)
 +
 +
 +
== ScriptFu architecture ==
 +
 +
The ScriptFu interpreter and the ScriptFu Console are "GIMP extensions", that is, separate processes.
 +
The ScriptFu interpreter receives a message from the GIMP app when you choose certain menu items.
 +
 +
If the ScriptFu interpreter crashes, you must restart GIMP.
 +
 +
The ScriptFu interpreter process reads all scripts when it starts.
 +
If you edit a script, you can ask the running ScriptFu interpreter process to reread the scripts.
 +
Use the menu item '''Filters>Development>Script-Fu>Refresh Scripts'''
 +
You can't do this when a script is already running (while its dialog is up.)
 +
 +
(The architecture is different for other interpreters, e.g. the Python interpreter,
 +
in which case the interpreter is started, and terminates, when you choose a menu item.)
 +
 +
 +
== Future directions using GObject introspection ==
 +
 +
Starting with GIMP 3, the preferred architecture for plugins uses GObject introspection (GI) of the libgimp API.
 +
For example, a GIMP Python plugin usually uses the PyGObject module for GObject introspection.
 +
 +
GIMP developers are considering replacing the ScriptFu interpreter with a standard Lisp interpreter (Guile)
 +
that might be capable of GObject introspection.
 +
 +
The ScriptFu interpreter is not capable of GObject introspection.

Revision as of 13:30, 12 May 2021

ScriptFu refers to GIMP support for plugins written in the Scheme language.

The GIMP Scheme interpreter implements TinyScheme, a dialect of the Scheme language, a dialect of the Lisp language. The GIMP TinyScheme interpreter specializes it for image processing, adding a few more symbols to the TinyScheme language.

Some Scheme plug-ins are distributed with GIMP and some are distributed by third parties.

This describes GIMP 2 and GIMP 3 plugins. ScriptFu is mostly unchanged from GIMP 2 to GIMP 3, except to accomodate changes to GIMP itself.


Audience

This is mainly for authors of third party plugins. This page is a basic introduction with references to further reading. This is somewhat about programming language theory: ScriptFu as a language.

There are many Scheme plugins in the GIMP repository, providing important capabilities of GIMP. If you write a particularly useful Scheme plugin, it could find its way into the GIMP repository.

If you are interested in enhancing the Scheme interpreter of GIMP, it is written in C and its source is in the GIMP repository under /gimp/plug-ins/script-fu.


Overview

GIMP plug-ins let you program image manipulation algorithms. Scheme language GIMP plug-ins are interpreted. They can call procedures in the GIMP Procedural Database (PDB) as well as the functions built into the Scheme language. They are distributed as text files called scripts with suffix ".scm". They are registered in the PDB with a name like "script-fu-...". They may appear in the GIMP user interface, in pull-down or pop-up menus.


Tutorials

A tutorial

Another tutorial from a paper book.

An out-of-date tutorial

Installation and debugging is covered in the tutorials.


Scheme plugins and the GIMP Procedural DataBase (PDB)

Scheme plugins are in the PDB and call the PDB

Calling procedures in the PDB

Scheme language plugins can call PDB procedures, as well as functions of the Scheme language. (They do not call functions from the libgimp library.) Example Scheme constructs for calling a PDB procedure:

(script-fu-clothify image drawable 1 2 3 4 5) calls the PDB procedure script-fu-clothify, which is another plugin
(gimp-image-get-drawables image ) calls an internal procedure, more or less the get-drawables method of the Image class of the Gimp module

PDB procedures called from a Scheme plugin return a list.

Scheme plugins in the PDB

Scheme language plugins are also in the PDB. Plug-ins register themselves in the PDB. The functions built into the interpreter for registering a plugin are:

  • script-fu-register
  • script-fu-menu-register

Registration means declaring:

  • the name and parameters of a plug-in (the signature)
  • other metadata such as help and author
  • declaring how and where a plug-in will appear in the GIMP menus, if at all.

ScriptFu plugins can return a value, when the script's run function's last line is a simple reference to a symbol. Unlike GIMP plugins in other languages, you do not register the types of return values.

All plugins understand a runtime "run mode". In NONINTERACTIVE (batch) mode, they do not provide a user interface. Most plugins take a run mode parameter. When a plugin calls a plugin, it usually passes a run mode. PDB procedures that are kind "Internal" do not usually accept a run mode parameter.


The language for defining ScriptFu plugin parameters

This is covered by many tutorials.

The only official documentation seems to be in the comments of the test-sphere.scm plugin in the GIMP repository.

Parameters are declared using a set of constants declared by the interpreter, the SF_... constants (an enumeration.)

Each parameter is declared by a triple of arguments to the script-fu-register function.

Each triple comprises:

  • a SF_... constant
  • a string name
  • a list that further specifies the parameter, the list contents depending on the SF_... constant

Most SF_... constants denote not only the type of the parameter, but how it appears in the dialog that ScriptFu can present in the GIMP GUI. (What kind of control widget will appear in the GUI.)


GIMP constants in ScriptFu

The ScriptFu interpreter also recognizes symbols for constants defined by GIMP. You use these symbols as arguments in calls to PDB procedures. They are generally of the form GIMP-... , that is, upper case with hyphens.


Examples and templates

Many examples can be found in the tutorials.

Many examples are in the GIMP repository at /gimp/plug-ins/script-fu/scripts.


A very brief and incomplete example, giving the basic structure of a plugin, is:

(define (script-fu-my-plugin 
...
)      )
(script-fu-register "script-fu-my-plugin"
...
)
(script-fu-menu-register "script-fu-my-plugin"
...
)

In the above example, you define the "run function" of your plugin, then call two functions to register it. After you install your script, your plugin will be in the PDB, and may appear in the GIMP GUI.



The Tiny Scheme language

Scheme is a dialect of Lisp. Lisp is a pure programmer's language with a very simple syntax.

GIMP provides a subset of the Scheme language called TinyScheme. The set of functions implemented by the TinyScheme interpreter of GIMP is smaller than the set implemented by the full Scheme language. But you can textually include third party Scheme functions inside your plug-in.

Revised5 Report on the Algorithmic Language Scheme

Early versions of GIMP used a different dialect of Lisp for ScriptFu plugins (called SIOD.) You may occasionally find ancient scripts in that dialect.

A history and porting guide for GIMP TinyScheme plugins

The language manual for TinyScheme as used by GIMP.

Lisp is beautiful because it is can be interpreted by a small program (an interpreter for Lisp written in Lisp can be a few tens of lines.) ScriptFu (the plugin support offered by GIMP) is implemented by a small interpreter written in the C language, part of GIMP


Internationalization

You can declare intent to internationalize strings in ScriptFu plugins using "_" notation before strings, for example:

_"Clothify..."

You only need to internationalize strings that appear in the GUI.

Getting people to translate your strings is another matter.


The ScriptFu Console

You can open a ScriptFu Console using the menu item Filters>Development>Script-Fu>Script-Fu Console.

The console is a window executing a REPL, a read-evaluate-print-loop. That is, you enter a construct in the ScriptFu language, enter Return, and see a printed result.

The console executes in the current context of the GIMP app. Thus for example, in the console:

(gimp-get-images)

will return, and print the representation of, a list whose first element is the number of images, and whose second element is a vector of image ID's.

The ScriptFu Console lets you browse the PDB. It shows the signature of PDB procedures in terms of C language types, so you must mentally translate into Scheme language.

The Apply button in the Script-Fu Procedure Browser will translate for you and paste a construct into the Script-Fu Console. Then you can enter Return in the console to execute the pasted construct.


Debugging ScriptFu scripts

Print GIMP messages

You can print to the message bar of the GIMP app using:

(gimp-message "my message")

The messages are ephemeral, only visible until the next message overwrites it.

Enable tracing

You can enable the tracing feature of the interpreter using:

(trace 1)

usually at the start of your script. This will make the interpreter print many messages about its execution, to the console (terminal, i.e. to stdout/stderr) where the GIMP app was started. The trace is not easy to understand, it shows the nested or recursive nature of Lisp interpretation. The trace is most useful to explain any errors in Scheme syntax. The trace is less useful to explain errors in calls to PDB procedures.

Write to a console

You can write to the console using:

(write "my message" (open-output-file "/dev/stderr"))

That will write to the console where the GIMP app was started.

You can also use other Scheme I/O functions to say write to a file. Scheme uses "port" objects. The call above to open-output-file returns a port object.

Enable ScriptFu logging of PDB calls

Starting with GIMP 3, the ScriptFu interpreter uses GLib logging. You can enable it by setting an environment variable before starting the GIMP app in a console:

export G_MESSAGES_DEBUG=scriptfu

Then the ScriptFu interpreter will print many messages about its interpretation of calls to the PDB.

For example:

( script-fu:102): scriptfu-DEBUG: 12:50:33.159: In script_fu_marshal_procedure_call()


ScriptFu warnings go to a console

If you suspect errors in a script, it it important to start GIMP in a console, since ScriptFu prints warnings to the console.

For example, you may see:

(script-fu:102): scriptfu-WARNING **: 12:45:44.166: in script, permitting too few args to gimp-edit-copy

These warnings do not depend on setting the environment variable G_MESSAGES_DEBUG.


ScriptFu uses numeric GIMP object ID's

GIMP identifies its objects with numeric ID's (as well as with C pointers.) ScriptFu uses the numeric ID's internally.

This is opaque to scripts. That is, ordinarily you need not think about it. You store returned objects in Scheme variables without worrying about it. However, a printed representation of a GIMP object appears as a numeral. And you could use a literal numeral when a reference to a GIMP object is required (in extraordinary circumstances.)


ScriptFu architecture

The ScriptFu interpreter and the ScriptFu Console are "GIMP extensions", that is, separate processes. The ScriptFu interpreter receives a message from the GIMP app when you choose certain menu items.

If the ScriptFu interpreter crashes, you must restart GIMP.

The ScriptFu interpreter process reads all scripts when it starts. If you edit a script, you can ask the running ScriptFu interpreter process to reread the scripts. Use the menu item Filters>Development>Script-Fu>Refresh Scripts You can't do this when a script is already running (while its dialog is up.)

(The architecture is different for other interpreters, e.g. the Python interpreter, in which case the interpreter is started, and terminates, when you choose a menu item.)


Future directions using GObject introspection

Starting with GIMP 3, the preferred architecture for plugins uses GObject introspection (GI) of the libgimp API. For example, a GIMP Python plugin usually uses the PyGObject module for GObject introspection.

GIMP developers are considering replacing the ScriptFu interpreter with a standard Lisp interpreter (Guile) that might be capable of GObject introspection.

The ScriptFu interpreter is not capable of GObject introspection.