Inkscape Extension Development
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:
- E and F are translations;
- A and D are scales;
- C and B are skews.
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:
- Extension subsystem lists the various types of extensions, basically concluding that you can either write internal (C/C++) ones or scripts, as the XSLT and DOM implementation aren't there yet.
- Script extensions explains what scripts do – in essence they're commands called with specific arguments whose output is piped into Inkscape.
- Python modules for extensions suggests a couple of convenience Python modules in case you want to write these scripts in Python.
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).