Python-Fu #2 - Yout first Python-Fu plugin

 

Welcome back to this series of articles about Gimp Python plugins. In the first part, we learned a bit about what was available for extending Gimp, how to install Gimp Python, find documentation and learned how to interact with Gimp through Python using the Python Console. We will now look at plugin registration and start coding our first script.

 

First, here is the solution to the simple exercise left at the end of the previous article. What we wanted to do was, after we had loaded a single image in Gimp, add a layer to it, fill it with a "Leopard" pattern, set its opacity to 50% and change its blending mode. Here's the solution (I have removed the console's ">>>" so you can copy paste to test it):

 

g = gimp.pdb
images = gimp.image_list() 
my_image = images[0]
layers = my_image.layers
w = g.gimp_image_width(my_image)
h = g.gimp_image_height(my_image)
print "Image Resolution: w=%d,h=%d"%(w,h)

new_layer = g.gimp_layer_new( my_image, w, h, RGBA_IMAGE, "LeopardLayer", 100, NORMAL_MODE)
my_image.add_layer( new_layer )

g.gimp_context_set_pattern("Leopard")
g.gimp_edit_fill(new_layer, PATTERN_FILL)
g.gimp_layer_set_opacity(new_layer, 20)
g.gimp_layer_set_mode(new_layer, SCREEN_MODE)


 

Writing your first Python-Fu plugin

 

Fiddling with the Python Console might be fun, it's also very interesting to learn about gimp python functions, but it's not very useful. We are now going to write our first plugin script. First, you need to know where to store your plugin files.

Where to save your script

First, it's best to store them locally, so they are usable for your user profile only, to do that, you need to store them in your local Gimp settings folder, which can be found at "%USERPROFILE%\.gimp-2.6\plug-ins\" in Windows, and "~/.gimp-2.6/plug-ins/" on Linux. Open an explorer there, and create a new text file there, and call it "Example1.py".

One important thing: on Linux, check that the file has execute permission, or your plug-in won't show in Gimp. Do that with your file manager of choice, or in the console: chmod u+x Example1.py

Know that you can save your Python plugins anywhere, and then in the Gimp Preferences menu, under the Folder entry, you can find a Plugins sub-entry, with a list of folders to check for plugins. You can add your own custom folder where you will save your python scripts. Restart Gimp so that the change is taken into account. The list of folders will also show you what is the system-wide folder used to store plugins for all users.

Next, we need to talk about three important aspects: Python syntax, Plugin Registration, and Plugin Code.

Python Syntax

There are a few things you will need to know about Python. I hope you have read a few tutorials about the Python language or you already know Python a bit. Python is not that hard to learn, but something original about this language is the block indentation. Block syntax in Python is defined by identation. Make a mistake in your identation, and your script won't run. So, I highly recommend that you use a decent Python editor, possibly with syntax checking. There are a few (Komodo Edit, PyScripter, Eric... ). For this tutorial we will use the IDLE editor which is included in Python. You will find a shortcut named "IDLE (Python GUI)" in your system menu. Launch IDLE and open your "Example1.py" file. Two interesting functions of IDLE will be very useful throughout this tutorial: "Run->Check Module (ALT-X)" and "Run->Run Module (F5)". "Check module" will be useful when writing our scripts, to check their syntax. IDLE will tell you where you made syntax errors in your scripts. "Run Module" will be useful to test simple non-gimp-related scripts and learn python.

 

Write in your document the following lines then press F5 to run the script.

#!/usr/bin/env python

print "Hello From Python"

 

Indentation is essential. Try to insert tabs or spaces before the print keyword, and press F5 again. IDLE will tell you there is a syntax error in your code, and will hilight where the error is in your code. It will be vital when you have complex code with functions, loops, etc... Once again, I won't try to teach you Python, so I encourage you to learn from online tutorials, like on this site, which offers a complete book about Python, you need to look at the 1.2 version of A Byte of Python, which covers the version we will use in Gimp. There is a PDF version too.

 

Plugin-Registration

Let's start writing our first plugin. The essential part of each script, is the registration. Without that, Gimp will not load your plugin, because it will not know where to put it, and how to run it. Here's the skeleton of a basic Gimp Python script:

 

#!/usr/bin/env python

# This tells Python to load the Gimp module 
from gimpfu import *

# This is the function that will perform actual actions
def my_script_function() :
    print "Hello from my script!"
    return

