The functionality of the Inkscape extensions was almost finished last week. Most of the work I’ve done this week was optimization and modification to different parts of the application. Some of these changes were made to the Witty application (in C++) and some were made to the extensions (in Python).
The first of these changes was applying the new naming convention for naming the pins of the elements. I explained the naming convention we implemented first in my previous blog. The problem we encountered was that we had to manually input the Verliog names for the pins when creating the component in Inkscape. This might seems like a small problem but imagine writing the pins names for more than 1000 components; and some of them have more that 50 pins! We changed our approach to extract the names from the modules fzb file instead of the Verilog file. If you have read any of my last two blogs you already know that our input files are Fritzing fzb files. In our current implementation we rely completely on the fzb file, by automatically extracting the names of the pins “that the user will see” and modifying these names to generate a corresponding Verilog names. Verilog names can contain “&”, “”, letters and numbers only. Also, every name should beging with either “” or a letter. Hence, we take the names from the fzb file, change every character that cannot exist in the Verilog name with an underscore, and attach “pin_” at the beginning to insure that the name starts with a letter and not a number. For example, if a pin has the name “3.3 V” in the fzb file, the generated Verilog name will be “pin_3_3_V”. To accomplish this in Python there are many ways; I have implemented it using regular expressions. First I specified all the character that I want to remove (which basically I specified the character I wanted to keep and negated them in regular expressions). Then I used the regular expressions “sub()” function to substitute characters with an underscore. The code looks something like this
charsToRemove = ‘[^a-zA-Z_$0-9]’
re.sub(charsToRemove, ‘_’, myString)
This process is done in the Inkscape import extension. These names are then used to create a base Verilog file. The file simply contains an empty module that has the component name, and the generated pins names as ports. Here is an example of a Verliog file generated by the export extension SPI flash memory.
clk_i, rst_i, adr_i, cyc_i, stb_i, we_i, sel_i, dat_i,ack_o, dat_o
Another addition to the import extension is the ability to specify the “mode” of the pins. Mode can be either input, output or inout. After specifying the mode, each will pin will have an xml “mode” attribute and its value will be the specified mode. These modes are used for validating the components connections in the schematic editor to enhance the user experience. That is, an input pin can only be connected to an output pin, an output pin can only be connected to an input pin, and an inout pin can only be connected to an inout pin.
The export extension was modified as well. Previously I exported the SVG format of the components using Python lxml “stringify()” function. It worked well for most of the shapes in the element SVG, however, some parts of the SVG looked differently when viewed in the browser. That is because the shape itself contains some Inkscape attributes that might specify its appearance. Hence, when displayed in the browser these attributes are ignored! Inkscape provide an option to export as Plain SVG. When exporting like this, the output will not contain any Inkscape attributes and it will look the same when rendered in the browser. However, this option removes all the user created attributes, such as “magnet”, “port”, and “mode” that we are using for the pins.
Inkscape, yet, has a third option, which is exporting as an optimized SVG. With this I can remove all Inkscape attributes while maintaining the ones I created. The problem I faced is that Inkscape does not provide an API to call these functions from within an extension. This problem will make the usage of the extension a bit complicated as the designer will need to first export it as an optimized SVG first then using the extension to create the JointJS element definition. Hence, this problem had to be solved.
After a lot of digging I found the script that Inkscape uses when exporting as optimized SVG. Originally it was a third party script but now it is included in Inkscape by default. It is Scour, which is “an open-source Python script that aggressively cleans SVG files, removing a lot of ‘cruft’ that certain tools or authors embed into their documents”. So instead of using Inkscape functionality I now use scour directly by calling it from within the extension to clear the SVG and create the JointJS with one click. I calling Scour using the function
subprocess.call([“scour”, “-i”, “tmpIn.svg”,”-o”, “tmpOut.svg”])
where tmpIn.svg and tmpOut.svg are temporarily files used only when exporting.
On the Witty side modification were made to the schematic editor, specifically, the function that creates new elements “components” in the editor. Previously all JointJS definitions of the components were in one big library, and this library is imported when the page loads. Apparently this is not the ideal solution when the number of modules increases. Inkscape export extension creates a separate file for each component so that it can be imported separately into the editor. Hence, when creating new components, the function first loads the corresponding JoinJS component definition, and then instantiate it once loaded. My only concern with this approach is with the speed of instantiating components, especially when creating multiple components at once, as each component waits for his JointJS definition to be loaded, as well as the JointJS definitions for all components that should be instantiated before it is created.