aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgerbolyze/gerbolyze.py11
-rw-r--r--svg-flatten/Makefile3
-rw-r--r--svg-flatten/src/vec_core.cpp14
-rw-r--r--svg-flatten/svg_flatten_wasi/__init__.py52
4 files changed, 65 insertions, 15 deletions
diff --git a/gerbolyze/gerbolyze.py b/gerbolyze/gerbolyze.py
index d4b4ab5..53b10a4 100755
--- a/gerbolyze/gerbolyze.py
+++ b/gerbolyze/gerbolyze.py
@@ -624,17 +624,24 @@ def svg_to_gerber(infile, outfile,
candidates = [os.environ['SVG_FLATTEN']]
else:
- # By default, try three options:
+ # By default, try four options:
candidates = [
# somewhere in $PATH
'svg-flatten',
+ 'wasi-svg-flatten',
# in user-local pip installation
Path.home() / '.local' / 'bin' / 'svg-flatten',
- # next to our current python interpreter (e.g. in virtualenv
+ Path.home() / '.local' / 'bin' / 'wasi-svg-flatten',
+ # next to our current python interpreter (e.g. in virtualenv)
str(Path(sys.executable).parent / 'svg-flatten'),
+ str(Path(sys.executable).parent / 'wasi-svg-flatten'),
# next to this python source file in the development repo
str(Path(__file__).parent.parent / 'svg-flatten' / 'build' / 'svg-flatten') ]
+ # if SVG_FLATTEN envvar is set, try that first.
+ if 'SVG_FLATTEN' in os.environ:
+ candidates = [os.environ['SVG_FLATTEN'], *candidates]
+
args = [ '--format', ('gerber-outline' if outline_mode else 'gerber'),
'--precision', '6', # intermediate file, use higher than necessary precision
'--trace-space', str(trace_space) ]
diff --git a/svg-flatten/Makefile b/svg-flatten/Makefile
index 902489e..e8d4dad 100644
--- a/svg-flatten/Makefile
+++ b/svg-flatten/Makefile
@@ -76,6 +76,9 @@ BINARY := svg-flatten
all: $(BUILDDIR)/$(BINARY) $(BUILDDIR)/nopencv-test
+.PHONY: wasm
+wasm: $(BUILDDIR)/$(BINARY).wasm
+
$(CACHEDIR)/$(WASI_SDK):
mkdir -p $(dir $@)
cd $(dir $@); curl -L ${WASI_SDK_URL} | tar xzf -
diff --git a/svg-flatten/src/vec_core.cpp b/svg-flatten/src/vec_core.cpp
index 1b36887..39285f9 100644
--- a/svg-flatten/src/vec_core.cpp
+++ b/svg-flatten/src/vec_core.cpp
@@ -175,7 +175,7 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(RenderContext &ctx, const pug
double off_y = 0;
handle_aspect_ratio(node.attribute("preserveAspectRatio").value(),
scale_x, scale_y, off_x, off_y, orig_cols, orig_rows);
- cerr << "aspect " << scale_x << ", " << scale_y << " / " << off_x << ", " << off_y << endl;
+ //cerr << "aspect " << scale_x << ", " << scale_y << " / " << off_x << ", " << off_y << endl;
/* Adjust minimum feature size given in mm and translate into px document units in our local coordinate system. */
min_feature_size_px = img_ctx.mat().doc2phys_dist(min_feature_size_px);
@@ -255,10 +255,10 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(RenderContext &ctx, const pug
vector<double> adjusted_fill_factors;
adjusted_fill_factors.reserve(32); /* Vector to hold adjusted fill factors for each edge for gap filling */
/* now iterate over all voronoi cells again to generate each cell's scaled polygon halftone blob. */
- cerr << " generating cells " << diagram.numsites << endl;
+ //cerr << " generating cells " << diagram.numsites << endl;
for (int i=0; i<diagram.numsites; i++) {
const jcv_point center = sites[i].p;
- cerr << " site center " << center.x << ", " << center.y << endl;
+ //cerr << " site center " << center.x << ", " << center.y << endl;
double fill_factor_ours = fill_factors[sites[i].index];
/* Do not render halftone blobs that are too small */
@@ -297,7 +297,7 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(RenderContext &ctx, const pug
e = e->next;
}
- cerr << " blob: ";
+ //cerr << " blob: ";
/* Now, generate the actual halftone blob polygon */
ClipperLib::Path cell_path;
double last_fill_factor = adjusted_fill_factors.back();
@@ -312,7 +312,7 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(RenderContext &ctx, const pug
off_x + center.x + (e->pos[0].x - center.x) * fill_factor,
off_y + center.y + (e->pos[0].y - center.y) * fill_factor
});
- cerr << " - <" << p[0] << ", " << p[1] << ">";
+ //cerr << " - <" << p[0] << ", " << p[1] << ">";
cell_path.push_back({
(ClipperLib::cInt)round(p[0] * clipper_scale),
(ClipperLib::cInt)round(p[1] * clipper_scale)
@@ -324,7 +324,7 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(RenderContext &ctx, const pug
off_x + center.x + (e->pos[1].x - center.x) * fill_factor,
off_y + center.y + (e->pos[1].y - center.y) * fill_factor
});
- cerr << " - [" << p[0] << ", " << p[1] << "]";
+ //cerr << " - [" << p[0] << ", " << p[1] << "]";
cell_path.push_back({
(ClipperLib::cInt)round(p[0] * clipper_scale),
(ClipperLib::cInt)round(p[1] * clipper_scale)
@@ -334,7 +334,7 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(RenderContext &ctx, const pug
last_fill_factor = fill_factor;
e = e->next;
}
- cerr << endl;
+ //cerr << endl;
/* Now, clip the halftone blob generated above against the given clip path. We do this individually for each
* blob since this way is *much* faster than throwing a million blobs at once at poor clipper. */
diff --git a/svg-flatten/svg_flatten_wasi/__init__.py b/svg-flatten/svg_flatten_wasi/__init__.py
index fe21b5b..3b35b1f 100644
--- a/svg-flatten/svg_flatten_wasi/__init__.py
+++ b/svg-flatten/svg_flatten_wasi/__init__.py
@@ -1,13 +1,14 @@
import os
import sys
+import subprocess
import tempfile
import wasmtime
import platform
import click
-import pathlib
+from pathlib import Path
import hashlib
-import appdirs
import lzma
+import appdirs
from importlib import resources as importlib_resources
try:
importlib_resources.files # py3.9+ stdlib
@@ -36,7 +37,7 @@ def _run_wasm_app(wasm_filename, argv, cachedir="svg-flatten-wasi"):
module_path_digest = hashlib.sha256(__file__.encode()).hexdigest()
module_digest = hashlib.sha256(module_binary).hexdigest()
- cache_path = pathlib.Path(os.getenv("SVG_FLATTEN_WASI_CACHE_DIR", appdirs.user_cache_dir(cachedir)))
+ cache_path = Path(os.getenv("SVG_FLATTEN_WASI_CACHE_DIR", appdirs.user_cache_dir(cachedir)))
cache_path.mkdir(parents=True, exist_ok=True)
cache_filename = (cache_path / f'{wasm_filename}-{module_path_digest[:8]}-{module_digest[:16]}')
@@ -72,11 +73,50 @@ def _run_wasm_app(wasm_filename, argv, cachedir="svg-flatten-wasi"):
return trap.code
+def run_usvg(input_file, output_file, dpi=96):
+ args = ['--keep-named-groups', '--dpi', str(dpi), input_file, output_file]
+
+ # By default, try a number of options:
+ candidates = [
+ # somewhere in $PATH
+ 'usvg',
+ 'wasi-usvg',
+ # in user-local cargo installation
+ Path.home() / '.cargo' / 'bin' / 'usvg',
+ # wasi-usvg in user-local pip installation
+ Path.home() / '.local' / 'bin' / 'wasi-usvg',
+ # next to our current python interpreter (e.g. in virtualenv)
+ str(Path(sys.executable).parent / 'wasi-usvg')
+ ]
+
+ # if USVG envvar is set, try that first.
+ if 'USVG' in os.environ:
+ exec_candidates = [os.environ['USVG'], *exec_candidates]
+
+ for candidate in candidates:
+ try:
+ res = subprocess.run([candidate, *args], check=True)
+ print('used usvg:', candidate)
+ break
+ except FileNotFoundError:
+ continue
+ else:
+ raise SystemError('usvg executable not found')
+
+
@click.command(context_settings={'ignore_unknown_options': True})
+@click.option('--no-usvg', is_flag=True)
+@click.option('--usvg-dpi', type=int, default=96)
@click.argument('other_args', nargs=-1, type=click.UNPROCESSED)
@click.argument('input_file', type=click.Path(resolve_path=True, dir_okay=False))
@click.argument('output_file', type=click.Path(resolve_path=True, dir_okay=False, writable=True))
-def run_usvg(input_file, output_file, other_args):
+def run_svg_flatten(input_file, output_file, other_args, usvg_dpi, no_usvg):
+
+ with tempfile.NamedTemporaryFile() as f:
+ if not no_usvg:
+ run_usvg(input_file, f.name, dpi=usvg_dpi)
+ input_file = f.name
+
+ cmdline = ['svg-flatten', '--force-svg', '--no-usvg', *other_args, input_file, output_file]
+ sys.exit(_run_wasm_app("svg-flatten.wasm", cmdline))
- cmdline = ['svg-flatten', *other_args, input_file, output_file]
- sys.exit(_run_wasm_app("svg-flatten.wasm", cmdline))