# This is the plugin registration function
# I have written each of its parameters on a different line 
register(
    "my_first_script",    
    "My first Python-Fu",   
    "This script does nothing and is extremely good at it",
    "Michel Ardan", 
    "Michel Ardan Company", 
    "April 2010",
    "<Image>/MyScripts/My First Python-Fu", 
    "*", 
    [], 
    [],
    my_script_function,
    )

main()

 

Copy that code to your "Example1.py" in IDLE, then run Check Module to see if the syntax is ok. Now, you need to restart Gimp before the plugin gets registered. Remember that each time you change the registration function, you need to restart gimp too. Later on, if you just modify the code of your script, and not the registration function, then you don't need to restart Gimp everytime, but registration modification requires a Gimp restart.

 

Gimp started ? Check the image's window menu, you should see a "MyScripts" menu between the "Filters" and "Windows" menu. It has one function, "My First Python-Fu", which is greyed out, until you actually load an image. You can launch your plugin, but it will not do anything, since we have not coded any actions yet.

 

Let's look at the registration function in details first. The registration function expects a list of parameters, which are, in the following order:

  1. Your plugin's main function name, as it will be found in Gimp's Procedure Browser. This means that your plugin will be callable by other plugins, using this function name (even by a script in a another language)!
  2. Your plugin's "documentation" name, as it will also appears in the Procedure Browser. This name should describe your plugin briefly.
  3. Plugin's help. Here you should explain in a more detailed manner what kind of function your plugin provides.
  4. The name of the author of this plugin
  5. Any copyright information needed
  6. The date this version of the plugin was released
  7. The path in the menu where your plugin should be found
  8. The image types supported by your plugin
  9. The list of the parameters needed by your plugin
  10. The results sent back by your plugin
  11. The name of the local function to run to actually start processing, which will be called with a set of parameters.

If the menu entry appeared correctly in your Gimp window and your plugin registered right, go to the Procedure Browser, and search for "my-first-script", you should find a  "python-fu-my-first-script" function, that shows the information we wrote in our script. Note that Gimp changed the underscores into hyphens and added a "python-fu" prefix. What your plugin does, can be used by any other plugin using the "python-fu-my-first-script" function, more on that later.

 

In the procedure browser, you may wonder why we have 3 parameters defined, something we did not specify in our registration function. Let's get a closer look at parameters 7 through 11.

 

The Menu Path

This parameter is important as, if you do not specify it correctly, you will not be able to find a menu for your plugin.  We wrote:

"<Image>/MyScripts/My First Python-Fu"

and that added a "MyScripts" submenu, with a menu entry for our script, in the main image menu. "<Image>" is a keyword for this menu. Replace that parameters with this:

"<Image>/Filters/MyScripts/My First Python-Fu" 

quit Gimp and restart it. Look in the "Filters" menu from your main image menu, your will now find a "MyScripts" entry there, which contains your script! This means that you can put a menu entry for your script anywhere you feel its place is. If your plugin is related to colors, try:

"<Image>/Colors/My First Python-Fu"

and it's in the colors menu. See that if you do not put "/MyScripts/" then you do not create a submenu, just a menu entry. If it's related to selections, try:

"<Image>/Select/My First Python-Fu"

You can also put it in an existing submenu, for instance, if your plugin is related to distortions, try:

"<Image>/Filters/Distorts/My First Python-Fu"

Don't forget to quit and restard Gimp if you want your changes to take effect. Load an image otherwise your menu will be greyed out. Also, note that you can create several levels of submenus if you plan to develop many scripts and group them, for instance:

"<Image>/MyTools/MyTestScripts/Tutorial/My First Python-Fu"

 

There is another keyword you can use, which is "<Toolbox>", try:

"<Toolbox>/MyScripts/My First Python-Fu"

 

The difference might not be visible first. Your script will go to the same menu apparently. Go to the Procedure Browser and look for your plugin, and see that when it has been defined with a "<Toolbox>" keyword, your plugin does not have 3 but only one parameter! More on that later. You may also use any of the following shortcuts:

"<Toolbox>", "<Image>", "<Layers>", "<Channels>", "<Vectors>", "<Colormap>", "<Load>", "<Save>", "<Brushes>", "<Gradients>", "<Palettes>", "<Patterns>" or "<Buffers>".

 

Image Types

The Image Types parameter defines what type of images your plugin supports as input. We wrote "*" which means "any type of image". Image types are "RGB", "RGBA", "GRAY", or "INDEXED", and can be multiple, seperated by commas. Your plugin supports all image types, write:

