diff --git a/README.md b/README.md new file mode 100644 index 0000000..9593e38 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# cobbled paths + +from figlet2svgbob, creating contextual stroke font ready to plot. + +this is called _cobbled paths_ as a reminder of the permeability between the discrete and the continuous. +smooth connected paths are made out of an extremely restrictive grid, like multiple blocky stones form a tortuous path. + +## dependencies + +## font database + +* figlet offical ftp at + * `ours` the original default font made by the developper and given with the program, in early 1993 + * `contributed` fonts made by figlet amateur and submitted to the official figlet ftp, from before 1993 to 2005 + * `c64` are fonts that are only made of the `#` character, the most black ascii char, is if it was a pixel + * `bdffont` are fonts automatically made using bdf2figlet, converting [Glyph Bitmap Distribution Format](https://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format), often from adobe to `c64` like font. +* figlet font library of JavE (a free Ascii Editor), . those also include the figlet ftp native, they where sorted in order to keep only the uniques ones. + + +## todo + +* redo catalogue! + + +* iframe per category for less computing time +* left and right reload in draw & font +* input listen when opening page (for browser history remember) +* factorise JS +* factorise CSS +* show font-info file +* option to save as hpgl \ No newline at end of file diff --git a/__pycache__/hpgl_multipen_encoder.cpython-38.pyc b/__pycache__/hpgl_multipen_encoder.cpython-38.pyc new file mode 100644 index 0000000..c390ed8 Binary files /dev/null and b/__pycache__/hpgl_multipen_encoder.cpython-38.pyc differ diff --git a/__pycache__/hpgl_multipen_output.cpython-38.pyc b/__pycache__/hpgl_multipen_output.cpython-38.pyc new file mode 100644 index 0000000..94a2efa Binary files /dev/null and b/__pycache__/hpgl_multipen_output.cpython-38.pyc differ diff --git a/__pycache__/hpgl_output_adapted.cpython-38.pyc b/__pycache__/hpgl_output_adapted.cpython-38.pyc new file mode 100644 index 0000000..b340e0c Binary files /dev/null and b/__pycache__/hpgl_output_adapted.cpython-38.pyc differ diff --git a/__pycache__/svg_to_hpgl.cpython-38.pyc b/__pycache__/svg_to_hpgl.cpython-38.pyc new file mode 100644 index 0000000..be192cf Binary files /dev/null and b/__pycache__/svg_to_hpgl.cpython-38.pyc differ diff --git a/app.py b/app.py index 9d34b60..c5d1896 100644 --- a/app.py +++ b/app.py @@ -75,15 +75,28 @@ autofix = [ 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 text2figlet(text, figfont): + print('--- FIGLET SUBPROCESS') + figlet = subprocess.run(["figlet", text, "-f", figfont, "-w", "160"], stdout = subprocess.PIPE, stderr = subprocess.PIPE, text=True) + print(figlet.stdout) + + if figlet.returncode == 0: + answer = (True, figlet.stdout) + else: + answer = (False, figlet.stderr) + + return answer + +def ascii2svg(ascii, weight): + if ascii: + print('--- SVGBOB SUBPROCESS') + svgbob = subprocess.run(["svgbob_cli", '--stroke-width', weight], input = ascii, stdout = subprocess.PIPE, text=True) + return svgbob.stdout + else: + return "ERROR: etherpad request failed" def ascii_autofix(ascii): + print('--- REGEX AUTOFIX') for regex, replace in autofix: ascii = re.sub(regex, replace, ascii) return ascii @@ -92,11 +105,29 @@ 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("[\$]", "", ascii) ascii = re.sub("[\€]", "", ascii) return ascii +def get_pad(url): + # get pad content + print('--- ETHERPAD REQUEST') + print(url) + pad_export = requests.get(url + '/export/txt') + if pad_export.status_code == requests.codes.ok: + answer = (True, pad_export.text) + else: + answer = (False, "ERROR: etherpad request failed") + return answer + +def make_figfont(ascii): + print('--- MAKE TEMP FIGFONT') + (figfont_file, figfont_path) = tempfile.mkstemp(suffix='.flf') + print(figfont_path) + with open(figfont_path, 'w') as figfont_file: + figfont_file.write(ascii) + return figfont_path + # ROUTES # ------------------------------ @@ -151,13 +182,12 @@ def drawing(id): } 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']) + pad_answer = get_pad(params['pad-full']) + if pad_answer[0]: + ascii = pad_answer[1] + svg = ascii2svg(ascii, params['weight']) + else: + svg = pad_answer[1] return render_template( 'drawing.html', @@ -178,7 +208,7 @@ def drawing(id): def font(): params = { - 'text': request.args.get('t') or 'Cobbled Paths', + 'text': request.args.get('t') or 'the quick brown fox jumps over the lazy dog', 'pad': request.args.get('p') or 'standard', 'weight': request.args.get('w') or '3', } @@ -193,30 +223,29 @@ def font(): def writing(id): params = { - 'text': request.args.get('t') or 'Cobbled Paths', + 'text': request.args.get('t') or 'the quick brown fox jumps over the lazy dog', 'pad': id or 'standard', '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 + pad_answer = get_pad(params['pad-full']) + # TODO: only create new file if content of pad changed # store as a temporary file - print('--- saving figfont as temp ---') - (figfont_file, figfont_path) = tempfile.mkstemp(suffix='.flf') - print(figfont_path) - with open(figfont_path, 'w') as figfont_file: - figfont_file.write(ascii_input) - - print('--- opening the figfont ---') - ascii = text2figlet(params['text'], figfont_path) - print(ascii) - print('--- rendering to svg ---') - svg = ascii2svg(ascii, params['weight']) + if pad_answer[0]: + ascii = pad_answer[1] + figfont = make_figfont(ascii) + figlet_answer = text2figlet(params['text'], figfont) + if figlet_answer[0]: + ascii = figlet_answer[1] + svg = ascii2svg(figlet_answer[1], params['weight']) + else: + ascii = svg = figlet_answer[1] + + else: + ascii = svg = pad_answer[1] return render_template( 'writing.html', @@ -234,51 +263,51 @@ def writing(id): # # FIGLET 2 SVGBOB INTERACTIVE CATALOGUE -@app.route("/catalogue.html") -def 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: +# # 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']) +# 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']) +# # 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']) +# 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) +# return render_template( +# 'catalogue.html', +# title = title, +# databases = databases, +# output = output, +# params = params) # _ _ _ @@ -302,10 +331,10 @@ def hpgl (id): # get pad content print(' getting ' + params['pad-full']) pad_export = requests.get(params['pad-full'] + '/export/txt') - ascii_input = pad_export.text + ascii = pad_export.text # to SVG - svg = ascii2svg(ascii_input, params['weight']) + svg = ascii2svg(ascii, params['weight']) # store as a temporary file (svg_file, svg_path) = tempfile.mkstemp() diff --git a/hpgl_output_adapted.py b/hpgl_output_adapted.py index 688e169..7e694f7 100644 --- a/hpgl_output_adapted.py +++ b/hpgl_output_adapted.py @@ -19,8 +19,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from __future__ import print_function +import sys sys.path.append('/usr/share/inkscape/extensions') +sys.path.append('/snap/inkscape/10555/share/inkscape/extensions') import inkex from inkex.localization import inkex_gettext as _ @@ -70,6 +72,7 @@ class HpglOutputAdapted(inkex.OutputExtension): ) def save(self, stream): + print('start') self.options.debug = False # get hpgl data if len(self.svg.xpath("//svg:use|//svg:flowRoot|//svg:text")) > 0: @@ -79,6 +82,9 @@ class HpglOutputAdapted(inkex.OutputExtension): hpgl = encoder.getHpgl() except hpgl_encoder.NoPathError: raise inkex.AbortExtension(_("No convertible objects were found")) + + print('middle') + # convert raw HPGL to HPGL hpgl_init = "IN" # if self.options.force > 0: @@ -88,7 +94,9 @@ class HpglOutputAdapted(inkex.OutputExtension): hpgl = hpgl_init + hpgl + ";SP0;PU0,0;IN; " # Make it available externally self.hpgl = hpgl - stream.write(hpgl.encode("utf-8")) + # stream.write(hpgl.encode("utf-8")) + + print('end') if __name__ == "__main__": diff --git a/static/css/interface.css b/static/css/interface.css index 72a86b2..d278818 100644 --- a/static/css/interface.css +++ b/static/css/interface.css @@ -1,11 +1,13 @@ :root{ --bar-h: 3rem; + --c-link: blue; + --c-back: whitesmoke; + --c-default: black; --c-contributed: palegreen; --c-jave: mediumpurple; - --c-back: whitesmoke; } .default{ --c: var(--c-default); @@ -24,28 +26,13 @@ body{ line-height: 1.45; } a{ - color: currentColor; + color: var(--c-link); } a:hover{ font-weight: bold; } - -ul.special{ - display: flex; - gap: 1rem; - justify-content: center; - align-items: baseline; -} -.special a{ - display: block; - border: 1px solid black; - padding: 2rem 3rem; - border-radius: 2rem; - text-decoration: none; -} -ul.classic{ - list-style: initial; - padding: 0 1rem; +p{ + margin: 0.5rem 0; } /* BAR @@ -62,25 +49,14 @@ body.draw{ nav ul, .controls{ box-sizing: border-box; - height: var(--bar-h); position: fixed; width: 100%; z-index: 999; - gap: 1rem; display: flex; align-items: center; - border-bottom: 1px solid black; } nav ul{ top: 0; - background: black; - color: white; -} -.controls{ - top: var(--bar-h); - background-color: var(--c-back); - border-bottom: 1px solid black; - padding: 1rem 2rem; } nav ul li{ flex-grow: 1; @@ -89,16 +65,32 @@ nav ul li:not(:last-child){ border-right: 1px solid var(--c-back); } nav ul a{ - padding: 1rem 2rem; + color: white; + padding: 0 2rem; display: flex; align-items: center; justify-content: center; text-decoration: none; + height: var(--bar-h); + background-color: black; + box-sizing: border-box; +} +nav ul a.active{ + background-color: var(--c-link); } /* CONTROLS ================================================= */ +.controls{ + gap: 0.5rem; + top: var(--bar-h); + background-color: var(--c-back); + border-bottom: 1px solid black; + padding: 0rem 2rem; + height: var(--bar-h); +} + h1,h2{ font-weight: bold; } @@ -127,6 +119,14 @@ label{ padding: 1rem 2rem; border-bottom: 1px solid black; } +.two-columns{ + display: flex; + flex-wrap: wrap; + gap: var(--bar-h); +} +.two-columns > *{ + flex: 1 1 0%; +} .legend::before{ content: ''; @@ -267,13 +267,7 @@ span.fix{ fill: red !important; } -/* font info */ -.info-label{ - border-bottom: solid mediumblue 3px; -} - /* body class checkboxes */ - .font div.fix{ visibility: hidden; } @@ -286,30 +280,53 @@ body.check-fix .font div.fix{ body.check-text .svgbob text{ visibility: visible; } -/* .fix{ - visibility: hidden; -} -body.check-fix .fix{ - visibility: visible; -} */ /* TITLE ================================================= */ .title.font{ - padding: 1rem 2rem; + padding: 3rem 2rem; + gap: 1rem var(--bar-h); + grid-template-columns: repeat(2, calc(50% - calc(var(--bar-h) / 2))); } .title .f-ascii{ margin-left: auto; padding: 0; background: initial; + grid-row: auto; } .title .f-svg{ + grid-row: auto; margin-right: auto; padding: 0; background: initial; } +.title .special{ + grid-column: 1 / -1; + grid-row: 2 / span 1; +} +ul.special{ + display: flex; + gap: 1rem; + justify-content: center; + align-items: baseline; +} +.special a{ + display: block; + border: 1px solid currentColor; + padding: 2rem 3rem; + border-radius: 2rem; + text-decoration: none; +} +ul.classic{ + list-style: initial; + padding: 0 1rem; + margin: 0.5rem 0; +} + +/* DRAW + ================================================= */ .draw .font{ height: calc(100vh - var(--bar-h) * 2); @@ -336,4 +353,23 @@ body.check-fix .fix{ width: 100%; height: 100%; display: block; +} + +.figfont{ + grid-template-columns: 32rem 1fr; +} + +.reload::after{ + content: 'reload'; + position: absolute; + inset: 0; + background-color: rgba(0,0,205,0.2); + z-index: 999; + pointer-events: none; + color: white; + display: flex; + justify-content: center; + align-items: center; + font-weight: bold; + } \ No newline at end of file diff --git a/svg_to_hpgl.py b/svg_to_hpgl.py index 0a3acf3..9b1930d 100644 --- a/svg_to_hpgl.py +++ b/svg_to_hpgl.py @@ -3,7 +3,7 @@ from hpgl_output_adapted import HpglOutputAdapted def svgToHPGL (path, speed=1, penCount=8, force=2): e = HpglOutputAdapted() - e.affect([ + e.run([ '--orientation', '0', '--force', '0', '--overcut', '0', @@ -12,7 +12,6 @@ def svgToHPGL (path, speed=1, penCount=8, force=2): '--toolOffset', '0', '--autoAlign', 'false', '--speed', str(speed), - '--penCount', str(penCount), '--force', str(force), path], False) diff --git a/templates/base.html b/templates/base.html index e4ddc5b..19b91b2 100644 --- a/templates/base.html +++ b/templates/base.html @@ -24,10 +24,10 @@ diff --git a/templates/font.html b/templates/font.html index 540ce82..6a943d8 100644 --- a/templates/font.html +++ b/templates/font.html @@ -13,89 +13,118 @@ - + + + + - - - -
+
+ + {% endblock %} diff --git a/templates/index.html b/templates/index.html index 83773f4..7ec3f73 100644 --- a/templates/index.html +++ b/templates/index.html @@ -12,252 +12,12 @@ -____- \\ / \\/ \\/ \\ \\ / \\/
- - - - - - - - - - - - - - - - - - - - - ' - . - . - . - - .' - . - . - ` - :' - . - - . - ' - ` - - . - . - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ {% include 'logo.svg' %} -
-
-
+
+

Cobbled paths

+

+ It is a web interface that brings multiple tools together, to allow experimental and direct collaboration on + pen-plotted drawings by making Ascii art. +

It makes a way from the blocky discontinuity of Ascii drawings, to the smoothness of bezier curves, @@ -279,9 +44,8 @@ Like cobbled paths, it is a reminder of the permeability between the discrete and the continuous, and how regular stones can form tortuous paths.

-
- -
+
+

Handfull links

+
{% endblock %} diff --git a/templates/logo.svg b/templates/logo.svg new file mode 100644 index 0000000..ef2ec18 --- /dev/null +++ b/templates/logo.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + ' + . + . + . + + .' + . + . + ` + :' + . + + . + ' + ` + + . + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/writing.html b/templates/writing.html index bd602ed..46aa591 100644 --- a/templates/writing.html +++ b/templates/writing.html @@ -41,6 +41,9 @@ font-size: 1rem; } + .f-svg svg{ + overflow: visible; + }