hugo-site/content/posts/2021/building-svg.md

5.0 KiB

title date draft toc tags
Building With SVG 🖼 2021-08-28T11:53:54+02:00 false true
svg
xml
python
code

SVG is generally my image format of choice having used it for illustrations, chip diagrams, device specifications, and visual outputs generated by code. SVG is plain text-baesd xml that is structured with some top level object/properties followed by standardized objects that draw lines and shapes.

On a few occasions, I have scripted the generation of some SVG illustration where some parameters are extracted from a database that are then visualized. These scripts are generally quite simple since you just define some pre-formatted shapes and place them inside the drawing region. Besides this I think it useful to highlight some of the automated tools and libraries that are useful with similar functionality.

KGT: Kate's Grammar Tool

KGT is a pretty neat starting point to experiment with this kind of function. It is relatively self contained and produces compact SVG objects from simple statements.

Build Instructions

Building libfms and kgt from source was not too much of a hassle although the build / dependency documentation could be better. This was build with my WLS-Ubuntu environment.

apt install clang pmake
git clone --recursive "https://$libfsm_REPO/libfsm"
pushd libfsm; CC=clang PREFIX=$HOME pmake -r install; popd
git clone --recursive "https://$KGT_REPO/kgt"
pushd kgt/src; CC=clang PREFIX=$HOME pmake -r install; popd

The main issue is noticed is the SVG being generated uses path {rouded} in its style definition which the svg rasterizer from librsvg2 2.40.20 complained about. Getting the latest build however is quite involved requiring the latest cairo and proppler libraries as well. Ideally generating pngs or rasterizing won't be needed.

Example

Just to show a typical use case for making an illustration using the KGT tool, below I generate the svg for one of the examples included by it's repository.

KGT_DEF="<personal-part> ::= <first-name> | <initial> \".\" "
echo "$KGT_DEF" | kgt -l bnf -e svg | awk -vf1="$(<style.svg)" -f replace_style.awk > example_kgt.svg

The style is automatically introduced in the xml header section which is mostly plain black. This has some legibility issues for dark themes so a short awk script is used to replace the style with one that we define for this theme.

BEGIN{style_flag=0}
/<style>/{style_flag=1}
{if(style_flag == 0) print $0}
/<\/style>/{style_flag=0;print f1}

For completeness we include the style definition below but this could be added directly to KGT as a feature in future releases.

<style>
  rect, line, path { stroke-width: 1.5px; stroke: white; fill: transparent; }
  rect, line, path { stroke-linecap: square; stroke-linejoin: rounded; }
  path { fill: transparent; }
  text { fill: white; font-family:'Trebuchet MS'; }
  text.literal {  }
  line.ellipsis { stroke-dasharray: 1 3.5; }
  tspan.hex { font-family: monospace; font-size: 90%; }
  path.arrow { fill: white; }
</style>

The final result is shown below.

example_kgt.svg

Tabatkins Railroad Diagrams

On the topic of rail-road diagrams there is also a repository from tabatkins which is a python based code-base for generating similar SVG diagrams as KGT but without having to deal with building or running binaries. I prefer monochrome diagrams with plan formatting so again we are overriding the default style.

style = ( ''
+'\tsvg.railroad-diagram {\n\t\tbackground-color:none;\n\t}\n'
+'\tsvg.railroad-diagram path {\n\t\tstroke-width:1.5;\n\t\tstroke:white;\n\t\tfill:rgba(0,0,0,0);\n\t}\n'
+'\tsvg.railroad-diagram text {\n\t\tfont:bold 14px monospace;\n\t\tfill: white;\n\t\ttext-anchor:middle;\n\t}\n'
+'\tsvg.railroad-diagram text.label{\n\t\ttext-anchor:start;\n\t}\n'
+'\tsvg.railroad-diagram text.comment{\n\t\tfont:italic 12px monospace;\n\t}\n'
+'\tsvg.railroad-diagram rect{\n\t\tstroke-width:1.5;\n\t\tstroke:white;\n\t\tfill:none;\n\t}\n'
+'\tsvg.railroad-diagram rect.group-box {\n\t\tstroke: gray;\n\t\tstroke-dasharray: 10 5;\n\t\tfill: none;\n\t}\n'
)

Styling is best done on a case to case basis with various color-schemes such as using white text/lines for dark themes. Since this is all handeled in python the overall interface. Possibly including some kind of command-line utility here would be quite good but it depends on the final flow for figure generation. Using the style definition shown above, generating a similar example as before would look like this:

import railroad
with open("./test.svg","w+") as file:
    obj = railroad.Diagram("foo", railroad.Choice(0, "bar", "baz"), css=style)
    obj.writeSvg(file.write)

The final result is shown below.

example_kgt.svg

Note that this figure is quite a bit more compact but adding additional labels or customizations outside the scope of the library will probably require quite a bit of manual work. This could be a fun side project though.