Skip to content
Snippets Groups Projects
app.py 7.11 KiB
Newer Older
gijs's avatar
gijs committed
from flask import Flask, Response, request, render_template
Doriane's avatar
Doriane committed
import subprocess
import os
import re
import sys
gijs's avatar
gijs committed
import tempfile
Doriane's avatar
Doriane committed
import io
import requests
gijs's avatar
gijs committed
from svg_to_hpgl import svgToHPGL
Doriane's avatar
Doriane committed

app = Flask(__name__)

title = 'Cobbled paths'

fonts_directory = 'db/'
possible_extensions = [".flf"]
etherpad = 'https://pad.constantvzw.org/p/'
prefix = 'cobbled-pad-'

# VARIABLES 4 CATALOGUE
# ------------------------------

output = {
    'stroke':  { 'ascii': ' | ' , 'fonts': [] },
    'script':  { 'ascii': ' _/' , 'fonts': [] },
    'block':   { 'ascii': '|_|' , 'fonts': [] },
    'outline': { 'ascii': '/ /' , 'fonts': [] },
    'effect':  { 'ascii': ': :' , 'fonts': [] },
    'pattern': { 'ascii': ')()' , 'fonts': [] },

    # 'fill': { 'ascii': '_/', 'fonts': {} },

    # 'directions': { 'ascii': '_/', 'fonts': {} },
    # '3d': { 'ascii': '_/', 'fonts': {} },

    # 'frame': { 'ascii': '_/', 'fonts': {} },
    # 'code': { 'ascii': '_/', 'fonts': {} },
}
databases = {
    'default': 'fonts made by the figlet developpers and given with the program, early 1993',
    'contributed': 'fonts made by figlet amateurs and submitted to the official figlet ftp, from before 1993 to 2005', 
    'jave': 'figlet font library of JavE (a free Ascii drawing Editor)',
}

# VARIABLES 4 REGEX
Doriane's avatar
Doriane committed
# ------------------------------

# all the character that svgbob understand
spec = [".", ",", "", "'", "`", "+", "*", "o", "O", "V", "\\-", "|", "~", "_", ":", "!", "<", ">", "v", "^", "/", "\\\\", '\\', '\\"', "(", ")", "=", "#"]
r_spec = "".join(spec)
r_nspec = "[^" + r_spec + "\€\$\s]"

# autofix regex
autofix = [
     
    # every arrowshead into lines
    [re.compile("[<{]"), "("],
    [re.compile("[>}L]"), ")"],
    [re.compile("[vV]"), "-"],
    [re.compile("[\\^]"), "-"],

    [";", ":"],
    ["7", "/"],

    [re.compile("[1Tlj\\[\\]]"), "|"],
    [re.compile("[Y]"), "+"],

    # every not in the spec --> block
    [re.compile(r_nspec), "#"],
]

# FUNCTIONS
# ------------------------------
Doriane's avatar
Doriane committed

def most_common(lst):
    return max(set(lst), key=lst.count)

def text2figlet(input, figfont):
    figlet = subprocess.run(["figlet", input, "-f", figfont, "-w", "160"], stdout = subprocess.PIPE, text=True)
    return figlet.stdout

def ascii2svg(ascii_input, weight):
    svgbob = subprocess.run(["svgbob_cli", '--stroke-width', weight], input = ascii_input, stdout = subprocess.PIPE, text=True)
    return svgbob.stdout

def ascii_autofix(ascii):
    for regex, replace in autofix:
        ascii = re.sub(regex, replace, ascii)
    return ascii

def autofix_indication(ascii):
    for regex, replace in autofix:
        # the two markers have to not appear in any regex
        ascii = re.sub(regex, "$" + replace + "", ascii)

    ascii = re.sub("[\$]", "<span class='fix'>", ascii)
    ascii = re.sub("[\€]", "</span>", ascii)
    return ascii


Doriane's avatar
Doriane committed
# ROUTES
# ------------------------------

#  _           _           
# (_)_ __   __| | _____  __
# | | '_ \ / _` |/ _ \ \/ /
# | | | | | (_| |  __/>  < 
# |_|_| |_|\__,_|\___/_/\_\
# 
# PRESENT THE TOOL

Doriane's avatar
Doriane committed
@app.route("/")
def index():

    return render_template(
        'index.html',
        title = title)

