home page of dan zwell


I release all code samples on this page to the public domain.


Gimp is scriptable. So if you find yourself publishing photos and repeating the same task over and over, you may find this idea useful.

On an unrelated note, I read about a person that said he doesn't tell his photography clients that he is a computer programmer by trade, and he doesn't tell his regular employer that he is a professional photographer--if you do two things, people will assume that you do neither of them well. I am fortunate enough to be surrounded by artistic geeks and geeky artists, so I haven't encountered such opinions, recently. The people who would get the most out of this may be artistic geeks.

This capability is documented very well by the GIMP documentation (which I don't intend to be a substitute for), but there were some things it didn't leave me clear about:

  • Python-Fu, pygimp, and GIMP-Python pretty much all refer to the same thing.
  • This capability is installed and turned on by default in GIMP 2.4 and 2.5.
  • Python extensions are just as useful and simple as the older Scheme type. In particular, you can attach them to menus.
  • Python extensions go in the ".gimp/plug-ins" directory, while scheme extensions go in the ".gimp/scripts" directory.
  • Scheme scripts are loaded when you run "Script-Fu -> Refresh scripts", while Python scripts are not "loaded" in the same way. They are registered when GIMP starts, but each time they are run, the file is loaded anew. This simplifies debugging, but means you can't change the name of a function or the plugin's location within the menu hierarchy without restarting GIMP.
  • Though Scheme scripts do not need to have executable permissions, Python scripts do.


This script prompts the user for a maximum width and height, and resizes an image, maintaining its aspect ratio. The main reason this is useful is that it allows a default to be set, so I don't have to type numbers each time I resize an image. I changed the defaults to the resolution of my screen.

#!/usr/bin/env python import math from gimpfu import * def lazy_scale_image(timg, tdrawable, max_width, max_height): print "max width: %s\nmax height: %s" % (max_width, max_height) width = tdrawable.width height = tdrawable.height if max_width <= 0: # Assume width is okay as it is max_width = width if max_height <= 0: # Assume height is okay max_height= height if width <= max_width and height <= max_height: print "Nothing to do, returning" return image_aspect = float(width) / float(height) boundary_aspect = float(max_width) / float(max_height) if image_aspect > boundary_aspect: # Width is the limiting factor: new_width = max_width new_height= int(round( new_width/image_aspect )) else: # Height is the limiting factor: new_height = max_height new_width = int(round( image_aspect*new_height )) print "Resizing %s:%s to %s:%s" % (width, height, new_width, new_height) # At present, documnatation does not specify the interpolation-- # another tutorial claimed it was cubic: pdb.gimp_image_scale(timg, new_width, new_height) register( "lazy_scale_image", "Scale the specified image so that it is no larger than the given dimensions", "Scale the specified image so that it is no larger than the given dimensions", "Daniel Zwell", "Daniel Zwell", "2008", "<Image>/_Xtns/_Lazy Resize", "RGB*, GRAY*", [ (PF_INT, "max_width", "Maximum new width", 1280), (PF_INT, "max_height", "Maximum new height", 900), ], [], lazy_scale_image) main()

Add border

I also frequently add a border to images. This takes a few steps, and doing it to twenty images is painful. This script prompts for a number, and adds a border of that radius to an image. It does not overlap with the image--rather, it increases the canvas size to make room for the border. The border is colored is the current FG color.

#!/usr/bin/env python from gimpfu import * def add_border(image, drawable, radius): # Group the operations of this script pdb.gimp_image_undo_group_start(image) width = image.width height = image.height width_new = width + 2*radius height_new = height + 2*radius # Increase the canvas size pdb.gimp_image_resize(image, width_new, height_new, radius, radius) # Add a new layer, fill it with FG color layer = pdb.gimp_layer_new(image, width_new, height_new, 0, "border layer", 100, NORMAL_MODE) pdb.gimp_drawable_fill(layer, FOREGROUND_FILL) # Add new layer, move it to bottom: pdb.gimp_image_add_layer(image, layer, -1) pdb.gimp_image_lower_layer_to_bottom(image, layer) pdb.gimp_image_undo_group_end(image) register( "add_border", "Add a border around an image, colored in the current FG color.", "Add a border around an image, colored in the current FG color.", "Daniel Zwell", "Daniel Zwell", "2008", "<Image>/_Xtns/_Add border", "RGB*, GRAY*", [ (PF_INT, "radius", "Border radius", 20), ], [], add_border) main()

Sometimes it is nice to add a black border of 2px around an image, then add a thicker white border around that.

If you have any questions or corrections, write me at "dzwell at [this domain]".