**NAME** dia2kroki - convert textual descriptions for various diagram tools to image URL's using the https://kroki.io/ webservice. kroki4tcl - extended version bundled as package, GUI and terminal application (see below) <> **CODE** ====== # dia2kroki.tcl - unicode versions see below proc dia2kroki {text {dia graphviz} {ext svg}} { set b64 [string map {+ - / _ = ""} [binary encode base64 [zlib compress $text]]] set uri https://kroki.io//$dia/$ext/$b64 } # like to know the code of an URL proc kroki2dia {url} { set text [regsub {.+/} $url ""] set dia [zlib decompress [binary decode base64 [string map {- + _ /} $text]]] } ====== **EXAMPLES** ***dia2kroki*** ====== % source dia2kroki.tcl % puts [dia2kroki "digraph G { A -> B }"] https://kroki.io//graphviz/svg/eJxLyUwvSizIUHBXqFZwVNC1U3BSqAUAREAFzQ ====== This URL can be directly embedded into HTML pages or on Markdown code. Unfortunately as far as I know Tcler's Wiki can't embed external images without an extension like png, svg etc. So just the link to the image is shown. https://kroki.io//graphviz/svg/eJxLyUwvSizIUHBXqFZwVNC1U3BSqAUAREAFzQ To fix this we have to use the ''inlinehtml'' syntax: ====== <> . <> ====== Here the output: <> . <> Here an example for plantuml: http://www.plantuml.com ====== % source dia2kroki.tcl % dia2kroki { @startuml Bob -> Alice : hello @enduml } plantuml png https://kroki.io//plantuml/png/eJzjciguSSwqKc3N4XLKT1LQtVNwzMlMTlWwUshIzcnJ53JIzUsBSQIABnMM1A ====== Here this image, this time a PNG: <> <> ***kroki2dia*** Using `kroki2dia` you can get the code of an kroki URL back to text: ====== % kroki2dia https://kroki.io//graphviz/svg/eJxLyUwvSizIUHBXqFZwVNC1U3BSqAUAREAFzQ digraph G { A -> B } ====== **GUI** Let's build around those two functions a graphical user interface where you can enter your diagram code in a text widget, after file saving the extensions determines the diagram type and the data are send to the server. The produced image is then fetched to our local machine in parallel to the source file and then displayed in a ttk::label below. For tools like [Pikchr] which can only create SVG images https://cairosvg.org%|%cairosvg%|% is required to convert the image then locally to a PNG image. Here follows the code: ====== namespace eval ::kroki { } proc ::kroki::dia2kroki {text {dia graphviz} {ext svg}} { set b64 [string map {+ - / _ = ""} [binary encode base64 [zlib compress $text]]] set uri https://kroki.io//$dia/$ext/$b64 } proc ::kroki::kroki2dia {url} { set text [regsub {.+/} $url ""] set dia [zlib decompress [binary decode base64 [string map {- + _ /} $text]]] } proc ::kroki::gui {{path ""}} { package require Tk variable txt variable img variable lastfile variable filetypes variable maps ttk::frame $path.top foreach btn [list New Open Save SaveAs Exit] { ttk::button "$path.top.[string tolower $btn]" -width 10 -text $btn -command ::kroki::file$btn pack "$path.top.[string tolower $btn]" -side left -padx 5 -pady 5 } pack $path.top -side top ttk::panedwindow $path.pwd -orient horizontal ttk::frame $path.pwd.frame ttk::label $path.pwd.frame.lbl -text "Hello" place $path.pwd.frame.lbl -relx 0.5 -rely 0.5 -anchor center tk::text $path.pwd.text $path.pwd add $path.pwd.text $path.pwd add $path.pwd.frame pack $path.pwd -side top -fill both -expand true # variables set txt $path.pwd.text set img $path.pwd.frame.lbl set lastfile "" set filetypes { {{BlockDiag Files} {.bdia} } {{Ditaa Files} {.ditaa} } {{Graphviz Files} {.dot} } {{Mermaid Files} {.mmd} } {{Pikchr Files} {.pik} } {{PlantUML Files} {.puml} } {{SeqDia Files} {.sdia} } {{All Files} * } } set maps [dict create bdia blockdiag ditaa ditaa dot graphviz puml plantuml \ mmd mermaid pik pikchr sdia seqdiag] # bindings bind $txt ::kroki::fileSave # styles ttk::style layout WLabel [ttk::style layout TLabel] ttk::style layout WFrame [ttk::style layout TFrame] ttk::style configure WLabel -background white ttk::style configure WFrame -background white $img configure -style WLabel $path.pwd.frame configure -style WFrame } proc ::kroki::fileNew {} { variable txt variable lastfile "" $txt delete 1.0 end } proc ::kroki::fileSave {} { variable lastfile variable txt variable maps variable img if {$lastfile eq ""} { ::kroki::fileSaveAs return } if {$lastfile ne ""} { set text [$txt get 1.0 end] set out [open $lastfile w 0600] puts $out "$text" close $out set ext [string range [file extension $lastfile] 1 end] if {![dict exists $maps $ext]} { tk_messageBox -title "Error!" -icon error -message "Wrong file extension `.$ext`!\nUse .dot, .mmd, .puml or .pik!" -type ok return } if {$ext eq "pik"} { if {[auto_execok cairosvg] eq ""} { tk_messageBox -title "Error!" -icon error \ -message "Error: Pikchr diagrams need cairosvg!\nPlease install: pip3 install cairosvg --user" \ -type ok return } set uri [::kroki::dia2kroki $text [dict get $maps $ext] svg] puts "fetching $uri" exec -ignorestderr wget $uri -O [file rootname $lastfile].svg 2>@1 exec -ignorestderr cairosvg -f png -o [file rootname $lastfile].png [file rootname $lastfile].svg } else { set uri [::kroki::dia2kroki $text [dict get $maps $ext] png] puts "fetching $uri" exec -ignorestderr wget $uri -O [file rootname $lastfile].png 2>@1 } if {[file exists [file rootname $lastfile].png]} { image create photo ::kroki::img -file [file rootname $lastfile].png $img configure -image ::kroki::img } wm title . "kroki-gui [file tail $lastfile]" } } proc ::kroki::fileSaveAs {} { variable filetypes variable txt variable lastfile set types $filetypes unset -nocomplain savefile set savefile [tk_getSaveFile -filetypes $types] if {$savefile != ""} { set lastfile $savefile ::kroki::fileSave } } proc ::kroki::fileOpen {{filename ""}} { variable txt variable lastfile variable filetypes set types $filetypes if {$filename eq ""} { set filename [tk_getOpenFile -filetypes $types] } if {$filename != ""} { $txt delete 1.0 end if [catch {open $filename r} infh] { puts stderr "Cannot open $filename: $infh" exit } else { while {[gets $infh line] >= 0} { $txt insert end "$line\n" } close $infh } set lastfile $filename } } proc ::kroki::fileExit {} { set answer [tk_messageBox -title "Question!" -message "Really exit ?" -type yesno -icon question] if { $answer } { exit 0 } } if {[info exists argv0] && $argv0 eq [info script]} { kroki::gui if {[llength $argv] > 0} { if {[file exists [lindex $argv 0]]} { ::kroki::fileOpen [lindex $argv 0] ::kroki::fileSave } } } ====== Here two example images for the running application first editing https://github.com/drhsqlite/pikchr%|%Pikchr%|% code: <> <> And then, if you prefer more the old ASCII style, you can create as well http://ditaa.sourceforge.net/%|%ditaa%|% images: [kroki-gui-ditaa] **UNICODE** Here versions of the two functions which can as well encode Unicode diagrams (not yet completely tested): ====== proc ::kroki::dia2kroki {text {dia graphviz} {ext svg}} { set b64 [string map {+ - / _ = ""} [binary encode base64 [zlib compress [encoding convertto utf-8 $text]]]] set uri https://kroki.io//$dia/$ext/$b64 } proc ::kroki::kroki2dia {url} { set text [regsub {.+/} $url ""] set dia [encoding convertfrom utf-8 [zlib decompress [binary decode base64 [string map {- + _ /} $text]]]] } ====== Here is a diagram which I encoded that way: ====== A₀ ---> A₁ ---> A₂ ---> A₃ ---> A₄ | | | | | | f₀ | f₁ | f₂ | f₃ | f₄ | | | | | v v v v v B₀ ---> B₁ ---> B₂ ---> B₃ ---> B₄ ====== And that is the image which was generated using kroki::dia2kroki: <> <> **TODO's** * convert without GUI `kroki.tcl dia.ditaa dia.png` * display the URL not only in the terminal * tls and http package instead of wget * some more tools from https://krokio.io **kroki4tcl package** An improved version is available as package on Github. You can start the GUI application with `kroki4tcl.tcl --gui` [https://raw.githubusercontent.com/mittelmark/DGTcl/master/lib/kroki4tcl/examples/sample-sbob-gui.png] The application allows you to edit one diagram per file or using the Markdown mode multiple images per one file. Just switch to the code chunk you would like to preview with your insert cursor and press Ctrl-s to save the file. Here an example: [https://raw.githubusercontent.com/mittelmark/DGTcl/master/lib/kroki4tcl/examples/sample-markdown-gui.png] That way you can collect multiple graphics in one file. Here the links to start (click on the help button to start): * Download: https://downgit.github.io/#/home?url=https://github.com/mittelmark/DGTcl/tree/master/lib/kroki4tcl * README: https://htmlpreview.github.io/?https://github.com/mittelmark/DGTcl/blob/master/lib/kroki4tcl/README.html * Help-Manual for the GUI: https://github.com/mittelmark/DGTcl/blob/master/lib/kroki4tcl/kroki4tcl.md Please note: This is a WIP. ---- **DISCUSSION** [DDG] - 2022-02-18: The main advantage of this little function is that you can create these images without having all these diagram tools installed just using basic Tcl (8.6). You can embed the images directly into your documentation using a simple hyperlink or you can download the images using Tcl with the [http] and [tls] libraries or a tool like wget. In the afternoon I added as well a little GUI which needs a running Tcl and the wget application. For pikchr graphics as well cairosvg is required to convert from SVG to PNG. [DDG] - 2022-02-21: Adding Unicode version which needs probably more testing. [DDG] - 2022-02-23: Extended version as package kroki4tcl. GUI allows you to edit several images in one Markdown file within separate code blocks. [TB] - 2022-10-19: This is marvellous! I just stumbled across kroki (via mermaid) and just wanted to create a Wiki page with a small function to call kroki from Tcl ... now I see it has already been done, and even much more than that! Very helpful!