dia2plantuml

NAME

dia2plantuml - convert textual descriptions for various diagram tools to image URL's using the https://www.plantuml.com/ server (PlantUML manual ).

CODE

#!/usr/bin/env tclsh

package provide plantuml2dia 0.1

### file dia2plantuml.tcl
proc dia2plantuml {text {ext svg}} {
    ### plantuml does use a different order in encoding
    set b64 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
    set pml 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_

    set lmapper [list]
    set i 0
    foreach char [split $b64 ""] {
        lappend lmapper $char
        lappend lmapper [string range $pml $i $i]
        incr i
    }
    set b64 [string map $lmapper [binary encode base64 [zlib compress [encoding convertto utf-8 $text]]]]
    set uri https://www.plantuml.com/plantuml/$ext/~1$b64
    return $uri
}

### converting URL to diagram code back
proc plantuml2dia {uri} {
    set b64 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
    set pml 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_
    set lmapper [list]
    set i 0
    foreach char [split $pml ""] {
        lappend lmapper $char
        lappend lmapper [string range $b64 $i $i]
        incr i
    }
    set text [regsub {.+/} $uri ""]
    set text [regsub {^~1} $text ""]
    set dia [encoding convertfrom utf-8 [zlib decompress [binary decode base64 [string map $lmapper $text]]]]
}

### make it a standalone application
if {[info script] eq $argv0} {
    proc usage {} {
        puts "Usage: $::argv0 plantuml-url|diagram-file"
    }
    proc help {} {
        puts "PlantUML encoder/decoder"
        puts "Converts PlantUML code in files to PlantUML URLS or"
        puts "converts PlantUML URL's back to diagram code."
        puts "Note: Only URLS with the ~1 prefixes can be currently encoded back!"
        puts "Author: Detlef Groth, University of Potsdam, Germany"
        puts "License: BSD 3.0"
        puts ""
        usage
    }
    if {[llength $argv] == 0} {
        usage
    } elseif {[info exists argv] && "--help" in $argv}  {
        help
    } elseif {[llength $argv] == 1}  {
        if {[regexp  {^http} [lindex $argv 0]]} {
            if {![regexp "~1" [lindex $argv 0]]}  {
                puts "Error: Only URL's with ~1 inside can be decoded!"
            }  else {
                puts -nonewline [plantuml2dia [lindex $argv 0]]
            }
        } else {
            if {![file  exists [lindex $argv 0]]} {
                puts "Error: File '[lindex $Eargv 0]' does not exists!"
            } else {
                if [catch {open [lindex $argv 0] r} infh] {
                    puts stderr "Cannot open [lindex $argv 0]e: $infh"
                    exit
                } else {
                    set text [read $infh]
                    puts -nonewline [dia2plantuml $text]
                }
            }
        }
    }
}

This code was translated from Python to Tcl, for the Python code look here: https://github.com/dougn/python-plantuml/blob/master/plantuml.py - the encoding used by PlantUML is explained here: https://plantuml.com/text-encoding

EXAMPLES

% source dia2plantuml.tcl
% puts [dia2plantuml "class TclExample"]
https://www.plantuml.com/plantuml/svg/~1U9nBpaaiBbO8ISvnhKZCBSX91G0pUGOc
% puts [plantuml2dia [dia2plantuml "class TclExample"]]
TclExample

Here the image:

.

Here now a run as a standalone application:

### make a test file
$ echo -e "class A {}\nclass B {}\nA -> B"  > class.pml
### encode it as URL (image below)
$ dia2plantuml.tcl class.pml 
https://www.plantuml.com/plantuml/svg/~1U9nBpaaiBbPmLAYkvKe6Cvr0J4S5NJi59ou0Zfe8R0==
### decode it back
$ dia2plantuml.tcl https://www.plantuml.com/plantuml/svg/~1U9nBpaaiBbPmLAYkvKe6Cvr0J4S5NJi59ou0Zfe8R0==
class A {}
class B {}
A -> B
.

SEE ALSO


DISCUSSION

Please discuss here.

  • DDG - 2023-07-29: decoding an URL back to diagram code now works
  • DDG - 2023-07-30: make it a standalone application and a package as well