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

133 lines
5.0 KiB
Markdown
Raw Normal View History

---
2021-10-30 10:33:38 +02:00
title: "Building With SVG 🖼"
date: 2021-08-28T11:53:54+02:00
2021-08-30 17:54:51 +02:00
draft: false
toc: true
tags:
- svg
- xml
2021-10-31 15:18:54 +01:00
- python
- code
---
2021-10-30 10:33:38 +02:00
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.
2021-10-30 10:33:38 +02:00
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
2021-09-19 13:41:50 +02:00
the build / dependency documentation could be better. This was build with my
WLS-Ubuntu environment.
``` bash
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.
``` bash
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.
``` awk
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.
``` xml
<style>
rect, line, path { stroke-width: 1.5px; stroke: white; fill: transparent; }
rect, line, path { stroke-linecap: square; stroke-linejoin: rounded; }
path { fill: transparent; }
2021-08-30 17:54:51 +02:00
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](/images/example_kgt.svg)
2021-10-30 10:33:38 +02:00
## Tabatkins Railroad Diagrams
On the topic of rail-road diagrams there is also a repository from
[tabatkins](https://github.com/tabatkins/railroad-diagrams) 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.
``` python
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:
``` python
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](/images/example_trd.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.