Jérôme Belleman
Home  •  Tools  •  Posts  •  Talks  •  Travels  •  Graphics  •  About Me

Inkscape Extension Development

1 Feb 2014

If Inkscape comes bundled with many extensions, there will always be repetitive actions specific to your style of work and which you may be able to automate.

1 The Sad Truth About Extensions

Thankfully, Inkscape makes writing extensions sufficiently easy to write that they make it totally worth it.

However, what extensions do is nothing more than to juggle with XML. There are no facilities to perform higher-lever operations such as applying a union boolean operation on a set of objects or adjusting blur like one would do with the Blur slider in the Fill and Stroke dialogue. You'll just have to square with the fact that you can't automate everything – some of the work is left to the designer.

Of course, these limitations could be overcome with internal (C/C++) extensions but that's another kettle of fish.

2 User Interface

2.1 Extensions Files

You're supposed to add an inx/py pair of files to your ~/.config/inkscape/extensions directory. Just copy sample ones from /usr/share/inkscape/extensions.

The inx file specifies an id which is useful to e.g. bind it to keys. You need to list dependencies to other modules which typically live in /usr/share/inkscape/extensions too. Funnily enough, you have to mention the extension script here too. This file is also the place to indicate what arguments are expected by the script and that's probably also the way to describe the dialogue. And then the command line, of course.

2.2 Key Bindings

The ~/.config/inkscape/keys directory allows you to define or override specific key bindings. Check what's in /usr/share/inkscape/keys to make sure you don't clash with anything useful. You'll find that key binding sets are stored in separate files. We normally use default.xml. If you inspect this file closely, you'll notice that the smallest number of bindings use the Ctrl,Shift,Alt (or Ctrl,Alt,Shift, search for .*Shift\&.*Ctrl\&.*Alt) modifiers, so that's what we would have preferred, except that for some reason it doesn't work. Next would have been Alt but it clashes with menu operation. And Shift,Alt doesn't work either. Fine, then, Ctrl,Alt.

3 Programming Interface

From all the examples I've seen, you're supposed to implement a class with a name of your choosing, which will inherit from inkex.Effect (or any other intermediate class which might be defined in /usr/share/inkscape/extensions. As far as I could see, inkex.Effect is the top-level one. I've experienced that you're supposed to implement an effect() method. This will indirectly be called by running affect() – which you're expected to call yourself from your extension script. Yes, effect() and affect(), no spelling mistake here.

The self object, an inkex.Effect in essence, provides a number of useful members, namely document.

4 Programmatically Drawing

4.1 Tag Names

You'll often need to use full-fledged tag names (something to do with the namespace, I guess) looking like {http://www.w3.org/2000/svg}image instead of just image. Unfortunately, the best way I found to come up with the fully-qualified name is to programmatically iterate through nodes and see what their names look like.

4.2 Creating Nodes

You may see some examples which refer to namespaces when creating nodes. Never seen the need for this, never seen the difference in the resulting XML. Really, all you ever need to do is call the inkex.etree.SubElement(parent, 'tagname') constructor. Note that it also takes a dictionary for attributes, most of which can be left out as Inkscape will set default values.

4.3 Creating and Applying Effects

I used the edge3d.py extension as a reference to do this. Creating effects involves adding a filter node in the defs tag, where you should set an id attribute. This filter node parents a node for each effect (e.g. feBlend).

4.4 Node Selection

Selected nodes are available in self.selected. Interestingly, self.getselected() will always return None. In turns out that self.selected is in fact a dictionary, unordered, which means we don't know in which order objects have been selected. A better solution therefore is self.options.ids, which I found Sozi use, as this is a real list.

4.5 Moving Nodes in the Tree

For instance, when you need to move a loose node into a group. All you need to do is to add the node to the group (with append(), or extend() if you have several of them). You don't need to remove the previous node, bizarrely enough. I wager xml.etree.ElementTree does that for you.

4.6 Coordinates

Inkscape (and areas as specified with the --export-area=x0:y0:x1:y1 option) takes the bottom-left node of objects and pages as reference, but SVG takes the top-left node of objects and pages. You'll need to do some work on the x axis to switch from one to the other.

4.7 Transformations

Tavmjong Bah explains that the transformation matrix is defined as:

x'=Ax+Cy+E and y'=Bx+Dy+F

... where:

Rotations are performed by changing several of these parameters. I used this in the export extension. I found that it was quite convenient to take an object at the reference coordinate to avoid surprises with translations. So, matrix is one of the transformations known to Inkscape but I believe you can use scale too.

4.8 I/O

What you effectively work on, is a temporary XML file. If you need to run inkscape against it (e.g. to export something), make sure you save it with self.document.write(self.svg_file) first (self.svg_file is one of the many ways to refer to the temporary file).

When running subprocess.Popen(), make sure to douse both stdout (lest Inkscape crashes) and stderr (lest you get message dialogues displayed).

5 Debugging

Don't print to stdout, that causes Inkscape to crash – no less. Only print to stderr, the message will be displayed in a dialogue (which will suspend extension execution). I have a suspicion that there are other, more elegant ways of communicating with the user. Probably worth grepping for it in /usr/share/inkscape/extensions.

6 References

http://www.inkscape.org → LEARN → Inkscape Wiki provides a couple of links to get an overview of what kind of extensions you can write:

There's pretty much no useful documentation other than this. Once you get a hang of what extensions really are about, you're better off grepping around with the existing ones in /usr/share/inkscape/extensions. Many people write extensions too. I quite liked getting my inspiration from Sozi. And then there's the fact that the inkex Python module, which seems to be the base of everything happens, to simply use The ElementTree XML API.

Tavmjong Bah's Inkscape – Guide to a Vector Drawing Program explains the transformation matrix (and many other useful things about Inkscape in general).