tools.cobbled-paths/app.py
2024-03-28 10:42:47 +01:00

283 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from flask import Flask, Response, request, render_template
import subprocess
import os
import re
import sys
import tempfile
import io
import requests
from svg_to_hpgl import svgToHPGL
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
# ------------------------------
# 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
# ------------------------------
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
# ROUTES
# ------------------------------
# _ _
# (_)_ __ __| | _____ __
# | | '_ \ / _` |/ _ \ \/ /
# | | | | | (_| | __/> <
# |_|_| |_|\__,_|\___/_/\_\
#
# PRESENT THE TOOL
@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
@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
svg = ascii2svg(ascii_input, params['weight'])
return render_template(
'drawing.html',
title = title,
params = params,
svg = svg)
@app.route("/font.html")
def font():
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(
'font.html',
title = title,
params = params)
# _ _
# ___ __ _| |_ __ _| | ___ __ _ _ _ ___
# / __/ _` | __/ _` | |/ _ \ / _` | | | |/ _ \
# | (_| (_| | || (_| | | (_) | (_| | |_| | __/
# \___\__,_|\__\__,_|_|\___/ \__, |\__,_|\___|
# |___/
#
# FIGLET 2 SVGBOB INTERACTIVE CATALOGUE
@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)
# 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'])
# regex auto_fix
f['ascii_fix'] = ascii_autofix(f['ascii'])
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'])
return render_template(
'catalogue.html',
title = title,
databases = databases,
output = output,
params = params)
# _ _
# ___ __ _| |_ __ _| | ___ __ _ _ _ ___
# / __/ _` | __/ _` | |/ _ \ / _` | | | |/ _ \
# | (_| (_| | || (_| | | (_) | (_| | |_| | __/
# \___\__,_|\__\__,_|_|\___/ \__, |\__,_|\___|
# |___/
#
# FIGLET 2 SVGBOB INTERACTIVE CATALOGUE
@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'])
# store as a temporary file
(svg_file, svg_path) = tempfile.mkstemp()
print(svg_path)
with open(svg_path, 'w') as svg_file:
svg_file.write(svg)
# 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
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')