#      _                    
#   __| |_ __ __ ___      __
#  / _` | '__/ _` \ \ /\ / /
# | (_| | | | (_| |\ V  V / 
#  \__,_|_|  \__,_| \_/\_/  
# 
# ETHERPAD 2 SVGBOB INTERFACE
# one iframe for the etherpad
# another iframe to dump the generated svg

Doriane's avatar
Doriane committed
@app.route("/draw.html")
def draw():

    params = {
        'pad': request.args.get('p') or 'default',
        'weight': request.args.get('w') or '3',
    }
    params['pad-full'] = etherpad + prefix + params['pad']

    return render_template(
        'draw.html',
        title = title,
        params = params)

# this is the route of the iframe where the svg is generated and dumped

@app.route("/drawing/<id>")
def drawing(id):

    params = {
        'pad': id or 'default',
        'weight': request.args.get('w') or '3',
    }
    params['pad-full'] = etherpad + prefix + params['pad']

    # get pad content
    print('  getting ' + params['pad-full'])
    pad_export = requests.get(params['pad-full'] + '/export/txt')
    ascii_input = pad_export.text

    # to SVG
gijs's avatar
gijs committed
    svg = ascii2svg(ascii_input, params['weight'])

    return render_template(
        'drawing.html',
        title = title,
        params = params,
        svg = svg)

#            _        _                        
#   ___ __ _| |_ __ _| | ___   __ _ _   _  ___ 
#  / __/ _` | __/ _` | |/ _ \ / _` | | | |/ _ \
# | (_| (_| | || (_| | | (_) | (_| | |_| |  __/
#  \___\__,_|\__\__,_|_|\___/ \__, |\__,_|\___|
#                             |___/  
# 
# FIGLET 2 SVGBOB INTERACTIVE CATALOGUE
Doriane's avatar
Doriane committed

@app.route("/catalogue.html")
def catalogue():
    
    # text and weight as get parameter
    params = {
        'text': request.args.get('t') or 'Echoes',
        'weight': request.args.get('w') or '3',
    }

    # walk in the figlet font directory
    for root, dirs, files in os.walk(fonts_directory):
        for name in files:

            (basename, ext) = os.path.splitext(name)
            if  ext in possible_extensions:

                figfont = os.path.join(root, name)
                print(figfont)
Doriane's avatar
Doriane committed

                # get font category out of last folder
                catalogue = root.split('/')[-2]
                type = root.split('/')[-1]
                if type in output:
                
                    f = {}
                    output[type]['fonts'].append(f)
                    f['name'] = name
                    f['catalogue'] = catalogue
                    f['ascii'] = text2figlet(params['text'], figfont)
                    f['svg'] = ascii2svg(f['ascii'], params['weight'])
Doriane's avatar
Doriane committed
                    
                    # regex auto_fix
                    f['ascii_fix'] = ascii_autofix(f['ascii'])
Doriane's avatar
Doriane committed

                    if f['ascii'] != f['ascii_fix']:
                        f['autofix'] = True
                        f['ascii_fix_indication'] = autofix_indication(f['ascii_fix'])
                        f['svg_fix'] = ascii2svg(f['ascii_fix'], params['weight'])
Doriane's avatar
Doriane committed

    return render_template(
        'catalogue.html',
        title = title,
        databases = databases,
        output = output,
        params = params)


# ----------------------------------------------------------

gijs's avatar
gijs committed
def make_svg ():
    return ''

gijs's avatar
gijs committed
@app.route('/hpgl/<id>')
def hpgl (id):
    params = {
        'pad': id or 'default',
        'weight': request.args.get('w') or '3',
    }
    params['pad-full'] = etherpad + prefix + params['pad']

    # get pad content
    print('  getting ' + params['pad-full'])
    pad_export = requests.get(params['pad-full'] + '/export/txt')
    ascii_input = pad_export.text

    # to SVG
    svg = ascii2svg(ascii_input, params['weight'])

gijs's avatar
gijs committed
    # store as a temporary file
gijs's avatar
gijs committed
    (svg_file, svg_path) = tempfile.mkstemp('.svg')


    with open(svg_file, 'w') as svg_handle:
        svg_handle.write(svg)
gijs's avatar
gijs committed

    # transform to hpgl
    hpgl = svgToHPGL(svg_path)

    # remove tmp file
    os.remove(svg_path)

    r = Response(hpgl, mimetype='application/hpgl')
    r.headers.extend({
        'Content-Disposition': 'attachment; filename="cobbled-paths.hpgl"'
    })
    return r

Doriane's avatar
Doriane committed
if __name__ == '__main__':
	app.run(debug=True, host='0.0.0.0')