"*"

 

your plugin supports only transparent RGB images, write:

"RGBA"

 

your plugin supports RGB and RGBA images, you can write:

"RGB*"

 

your plugin supports all image types, write "*" or:

"RGB*", "INDEXED", "GRAY"

 

Try to specify "GRAY" support for your image input, and restart Gimp. Load a color image, and your plugin will not be accessible. Load a grayscale image or convert your image to grayscale (Image->Mode->Grayscale) and your plugin will be accessible!

Input parameters

This is where you define what input parameter(s) your script needs. You don't need to have any if you do not need any other input from the user than an image and a layer. When your script does not need any parameter, just write:

[]

which is an empty list of parameters.

You may have noticed that our test plugin did not specify any parameter, but our look at the Procedure Database showed us that our plugin required 3 parameters. That's the normal behaviour of all plugins. A plugin is supposed to work on some image input data,  so Gimp automatically adds 3 parameters, the second beeing the current image, and the third the current drawable objet (layer). The first parameter is the "run mode". The run mode can have two values: "RUN-NONINTERACTIVE" or "RUN-INTERACTIVE".

Running non interactively may be useful later when we will need to run our script to batch process images (check article #4).

Ok, so we always have these 3 parameters first, then the other parameters will be extra parameters useful to your script. Note that if you defined a <Toolbox> menu entry, your plugin will only require a run-mode parameter (it means you plugin will not actually work on an image, but maybe generate one).

The parameters for you plugin are defined by a list of tuples of a specified format. The documentation tells you that each tuple should look like:

(Type, Name, Description, default, extra)

with Type, one of : PF_INT8, PF_INT16, PF_INT32, PF_INT, PF_FLOAT, PF_STRING, PF_VALUE, PF_COLOR, PF_COLOUR, PF_REGION, PF_IMAGE, PF_LAYER, PF_CHANNEL, PF_DRAWABLE, PF_TOGGLE, PF_BOOL, PF_RADIO, PF_SLIDER, PF_SPINNER, PF_ADJUSTMENT, PF_FONT, PF_FILE, PF_DIRECTORY, PF_BRUSH, PF_PATTERN, PF_GRADIENT, PF_PALETTE.

That's a lot of them, I won't explain each one, you may have a look at further documentation. Each type will allow you to build the interface of your plugin and allow the user to input different types of values, like integer value,  text, font selection, image or layer selection, file or directory selection etc... if you want to test them all, write a dummy plugin with all types of parameters (this might give a very tall window).

 

Then, you need to provide a name for your parameter. You will use this name in your script functions to get the value of this parameter.

 

Then you add a description, that will appear in the documentation and help the user understand what is the use for this parameter in the Procedure Browser.

 

Finally, you can specify a default value, and some extra value used by some types of parameters. We will look at an example soon. Oh, and if you provide an empty list of parameters, your script will run without showing you any input interface.

 

Results Parameters

Your plugin can send values back to you. These values can be defined as a list of tuples, in the form of: (type, name, description). We may look at an example in another tutorial, but for now we will always use "[]", meaning we don't return any parameter. Gimp will not do anything with those parameters, but you can use them from other scripts that might call your script.

 

Processing Function

The last value of the registration parameters is the name of the function that Gimp will call when you click OK to start your plugin. It is important to define this function with the correct list of parameters that corresponds to the ones you gave (starting with extra image and drawable parameters if your plugin works on an image) .

 

The updated Example Script

 

One last thing after the registration function: we need to call the globally defined main(), which is the function that starts your script.

Now, let's modify our first plugin to allow the user to input some values:

#!/usr/bin/env python


# This tells Python to load the Gimp module 
from gimpfu import *

# This is the function that will perform actual actions
def my_script_function(image, drawable, text_value, int_value) :
    print "Hello from my script!"
    print "You sent me this text: "+text_value
    print "You sent me this number: %d"%int_value
    return

# This is the plugin registration function
register(
    "my_first_script",    
    "My first Python-Fu",   
    "This script does nothing and is extremely good at it",
    "Michel Ardan", 
    "Michel Ardan Company", 
    "April 2010",
    "<Image>/MyScripts/My First Python-Fu", 
    "*", 
    [
      (PF_STRING, 'some_text', 'Some text input for our plugin', 'Write something'),
      (PF_INT, 'some_integer', 'Some number input for our plugin', 2010)
    ], 
    [],
    my_script_function,
    )

main()

Restart Gimp, and launch your script after you have loaded an image, you should see your plugin's interface asking you for some text and integer value. Click ok, and... well nothing happens. Gimp calls your "my_script_function", and passes 4 parameters to it. The first one will be the current image, the second one will be the current drawable, the third and fourth will be the two extra parameters you have defined. Be careful to define your function with the correct number of parameters, or Gimp will tell you there is an error with your plugin.

 

Our plugin does not have any error, yet we tell it to print some information, and do not see anything.

 

Full Script, with Debug Ouput

 

Let's write a new version of our script:

 

#!/usr/bin/env python

from gimpfu import *

# create an output function that redirects to gimp's Error Console
def gprint( text ):
   pdb.gimp_message(text)
   return 

# our script
def my_script_function(image, drawable, text_value, int_value) :

    gprint("Hello from my script!")
    gprint("You sent me this text: "+text_value)
    gprint("You sent me this number: %d"%int_value)
    gprint("Lets flip the image!")
    pdb.gimp_image_flip( image, ORIENTATION_HORIZONTAL )
    return

# This is the plugin registration function
register(
    "my_first_script",    
    "My first Python-Fu",   
    "This script does nothing and is extremely good at it",
    "Michel Ardan", 
    "Michel Ardan Company", 
    "April 2010",
    "<Image>/MyScripts/My First Python-Fu", 
    "*", 
    [
      (PF_STRING, 'some_text', 'Some text input for our plugin', 'Write something'),
      (PF_INT, 'some_integer', 'Some number input for our plugin', 2010)
    ], 
    [],
    my_script_function,
    )

main()


 

Gimp did not know what to do with Python's print function. It probably prints something somewhere, but Gimp does not handle these outputs. Instead we can use Gimp's Error Console, located at "Window->Dockable Dialogs->Error Console". In our script, we define a "gprint" function that redirect messages to the console. Open Gimp's Error Console,  run this script on an image and look at what gets outputed to the Error Console. We will use this mecanism a lot while debugging our scripts.

Run this script, and see that it outputs messages to the error console, and flips the current image.

 

Well, this is the end of this part of the tutorial, next time we will write a more interesting and complex script and work on layers.

You have enough information to start writing scripts, you will find more information about plugin registration, in the "Plugin Framework" section" on http://www.gimp.org/docs/python/index.html

 

One little tip too, you can also browse plugin information in the "Help->Plugin Browser" menu of Gimp.

 

Other references for Python:

http://docs.python.org/tutorial/index.html

http://docs.python.org/reference/index.html

 

Commentaires

Portrait de Frédéric Jaume

Sorry, I lost comments during the site update. Thank you so much to all those who appreciated this tutorial, I couldn't find time to publish part 3, but it's still in the works!

Oh, one reader mentionned that you should not forget to do a "chmod +x yourscript.py" on Linux.

(must say it did not work... ...until I 'chmod+x'ed the script to be executable ;-)
thank you very much for these clear explanations !!

Hi,

I'm just trying to get past the 1st step by getting the script to show up in the menu and it won't register!

I'm following every detail to the letter. I'm using Windows, so I shouldn't have permissions issues. I'm also using Gimp 2.8 and the Python-Fu console appears in the Filters menu so the installation of Gimp is fine. I'm saving a pytest.py in the C:\Users\<myname>\.gimp-2.8\plug-in directory.

I just want to get started on this so I can get scripting and I just can't get Gimp to register it!

Is there a place I can check for errors to get some clue as to what I'm doing wrong?

Here's what I have:

#!/usr/bin/env python

from gimpfu import *

def python_pytest() :
#Do stuff here
print "Hello from my script"
return

register(
"python_fu_pytest",
"Does something",
"Does something terribly useful",
"Young Dog",
"Young Dog Corporation",
"May 2012",
"<Image>/Filters/Artistic/_MyTest...",
"*",
[],
[],
python_pytest
)

main()

Portrait de Frédéric Jaume

I've installed Gimp 2.8 recently but did not check that these example scripts still works, they all were based on version 2.6! I think some update might be needed, I will update as soon as I have time to work on this again.

Ajouter un commentaire

Plain text

  • Aucune balise HTML autorisée.
  • Les adresses de pages web et de courriels sont transformées en liens automatiquement.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
By submitting this form, you accept the Mollom privacy policy.