mirror of
https://github.com/lleene/hugo-site.git
synced 2025-01-23 20:12:21 +01:00
134 lines
5.1 KiB
Markdown
134 lines
5.1 KiB
Markdown
---
|
|
title: "Building With SVG"
|
|
date: 2021-08-28T11:53:54+02:00
|
|
draft: false
|
|
toc: true
|
|
tags:
|
|
- 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.
|
|
|
|
``` 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; }
|
|
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.
|
|
|
|
{{< figure src="/images/posts/example_kgt.svg" title="example_kgt.svg" >}}
|
|
|
|
## 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("./posts/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.
|
|
|
|
{{< figure src="/images/posts/example_trd.svg" title="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.
|
|
|