Inkscape extensions by non developers, for non developers. A primer.
When we started developing Taiga at Kaleidos, we decided, for the first time, to design the product internally instead of hiring an external designer. We wanted Taiga to be truly as theTaiga team is, and it required to fully understand the soul behind it. Since we only use open source software for our front and back end coding stuff, it made sense to use an open source tool as well for our design process. So we decided to go with Inkscape, it was very know, enough powerful and we had some previous experience with it.
There is always a reason
While using Inkscape for advanced design work I found out that is mostly used by non developers, so its extensions are made by developers, for developers. There are a lot of math-related thinguies here (which is great) but not the extensions that I was looking for as a designer (something like this). Ironically, people are developing open source plugins and patches for proprietary software. Why? No idea!
So I decided I should learn how to make extensions to get same same features as others have but still using open source software, push forward OSS alternatives and hopefully, help other designers to come to OSS, use it and even develop their own extensions.
So, basically, it was a rant. I know.
This post is a basic explanation about how I developed a couple extensions for Inkscape not being myself a python developer (actually, I had no idea about python).
Open your text editor, we are going to get our hands dirty!
Are you ready?
Lets begin with the extensions structure. A basic Inkscape extension is formed by two files:
- A python script (extension_name.py)The responsible for the magic
- A inkscape extension description file (extension_name.inx) This will be the responsible of communicating the inkscape UI with our script.
Lets split this files up!
Extension description file (.inx)
The INX file (extension description file) will be the responsible of defining how the UI user interaction should be to connect Inkscape with our python script.
Lets see how a basic INX file is and lets analyze its parts:
The XML definition since this file is a valid XML
<?xml version="1.0" encoding="UTF-8"?>
A simple Inkscape extension tag
The extension name. Remember, this will become the name in the UI button so add a nice name.
<_name>Your extension awesome Name</_name>
The extension ID. This ID should be unique, you could just replace ‘org.inkscape.id’ with ‘org.inkscape.extension_name’.
The dependencies. Here you should add the relative path to your python script (.py) file. If this file does not exist the extension will not be loaded.
<dependency type="executable" location="extensions">plugin_name.py</dependency>
Extension params. Here we will set the UI of our extension. Will the user need a textfield? A range selector? Tabs? We will use the user options in our python script afterwards. Lets see a basic example:
<param name="some_name" type="string" _gui-text="Some text label">Some default text</param>
- name: Its the name of your option. Set an easy name because it will be used in your script to get this param value
- type: By default, Inkscape offers a very small set of GUI options: strings (textfields), interger(numbers field from 1 to 10), float(decimal numbers field), booleans (a checkbox selector), enum (a dropdown list), optiongroup (a multiselect), color (a colorpicker), desc (a free text) and notebook (a tab selector).
- _gui-text: This will be the label of the UI element so add a self explanatory copy
- Content: In some cases you can add a default text or set a boolean to true or false.
- _gui-hidden: A hidden parameter that can have a value.
The inkscape wiki page of INX file params is well documented.
The GUI menu. Here you will set the name of the button your users will click to perform the action. It will be useful to set your plugin at the submenu tag. Forget about the rest in this tutorial, its just the structure.
<submenu _name="Your plugin name"/>
The reference script. As in the dependencies you set at the beggining, you should tell inkscape which file it has to execute. Add here the relative path to your python script.
<command reldir="extensions" interpreter="python">plugin_name.py</command>
And that's it for the INX file! Now, if we install this plugin, you should be able to see a new option under extensions menu, and your plugin name sub option on hover.
The Python Script (.py)
As we have seen, the INX requires a python script to be executed. This script will be the responsible for the transformation of our SVG (everything in the inkscape work area is an SVG).
As said in the inkscape wiki this file can do three things:
- Input, providing translation from a file format to SVG
- Output, providing translation from SVG to a format
- Effect, taking in SVG, changing it, and then outputting SVG
I know, most of us have no clue on how python works. Don’t worry if you do not understand everything, its a basic example simple to read. You’ll understand later or you can read a more advanced version at inkscape wiki extension tutorial.
Lets see how it looks, in its simplest version:
Ok, lets open our file and follow (and understand) the code:
First, set the file as executable so Inkscape can execute its content and the character encoding
#-*- coding: utf-8 -*-
Import Inkex, a inkscape dependency, that will do some magic for us applying our changes to the SVG.
Declare a new Class() inheriting from inkex
Declare the init() function that will be executed when the class is invoked and add the option params defined at the INX (remember we set this params to be used later in the INX section? Yes, its now!)
self.OptionParser.add_option('-x', '--something', action='store', type='string', dest='optionName', default='defaultvalue', help='Helper text for this option')
Lets review the OptionParser according to the inkscape Wiki
- action — An action that will do something with our value. In this case we store the value in the dest value (following point)
- dest — Destination of option action specified by action argument. Using opti nName value we say that we want to store this value to self.options.optionName.
- type — Type of option value. We use string here but could anything of the defined in the INX file.
- default — Defalut value for this option if it is not specified.
- help — A help string that will be displayed if script will be given no arguments or some option or argument will have wrong syntax.
Create a new effect() function to get this values from the optionParser. It receives as first argument self, which is its parent class, in this case is MyExtensionName
option = self.options.optionName
- In the first line, we store the value we set in the optionParser in the variable option so we could use it anywhere in the function.
- In the second line, we just ask the parent to call a second function called _main_function that receives the option variable as a second parameter.
The main function, although it is not necessary (we could do everything in the previous one) helps keep clarity. Do whatever you can to your SVG (if you have no idea of python I recommend you to be humble and try something simple). In this case, we just print the value. This will have no effects on inkscape SVG.
Find a simple extension example on my extensions, since are quite simple because I am not a python developer
def _main_function(self, option):
Last step: Invoke the class and execute the affect() function that will do its inkscape magic to execute it on the SVG.
if __name__ == ‘__main__’:
MyExtension = MyExtensionName()
Cold outside, warm inside
I know, at first glance it looks very difficult, but remember that we have seen every code line to understand how it works. It is actually very small code to start with. You’ll see that you will need new functions and more code lines soon.
To install the extension, just copy the two files (extension_name.py and extension_name.inx) into your local inkscape extensions folder
As always, inkscape comes prepacked with handy and well written extensions in its core. Its a nice place to find how others made things and find clues on how to solve your own extension challenges. There are also dozens of extensions out there and there to learn from.
Good luck, and please, share your amazing extensions with us!