Python-Fu #3 - Working with Layers and XML in Python-Fu

Welcome back to this tutorial, and sorry for the long time since part 2! Thanks again to everyone who sent comments about this tutorial, I do hope it helped you.

This time we will focus on retrieving information from a Gimp image and its layers, as well a saving this information to a file. This will serve as a base for a future article of this tutorial where we will learn to code a full custom file format support for Gimp.

So, what do we want to do with this script ? I've often used Gimp to "prototype" layouts, for web page design, or for game interface screens, i.e. in situations where you have a bunch of small images that you place in layers of different sizes, and that you move around to try out designs. When you work on a game engine, you or someone in your team will probably have to build graphic tools for the production chain. This may be a viewer for a custom file format you use, maybe an image processor... why not use Gimp for this ?

So we're going to code a script that lists the elements composing your image, and their properties. By the way, if you find a clever layer naming convention, you may even use layer names to save extra information for each layer. We will save this information first in a flat file, and then in an XML file.

As we've already seen, our first script which we'll call "exportlayouttxt.py", must register a menu entry. Our plugin will work on any type of image, and will interactively ask the user to give two parameters: a file name, and a directory name where we will output the file. Here's the full script:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, glob
from gimpfu import *
from gimpenums import *

def txt_layout_builder(image, drawable, wcname, outdir) :
    # transmit error messages to gimp console
    gimp.pdb.gimp_message_set_handler( ERROR_CONSOLE )
    layers = image.layers

    #start building our file in a string
    doc = "# a simple file with layer info\n"
    for l in layers:
        doc += "Layer: Name=\"%s\" Width=%d Height=%d X=%d Y=%d\n"%(l.name, l.width, l.height, l.offsets[0], l.offsets[1]);

    gimp.pdb.gimp_message( "Saving to %s"%(outdir+wcname) );
    file_object = open(outdir+os.sep+wcname, "w")
    file_object.write(doc);
    file_object.close()
    
register(
    "python_fu_exportlayouttxt",
    "Layout Builder TXT",
    "Build a layout in gimp and export layer info as text",
    "Michel Ardan",
    "Michel Ardan Company",
    "2011",
    "<Image>/MyScripts/Layout Builder TXT",
    "*",
    [
      (PF_STRING, "widgetcontainer_name", "File Name", "layout.txt"),
      (PF_DIRNAME, "out_dirname", "Output Directory", ""),
    ],
    [],
    txt_layout_builder )

main()

watch out for the PF_DIRNAME parameter on Windows as I once had an issue probably related to UTF8 paths where my files could not be saved because of misinterpreted characters in the path. I'll try to find a way to fix that.

The txt_layout_builder function retrieves the image layers, and then iterates over them. You can then access a layer's name, its with, height, and offsets. To test that out, save the script, restart Gimp, anb create a new image, then drag & drop small images inside the image window to turn them into layers. Move them around, and run the script. The output file will contain a text description of all layers.

A text file is fine, but suppose you plan on a more complex tool that might interact with other tools. Using XML is a great option for this. As I already mentionned, I'm by no mean a Python expert. It seems like there are many ways to output XML in Python, some which depend on your Python installation. I will present you one here using minidom.

The full script looks like this, it is very similar to the previous one, expect for the file saving:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, glob
import xml.dom
import xml.dom.minidom
from gimpfu import *
from gimpenums import *

def xml_layout_builder(image, drawable, wcname, outdir) :
    # transmit error messages to gimp console
    gimp.pdb.gimp_message_set_handler( ERROR_CONSOLE )
    layers = image.layers
    #start building the XML document
    doc = xml.dom.minidom.Document()
    url = ""
    rootelt = doc.createElementNS(url, "layoutBuilder")
    doc.appendChild(rootelt)

    for l in layers:
        xmlnode = doc.createElementNS(url, "layer")
        xmlnode.setAttributeNS(url, "x", "%d"%l.offsets[0])
        xmlnode.setAttributeNS(url, "y", "%d"%l.offsets[1])
        xmlnode.setAttributeNS(url, "width", "%d"%l.width)
        xmlnode.setAttributeNS(url, "height", "%d"%l.height)
        xmltext = doc.createTextNode(l.name);
        xmlnode.appendChild(xmltext)
        rootelt.appendChild(xmlnode)

    gimp.pdb.gimp_message( "Saving to %s"%(outdir+wcname) );
    file_object = open(outdir+os.sep+wcname, "w")
    file_object.write(doc.toprettyxml());
    file_object.close()
    
register(
    "python_fu_exportlayoutxml",
    "Layout Builder XML",
    "Build a layout in gimp and export layer info as XML",
    "Michel Ardan",
    "Michel Ardan Company",
    "2011",
    "<Image>/MyScripts/Layout Builder XML",
    "*",
    [
      (PF_STRING, "widgetcontainer_name", "File Name", "layout.xml"),
      (PF_DIRNAME, "out_dirname", "Output Directory", ""),
    ],
    [],
    xml_layout_builder )

main()

I'm using "minidom" to output a very simple XML file here. It boils down to creating a document object, and insert a node for each layer, each node will have some attributes set from the layer's information, and the content of the node will be the name of the layer. In the end, a file is created, and we use minidom's "toprettyxml" function to easily convert our XML object to some text.

One thing of interest here, you may have noticed the "coding" tag in the first lines of the script. If like me, your language has accents and special characters in it, Python will not like you writing comments with those characters in them unless you add this tag.

To end part 3 of this tutorial, check out this cool Python IDE call Eric, it does a very good job of syntax hilighting and checking, even for simple Gimp scripts. It's available at: http://eric-ide.python-projects.org/index.html

More interesting links to check out:

http://www.linuxplanet.com/linuxplanet/tutorials/6720/3/

http://meetthegimp.org/why-python/

http://blenderartists.org/forum/showthread.php?t=84073

http://ojs.pythonpapers.org/index.php/tppm/article/viewFile/103/123

http://www.elvanor.net/wiki/GIMP_Scripting

 

See you next time for more Python-Fu!

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.