diff --git a/Dockerfile b/Dockerfile index 394a641..4b33d19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,8 +15,8 @@ RUN apt-get update \ && apt-get -y install \ fonts-roboto \ inkscape \ + mupdf-tools \ openscad \ - pstoedit \ python3 \ python3-pip \ && rm -rf /var/lib/apt/lists diff --git a/Pipfile b/Pipfile index 8b558ac..d6e6c7e 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,7 @@ verify_ssl = true pyppeteer = "*" quart = "*" hypercorn = "*" +lxml = "*" [requires] python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock index e2baf20..ea746e3 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "eba051b6315cc8b820efd1c0944fa7890e84072ce4dfdae1392a0e6cacd845d2" + "sha256": "42bcdc44919fe8d57ed1adf7edb582d36a65fcec2a9ccaadfdb2e507bd8c0e9b" }, "pipfile-spec": 6, "requires": { @@ -93,6 +93,39 @@ ], "version": "==2.11.2" }, + "lxml": { + "hashes": [ + "sha256:06d4e0bbb1d62e38ae6118406d7cdb4693a3fa34ee3762238bcb96c9e36a93cd", + "sha256:0701f7965903a1c3f6f09328c1278ac0eee8f56f244e66af79cb224b7ef3801c", + "sha256:1f2c4ec372bf1c4a2c7e4bb20845e8bcf8050365189d86806bad1e3ae473d081", + "sha256:4235bc124fdcf611d02047d7034164897ade13046bda967768836629bc62784f", + "sha256:5828c7f3e615f3975d48f40d4fe66e8a7b25f16b5e5705ffe1d22e43fb1f6261", + "sha256:585c0869f75577ac7a8ff38d08f7aac9033da2c41c11352ebf86a04652758b7a", + "sha256:5d467ce9c5d35b3bcc7172c06320dddb275fea6ac2037f72f0a4d7472035cea9", + "sha256:63dbc21efd7e822c11d5ddbedbbb08cd11a41e0032e382a0fd59b0b08e405a3a", + "sha256:7bc1b221e7867f2e7ff1933165c0cec7153dce93d0cdba6554b42a8beb687bdb", + "sha256:8620ce80f50d023d414183bf90cc2576c2837b88e00bea3f33ad2630133bbb60", + "sha256:8a0ebda56ebca1a83eb2d1ac266649b80af8dd4b4a3502b2c1e09ac2f88fe128", + "sha256:90ed0e36455a81b25b7034038e40880189169c308a3df360861ad74da7b68c1a", + "sha256:95e67224815ef86924fbc2b71a9dbd1f7262384bca4bc4793645794ac4200717", + "sha256:afdb34b715daf814d1abea0317b6d672476b498472f1e5aacbadc34ebbc26e89", + "sha256:b4b2c63cc7963aedd08a5f5a454c9f67251b1ac9e22fd9d72836206c42dc2a72", + "sha256:d068f55bda3c2c3fcaec24bd083d9e2eede32c583faf084d6e4b9daaea77dde8", + "sha256:d5b3c4b7edd2e770375a01139be11307f04341ec709cf724e0f26ebb1eef12c3", + "sha256:deadf4df349d1dcd7b2853a2c8796593cc346600726eff680ed8ed11812382a7", + "sha256:df533af6f88080419c5a604d0d63b2c33b1c0c4409aba7d0cb6de305147ea8c8", + "sha256:e4aa948eb15018a657702fee0b9db47e908491c64d36b4a90f59a64741516e77", + "sha256:e5d842c73e4ef6ed8c1bd77806bf84a7cb535f9c0cf9b2c74d02ebda310070e1", + "sha256:ebec08091a22c2be870890913bdadd86fcd8e9f0f22bcb398abd3af914690c15", + "sha256:edc15fcfd77395e24543be48871c251f38132bb834d9fdfdad756adb6ea37679", + "sha256:f2b74784ed7e0bc2d02bd53e48ad6ba523c9b36c194260b7a5045071abbb1012", + "sha256:fa071559f14bd1e92077b1b5f6c22cf09756c6de7139370249eb372854ce51e6", + "sha256:fd52e796fee7171c4361d441796b64df1acfceb51f29e545e812f16d023c4bbc", + "sha256:fe976a0f1ef09b3638778024ab9fb8cde3118f203364212c198f71341c0715ca" + ], + "index": "pypi", + "version": "==4.5.0" + }, "markupsafe": { "hashes": [ "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", diff --git a/namensschild.scad.j2 b/namensschild.scad.j2 index caba645..026fb64 100644 --- a/namensschild.scad.j2 +++ b/namensschild.scad.j2 @@ -1,28 +1,22 @@ $fn=64; //$fn=32; -length = 50/3; +depth = 50/3; width = 50; -name_length = 40/3; name_width = 40; height = 2; height_plate = 1; module name_file() { - translate([(width-name_width)/2, (length-name_length)/2, 0]) { - difference() { - hull() { - resize([name_width, name_length, 0]) import("{{ name}}.dxf"); - } - resize([name_width, name_length, 0]) import("{{ name }}.dxf"); - } + translate([width/2, depth/2, 0]) { + import("{{ name }}.svg", center=true); } } module box(height) { hull() { for(x=[0, width]) { - for(y=[0, length]) { + for(y=[0, depth]) { translate([x, y, 0]) linear_extrude(height) circle(r=1); } } @@ -33,12 +27,12 @@ difference() { union() { difference() { box(height); - translate([1.5, 1.5, height_plate]) resize([width-1, length-1, height-height_plate]) box(height-height_plate); + translate([1.5, 1.5, height_plate]) resize([width-1, depth-1, height-height_plate]) box(height-height_plate); } linear_extrude(height) { name_file(); } } - translate([width-2.5, length-2.5, 0]) linear_extrude(height_plate) circle(r=1.9); + translate([width-2.5, depth-2.5, 0]) linear_extrude(height_plate) circle(r=1.9); } diff --git a/server.py b/server.py index 86c88a6..ad09346 100755 --- a/server.py +++ b/server.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from jinja2 import Template +from lxml import etree from pyppeteer import launch from quart import Quart, request, render_template, url_for, redirect from subprocess import run @@ -22,6 +23,34 @@ async def gen_pdf(name): await browser.close() +def gen_svg(name): + # OpenSCAD only supports a small subset of SVG (namely no clips, transforms + # and uses). Experiments lead to the result that chaining some conversions + # removes all those. + run_check( + ["inkscape", "-T", "-E", f"static/{name}.eps", f"static/{name}.pdf",] + ) + run_check( + ["inkscape", "-T", "-A", f"static/{name}.pdf", f"static/{name}.eps",] + ) + run_check(["mutool", "convert", "-o", f"static/{name}.svg", f"static/{name}.pdf"]) + + # for some reason mutool exports to {name}1 instead onf {name}… + tree = etree.parse(f"static/{name}1.svg") + root = tree.getroot() + # background + del root[0][0][0] + tree.write(f"static/{name}.svg") + + +def gen_stl(name): + with open("namensschild.scad.j2", "r") as f: + template = Template(f.read()) + with open(f"static/{name}.scad", "w") as f: + f.write(template.render(name=name)) + run_check(["openscad", "-o", f"static/{name}.stl", f"static/{name}.scad"]) + + @app.route("/") async def index(): return await render_template("index.html.j2") @@ -31,29 +60,8 @@ async def index(): async def generate(): name = request.args["name"] await gen_pdf(name) - run_check( - ["inkscape", "-T", "-E", f"static/{name}.eps", f"static/{name}.pdf",] - ) - run_check( - [ - "pstoedit", - "-q", - "-flat", - "0.0001", - "-dt", - "-f", - "dxf: -polyaslines -mm", - f"static/{name}.eps", - f"static/{name}.dxf", - ] - ) - - with open("namensschild.scad.j2", "r") as f: - template = Template(f.read()) - with open(f"static/{name}.scad", "w") as f: - f.write(template.render(name=name)) - run_check(["openscad", "-o", f"static/{name}.stl", f"static/{name}.scad"]) - + gen_svg(name) + gen_stl(name) return redirect(url_for("static", filename=f"{name}.stl"), code=302)