Typed text animation with Python & Gimp

By Andreas Wilhelm Apr 25, 2013

Typed text animation using Python and Gimp

As I mentioned in my last post “Developing Gimp plugins using Python”, I was trying to create a typed text animation using Gimp, which should be integrated into a screencast intro I am currently working on. One problem I had to face was the renaming of the image layers, that allows me to control the frame rate and overlay behavior.

Because I had to handle so many layers, I wrote a simple script that renames all layers. After starting the script a dialog asks for the layer’s base name and the amount of milliseconds a layer should be displayed. After confirming the input by selecting “OK” the script renames all layers so each layer name had the following format:

<layername> #<0...n> (m ms) (replace)</layername>

If you now view the animation using the build in Gimp previewer (Filter -> Animation -> Playback), each layer is displayed m milliseconds and is then replaced by the next one.

typedTextScript

Even though this worked pretty well, I still had to create all this layers by hand, merge each of them with the background image and add the text layer by layer. That sucks! So I decided to write a more advanced plugin that utilizes all the power of Gimp’s Python scripting engine, so I could create a new typed text animation by just entering a few input parameters.

Once I found the correct command and the correct parameters for this command, it was pretty simple to extend my implementation to use this new operation, but since there is no offical manual that is up to date (just found the Gimp Python Documentation), this all took a long time. Finally the script ended being quite simple and elegant (see the code below).

#!/usr/bin/env python
from gimpfu import *
import os

def typedTextAnim(backgroundImage, backgroundColor, font, fontSize, textColor, text, x, y, millis):
	# Set foreground ...
	gimp.set_foreground(textColor)

	# ... and background color.
	gimp.set_background(backgroundColor)

	# Fetch the number of characters ...
	textLength = len(text)

	# ... and the image dimensions.
	width = backgroundImage.width
	height = backgroundImage.height

	# Setup a new image ...
	image = gimp.Image(width, height, RGB)

	# ... and fetch the background layer.
	background = backgroundImage.layers[0]

	# Generate a layer for each character of the text.
	for i in range(0, textLength + 1):
		# Setup the current layer, ...
		newLayer = gimp.Layer(image, "Background", width, height, RGB_IMAGE, 100, NORMAL_MODE)

		# ... set the layer name containing the animation data ...
		newLayer.name = 'Layer #' + str(i) + ' (' + str(millis) + 'ms) (replace)'

		# ... and add the new layer to the end of the image layer stack.
		image.add_layer(newLayer, 0)

		# Copy the background layer from the given background image, ...
		pdb.gimp_edit_copy(background)

		# ... create a floating selection  above the new layer, ...
		floating = pdb.gimp_edit_paste(newLayer, True)

		# ... specify the offsets within this layer ...
		pdb.gimp_layer_set_offsets(floating, *newLayer.offsets)

		# ... and anchor the floating selection on it.
		pdb.gimp_floating_sel_anchor(floating)

		# Setup the text layer, ...
		textLayer = pdb.gimp_text_fontname(image, None, x, y, text[0:i] + u'\u258a', 0, 1, fontSize, PIXELS, font)

		# ... change the visibility of the text and new layer to visible ...
		pdb.gimp_drawable_set_visible(newLayer, True)
		pdb.gimp_drawable_set_visible(textLayer, True)

		# ... and merge the two layers.
		merged = pdb.gimp_image_merge_visible_layers(image, 0)

		# After merging both layers, hide them.
		for layer in image.layers:
			pdb.gimp_drawable_set_visible(layer, False)

	# Finally make all layers visible again, ...
	for layer in image.layers:
		pdb.gimp_drawable_set_visible(layer, True)

	# ... display the created image ...
	display = gimp.Display(image)

	# ... and flush the image. Otherwise it is not visible.
	pdb.gimp_displays_flush()

register(
	proc_name=("bornageek_typed_text_animation"),
	label=("Typed text animation"),
	blurb=("Create a animation that show console typed text"),
	help=("Help?"),
	author=("Andreas Wilhelm"),
	copyright=("www.bornageek.com"),
	date=("2013"),
	menu=("<img/>/Avedo Scripts/Typed Text"),
	imagetypes=("*"),
	params=[
		(PF_IMAGE, 'backgroundImage', 'Background image', None),
  		(PF_COLOR, 'backgroundColor', 'Background color', (0,0,0) ),
  		(PF_FONT, 'font', 'Font', 'Arial'),
  		(PF_INT, 'fontSize', 'Font size', 18),
  		(PF_COLOR, 'textColor', 'Text color', (255,255,255) ),
  		(PF_STRING, 'text', 'Text to display', 'Avedo.net rocks!'),
 		(PF_INT, 'x', 'x text offset', 150),
 		(PF_INT, 'y', 'y text offset', 150),
 		(PF_INT, 'millis', 'Milliseconds to display a frame', 100),
	],
	results=[],
	function=(typedTextAnim)
);

main()

Hope this either helps you to understand how writing python extentions for Gimp works or the script itself is useful for for you. I would also be happy to see some of your own scripts.

So stay tuned and until next time - happy coding!


is a Computer Science MSc. interested in hardware hacking, embedded Linux, compilers, etc.