feat(scripts): Potrace floor-plan vectorization spike (#299) #1663

Merged
lekss361 merged 2 commits from feat/plan-vectorization-spike-299 into main 2026-06-17 17:12:49 +00:00
Showing only changes of commit 838e8a9639 - Show all commits

View file

@ -93,9 +93,7 @@ def _require_binary(name: str) -> str:
path = shutil.which(name) path = shutil.which(name)
if path is None: if path is None:
logger.error("required binary %r not found on PATH", name) logger.error("required binary %r not found on PATH", name)
raise SystemExit( raise SystemExit(f"{name!r} not found — install it (e.g. `brew install {name}`) and retry")
f"{name!r} not found — install it (e.g. `brew install {name}`) and retry"
)
return path return path
@ -145,9 +143,13 @@ def svg_to_png(rsvg_bin: str, svg_path: Path, png_path: Path, *, width: int) ->
try: try:
subprocess.run( subprocess.run(
[ [
rsvg_bin, "-w", str(width), rsvg_bin,
"-w",
str(width),
"--background-color=white", "--background-color=white",
"-o", str(png_path), str(svg_path), "-o",
str(png_path),
str(svg_path),
], ],
check=True, check=True,
capture_output=True, capture_output=True,
@ -216,8 +218,10 @@ def summarise(results: list[VectorizeResult]) -> None:
print(f"max ratio : {max(ratios):.2f}x") print(f"max ratio : {max(ratios):.2f}x")
total_raster = sum(r.raster_bytes for r in results) total_raster = sum(r.raster_bytes for r in results)
total_svg = sum(r.svg_bytes for r in results) total_svg = sum(r.svg_bytes for r in results)
print(f"aggregate : {total_raster}B raster -> {total_svg}B svg " agg_ratio = total_raster / total_svg if total_svg else float("inf")
f"({total_raster / total_svg:.2f}x overall)") print(
f"aggregate : {total_raster}B raster -> {total_svg}B svg " f"({agg_ratio:.2f}x overall)"
)
def build_parser() -> argparse.ArgumentParser: def build_parser() -> argparse.ArgumentParser:
@ -225,27 +229,37 @@ def build_parser() -> argparse.ArgumentParser:
description="Spike: contour-vectorize floor-plan rasters (PNG/JPG → SVG) via Potrace.", description="Spike: contour-vectorize floor-plan rasters (PNG/JPG → SVG) via Potrace.",
) )
parser.add_argument( parser.add_argument(
"--in-dir", type=Path, required=True, "--in-dir",
type=Path,
required=True,
help="folder containing input rasters (PNG/JPG/...)", help="folder containing input rasters (PNG/JPG/...)",
) )
parser.add_argument( parser.add_argument(
"--out-dir", type=Path, required=True, "--out-dir",
type=Path,
required=True,
help="folder for output .pbm/.svg (and .rendered.png with --render-back)", help="folder for output .pbm/.svg (and .rendered.png with --render-back)",
) )
parser.add_argument( parser.add_argument(
"--threshold", type=int, default=128, "--threshold",
type=int,
default=128,
help="grayscale ink/paper cutoff 0-255 (default 128)", help="grayscale ink/paper cutoff 0-255 (default 128)",
) )
parser.add_argument( parser.add_argument(
"--invert", action="store_true", "--invert",
action="store_true",
help="treat light strokes on a dark field as ink", help="treat light strokes on a dark field as ink",
) )
parser.add_argument( parser.add_argument(
"--render-back", action="store_true", "--render-back",
action="store_true",
help="rasterise each SVG back to PNG via rsvg-convert for visual QA", help="rasterise each SVG back to PNG via rsvg-convert for visual QA",
) )
parser.add_argument( parser.add_argument(
"--render-width", type=int, default=900, "--render-width",
type=int,
default=900,
help="width in px for --render-back output (default 900)", help="width in px for --render-back output (default 900)",
) )
return parser return parser