GIMP Scripting: Difference between revisions

From Elvanör's Technical Wiki
Jump to navigation Jump to search
 
(14 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Basics ==
= Basics =


* Scripting the GIMP can be done easily using the Python API. You can write pure Python scripts, and you don't need to use Scheme at all.
* Scripting the GIMP can be done easily using the Python API. You can write pure Python scripts, and you don't need to use Scheme at all.


* The Python API actually wraps the PDB. The PDB code is written in C so is fast. You can use PDB calls in your Python code, or use the object oriented API. The only advantage in using the OO API is cleaner code - no performance gain there, since the Python API wraps PDB anyway.
* The Python API actually wraps the PDB. The PDB code is written in C so is fast. You can use PDB calls in your Python code, or use the object oriented API. The only advantage in using the OO API is cleaner code - no performance gain there, since the Python API wraps PDB anyway.
* In order to make your Python script accessible from within the GIMP, you need to save it in ~/.gimp-2.4/plug-ins/. You need to make it executable or GIMP won't recognize it.


* In your script, you need to have the register() function and a main() function which can be empty, in addition to your actual function which executes what you want. Here are the arguments for the register function (with an example):
* In your script, you need to have the register() function and a main() function which can be empty, in addition to your actual function which executes what you want. Here are the arguments for the register function (with an example):
Line 29: Line 27:
* The _() function that you can see used in example plug-ins is for internationalization. The "_R" in "_Rounded Corners..." is for the mnemonic, eg the key that will be associated as a shortcut in the interface.
* The _() function that you can see used in example plug-ins is for internationalization. The "_R" in "_Rounded Corners..." is for the mnemonic, eg the key that will be associated as a shortcut in the interface.


== Writing and Debugging Python Scripts ==
= Plugins =
 
* The scripts should be stored in the plug-ins directory of the general Gimp directory (controlled by GIMP2_DIRECTORY). '''All should have executable permission!'''
 
* The following error:
LibGimpBase-WARNING **: gimp-console: gimp_wire_read(): error
 
essentially means that Gimp could not parse a Python script, eg the script that. This happens if you store a plain Python file in the plug-ins directory. For this reason only actual plug-in scripts should be present in that directory, helpers should go elsewhere.
 
* The file pluginrc contains information about the registered plugins. It can safely be deleted and will be regenerated by querying the plug-ins.
 
* You cannot import a plugin into another plugin and expect this to work. The solution is to refactor common functions into separate modules.
 
= Writing and Debugging Python Scripts =


* You can make your image appear on the GUI with the following command:
* You can make your image appear on the GUI with the following command:


  display = pdb.gimp_display_new(image)
  display = pdb.gimp_display_new(image)
* Already opened images can be used in the Python console:
imagesList = gimp.image_list()


* A recommended way to debug your scripts is to run each command separately in the Python console. You can also exit from a Python script by using the return() statement.
* A recommended way to debug your scripts is to run each command separately in the Python console. You can also exit from a Python script by using the return() statement.
Line 40: Line 55:


* Fore more advanced debugging, writing to a log file (from within Python) is mandatory.
* Fore more advanced debugging, writing to a log file (from within Python) is mandatory.
* Loading GIMP from a shell (as opposed to starting it from within a desktop environment such as KDE) gives you a stack trace when an exception happens! This is invaluable information, so you should *always* start Gimp from the console when developping Python scripts.


== Python API / Bindings ==
= Python API / Bindings =


* For operations on a layer, you must add the layer to the image first. Else you will get an execution error.
* For operations on a layer, you must add the layer to the image first. Else you will get an execution error.
Line 47: Line 63:
* In the PDB, some functions like pdb.gimp_text_fontname allows to specify -1 as a DRAWABLE argument (to create a new layer). Using the Python API this does not work, and should be replaced with None.
* In the PDB, some functions like pdb.gimp_text_fontname allows to specify -1 as a DRAWABLE argument (to create a new layer). Using the Python API this does not work, and should be replaced with None.


=== Selections ===
* Functions returning more than one argument must effectively be bound to the correct number of arguments (even if some of these will be null).
newLayer, newImage = pdb.some_function() # not newImage = pdb.some_function() even if the newLayer will be null


* Don't forget that selection operations must specify an operation mode (CHANNEL_OP_ADD CHANNEL_OP_REPLACE...).
== Layers ==


=== Gradients ===
* Copying a layer from one image to another is best done using gimp_layer_new_from_drawable(). The new layer must still be added to the destination image.
* Duplicating a layer on an image is done via gimp_layer_copy(). Here too you must add the copy to the image before working on it.
* Moving a layer can be done using the gimp_layer_translate() function. Be careful of the gimp-drawable-offset() which translates the *content* of the layer.
* Tiling a layer can be done via the plug_in_tile() PDB function.
 
== Selections ==
 
* Don't forget that selection operations must specify an operation mode (CHANNEL_OP_ADD, CHANNEL_OP_REPLACE...).
* Using the bucket fill function over a supposedly empty selection seems to still have some effect. So be careful about "empty selections" (when you use the rectangle selection tool with a width of 0 for example).
 
== Gradients ==


* There does not seem to be any gradient Python class, so the only way is to make direct calls to the PDB.
* There does not seem to be any gradient Python class, so the only way is to make direct calls to the PDB.
* When filling with gradients, there is an option to use (or not) dithering. This improves quality but introduces randomness so the result is no longer predictable (invisible for the naked eye, however).
== Colors ==
* You can easily convert between RGB, HSV, HSL programmatically. You can also easily change these values. However, automatically attempting some operations is rather hard (such as automatically obtaining a darker / lighter version of a color).
* There are no constants for black, white... colors in the Python module.


== Help ==
= Help =


* You can obtain built-in documentation about the API by using dir (gimp) in the Python Gimp shell. You should import gimpfu first.
* You can obtain built-in documentation about the API by using dir (gimp) in the Python Gimp shell. You should import gimpfu first.
Line 61: Line 96:
* Another way is to use help() on a defined variable, for example a layer.
* Another way is to use help() on a defined variable, for example a layer.


== List of types in Python ==
= List of types in Python =


* PF_INT8        = PDB_INT8
* PF_INT8        = PDB_INT8
Line 110: Line 145:
* Note that you cannot currently pass an array to a Python Gimp script, since PF_STRINGARRAY has been removed ([http://bugzilla.gnome.org/show_bug.cgi?id=122049 see this bug for reference]). One workaround is to pass a string with special separators (like slashes), and split it into an array inside the Python code.
* Note that you cannot currently pass an array to a Python Gimp script, since PF_STRINGARRAY has been removed ([http://bugzilla.gnome.org/show_bug.cgi?id=122049 see this bug for reference]). One workaround is to pass a string with special separators (like slashes), and split it into an array inside the Python code.


== Launching GIMP from outside ==
= Launching GIMP from outside =


* When loading GIMP with gimp-console for example, it will load an interpreter (the default is the Script-Fu one - but you can change that to the Python one if you want). This interpreter will then execute commands given to it (via the -b command line option for example).
* When loading GIMP with gimp-console for example, it will load an interpreter (the default is the Script-Fu one - but you can change that to the Python one if you want). This interpreter will then execute commands given to it (via the -b command line option for example).
Line 117: Line 152:


* You can change the base directory of Gimp (for settings, tile cache, plugins etc) by setting the environment variable GIMP2_DIRECTORY. This is very useful as it allows you to run Gimp when the user does not have a home directory (for example the Tomcat user). In Java there is an convenient way to set the environment variables for running a native process.
* You can change the base directory of Gimp (for settings, tile cache, plugins etc) by setting the environment variable GIMP2_DIRECTORY. This is very useful as it allows you to run Gimp when the user does not have a home directory (for example the Tomcat user). In Java there is an convenient way to set the environment variables for running a native process.
* gimp-console has a --verbose option which can be useful.
* Passing very long strings (eg, XML format strings) to the Python environment in Gimp won't work: there seems to be a limit to the number of characters you may send. The obvious workaround is to pass the path to a file and read the file within Python.

Latest revision as of 10:10, 28 April 2011

Basics

  • Scripting the GIMP can be done easily using the Python API. You can write pure Python scripts, and you don't need to use Scheme at all.
  • The Python API actually wraps the PDB. The PDB code is written in C so is fast. You can use PDB calls in your Python code, or use the object oriented API. The only advantage in using the OO API is cleaner code - no performance gain there, since the Python API wraps PDB anyway.
  • In your script, you need to have the register() function and a main() function which can be empty, in addition to your actual function which executes what you want. Here are the arguments for the register function (with an example):
    • "generate_rounded_corners": Name of the plugin (how to call it programmatically with Script-Fu)
    • "This is a test Python plugin." : Textual description
    • "It creates and saves an image.": Other description (extended, not sure here)
    • "Elvanör": Author
    • "Jean-Noël Rivasseau": Copyright owner
    • "2007": Date
    • "_Rounded Corners...": Name of the plugin (in the GIMP menus)
    • "RGB*, GRAY*": Modes accepted (??)
    • []: Arguments to this plugin
    • []: Return values of this plugin, only useful in non interactive mode
    • generateRoundedCorners: Python callback function (essential!)
    • menu="<Image>/Filters/Render/Rounder Corners": Path in the menus
  • In the previous list, the arguments list has the following syntax:
    • PF_STRING: type of argument
    • "targetDirectory": argument name
    • "The directory in which will be saved the images": description
    • "/srv/": Default value. This is used *only* in the interface, eg. when using the plugin non interactively you must always pass the correct number of arguments.
  • The _() function that you can see used in example plug-ins is for internationalization. The "_R" in "_Rounded Corners..." is for the mnemonic, eg the key that will be associated as a shortcut in the interface.

Plugins

  • The scripts should be stored in the plug-ins directory of the general Gimp directory (controlled by GIMP2_DIRECTORY). All should have executable permission!
  • The following error:
LibGimpBase-WARNING **: gimp-console: gimp_wire_read(): error

essentially means that Gimp could not parse a Python script, eg the script that. This happens if you store a plain Python file in the plug-ins directory. For this reason only actual plug-in scripts should be present in that directory, helpers should go elsewhere.

  • The file pluginrc contains information about the registered plugins. It can safely be deleted and will be regenerated by querying the plug-ins.
  • You cannot import a plugin into another plugin and expect this to work. The solution is to refactor common functions into separate modules.

Writing and Debugging Python Scripts

  • You can make your image appear on the GUI with the following command:
display = pdb.gimp_display_new(image)
  • Already opened images can be used in the Python console:
imagesList = gimp.image_list()
  • A recommended way to debug your scripts is to run each command separately in the Python console. You can also exit from a Python script by using the return() statement.
  • A primitive way to get basic information displayed by your scripts is to use the gimp_message function, which will display a string on the GIMP's GUI.
  • Fore more advanced debugging, writing to a log file (from within Python) is mandatory.
  • Loading GIMP from a shell (as opposed to starting it from within a desktop environment such as KDE) gives you a stack trace when an exception happens! This is invaluable information, so you should *always* start Gimp from the console when developping Python scripts.

Python API / Bindings

  • For operations on a layer, you must add the layer to the image first. Else you will get an execution error.
  • In the PDB, some functions like pdb.gimp_text_fontname allows to specify -1 as a DRAWABLE argument (to create a new layer). Using the Python API this does not work, and should be replaced with None.
  • Functions returning more than one argument must effectively be bound to the correct number of arguments (even if some of these will be null).
newLayer, newImage = pdb.some_function() # not newImage = pdb.some_function() even if the newLayer will be null

Layers

  • Copying a layer from one image to another is best done using gimp_layer_new_from_drawable(). The new layer must still be added to the destination image.
  • Duplicating a layer on an image is done via gimp_layer_copy(). Here too you must add the copy to the image before working on it.
  • Moving a layer can be done using the gimp_layer_translate() function. Be careful of the gimp-drawable-offset() which translates the *content* of the layer.
  • Tiling a layer can be done via the plug_in_tile() PDB function.

Selections

  • Don't forget that selection operations must specify an operation mode (CHANNEL_OP_ADD, CHANNEL_OP_REPLACE...).
  • Using the bucket fill function over a supposedly empty selection seems to still have some effect. So be careful about "empty selections" (when you use the rectangle selection tool with a width of 0 for example).

Gradients

  • There does not seem to be any gradient Python class, so the only way is to make direct calls to the PDB.
  • When filling with gradients, there is an option to use (or not) dithering. This improves quality but introduces randomness so the result is no longer predictable (invisible for the naked eye, however).

Colors

  • You can easily convert between RGB, HSV, HSL programmatically. You can also easily change these values. However, automatically attempting some operations is rather hard (such as automatically obtaining a darker / lighter version of a color).
  • There are no constants for black, white... colors in the Python module.

Help

  • You can obtain built-in documentation about the API by using dir (gimp) in the Python Gimp shell. You should import gimpfu first.
  • Another way is to use help() on a defined variable, for example a layer.

List of types in Python

  • PF_INT8 = PDB_INT8
  • PF_INT16 = PDB_INT16
  • PF_INT32 = PDB_INT32
  • PF_INT = PF_INT32
  • PF_FLOAT = PDB_FLOAT
  • PF_STRING = PDB_STRING
  • PF_VALUE = PF_STRING
  • PF_COLOR = PDB_COLOR
  • PF_COLOUR = PF_COLOR
  • PF_REGION = PDB_REGION
  • PF_DISPLAY = PDB_DISPLAY
  • PF_IMAGE = PDB_IMAGE
  • PF_LAYER = PDB_LAYER
  • PF_CHANNEL = PDB_CHANNEL
  • PF_DRAWABLE = PDB_DRAWABLE
  • PF_VECTORS = PDB_VECTORS
  • PF_TOGGLE = 1000
  • PF_BOOL = PF_TOGGLE
  • PF_SLIDER = 1001
  • PF_SPINNER = 1002
  • PF_ADJUSTMENT = PF_SPINNER
  • PF_FONT = 1003
  • PF_FILE = 1004
  • PF_BRUSH = 1005
  • PF_PATTERN = 1006
  • PF_GRADIENT = 1007
  • PF_RADIO = 1008
  • PF_TEXT = 1009
  • PF_PALETTE = 1010
  • PF_FILENAME = 1011
  • PF_DIRNAME = 1012

Obsolete:

  • #PF_INT8ARRAY = PDB_INT8ARRAY
  • #PF_INT16ARRAY = PDB_INT16ARRAY
  • #PF_INT32ARRAY = PDB_INT32ARRAY
  • #PF_INTARRAY = PF_INT32ARRAY
  • #PF_FLOATARRAY = PDB_FLOATARRAY
  • #PF_STRINGARRAY = PDB_STRINGARRAY
  • #PF_SELECTION = PDB_SELECTION
  • #PF_BOUNDARY = PDB_BOUNDARY
  • #PF_PATH = PDB_PATH
  • #PF_STATUS = PDB_STATUS
  • Note that you cannot currently pass an array to a Python Gimp script, since PF_STRINGARRAY has been removed (see this bug for reference). One workaround is to pass a string with special separators (like slashes), and split it into an array inside the Python code.

Launching GIMP from outside

  • When loading GIMP with gimp-console for example, it will load an interpreter (the default is the Script-Fu one - but you can change that to the Python one if you want). This interpreter will then execute commands given to it (via the -b command line option for example).
  • If you call Gimp from Java (via an external process), don't surround the Script-fu commands with single quotes. These are only needed if you launch Gimp from the shell, so that Gimp knows it's a string. If you use them in Java, it won't work since you will pass a string to script-fu rather than a command (Bash did not act the same way).
  • You can change the base directory of Gimp (for settings, tile cache, plugins etc) by setting the environment variable GIMP2_DIRECTORY. This is very useful as it allows you to run Gimp when the user does not have a home directory (for example the Tomcat user). In Java there is an convenient way to set the environment variables for running a native process.
  • gimp-console has a --verbose option which can be useful.
  • Passing very long strings (eg, XML format strings) to the Python environment in Gimp won't work: there seems to be a limit to the number of characters you may send. The obvious workaround is to pass the path to a file and read the file within Python.