Skip to content

hkevin01/laser-cut-vectorizer

Repository files navigation

Laser Cut Vectorizer

Python Build Format Inputs

Laser Cut Vectorizer converts raster-like artwork into SVG contour paths that are easier to clean, organize, and prepare for laser cutting workflows. The tool focuses on predictable, scriptable preprocessing: thresholding, contour detection, geometric simplification, and physical-size-aware SVG output.

In practical terms, this repository exists to bridge the gap between "I have artwork" and "I have paths I can refine for fabrication." Instead of manually tracing every shape from scratch, you can generate a strong first-pass vector layer and spend your time on design intent, kerf compensation, and machine-specific setup.

Table of Contents

What This Project Is

This is a Python command-line utility that accepts a source file, runs a vectorization pipeline, and writes an SVG document made of stroke paths. Inputs can be JPEG/PNG style artwork or PDF pages. The first PDF page is rasterized before vector extraction so the same contour pipeline can be applied consistently.

The output is intentionally simple and fabrication-friendly: no filled shapes, no style complexity, and explicit physical dimensions in millimeters. This keeps the generated file compatible with common design and cutter-prep tools, while leaving creative edits to downstream software where visual QA is easier.

Why It Is Needed

Laser workflows often start with images that are not manufacturing-ready. A scan, silhouette photo, or design comp may look right but still lack clean vectors. Manual tracing can be slow and inconsistent, especially when iterating across many parts.

This project solves that bottleneck by giving you:

  • A repeatable conversion baseline you can run from scripts and CI
  • Parameterized contour cleanup (threshold, simplification, minimum area)
  • Optional millimeter sizing so downstream layout starts closer to target scale
  • A clear boundary between automated extraction and manual finishing

Note

The generated SVG is a strong starting point, not a guaranteed production artifact. Final inspection and cleanup remain part of the process for serious fabrication work.

Feature Overview

# Capability What It Does Why It Matters
1 Image + PDF input Accepts JPG, JPEG, PNG, BMP, TIFF, and PDF. Supports common sources from scanning, export, and design workflows.
2 PDF first-page rasterization Renders page 1 with configurable DPI before contouring. Keeps the pipeline consistent across raster and document sources.
3 Thresholding and inversion Binarizes grayscale artwork, with optional inversion. Handles both dark-on-light and light-on-dark source styles.
4 Contour simplification Uses geometric approximation to reduce point count. Creates cleaner paths that are easier to edit and cut.
5 Minimum contour area filtering Drops tiny regions likely to be noise. Reduces cleanup time and accidental micro-cuts.
6 Millimeter sizing Writes SVG width/height in mm from DPI or explicit overrides. Improves scale continuity from conversion to cutter setup.
7 Presets Applies common parameter bundles for known source conditions. Speeds up early tuning and promotes reproducible conversions.
8 Contact-sheet debug visual Composes grayscale, binary, contour, and SVG preview into one PNG. Provides quick side-by-side diagnostics at a glance.
9 Self-contained HTML report Embeds run images and parameter summary as inline data URLs. Makes run review and sharing easier without extra files.

GitHub markdown note: This table summarizes the conversion primitives and why each one exists in a fabrication pipeline.

Tech Stack

The codebase intentionally uses a small stack focused on deterministic processing rather than heavy ML-based tracing. Each dependency has a specific role in the architecture.

# Layer Package / Tool Role in System
1 Language runtime Python 3.11+ Core runtime and packaging baseline.
2 Image math + arrays NumPy Represents grayscale image matrices for processing.
3 Computer vision OpenCV (headless) Thresholding, contour detection, area tests, and simplification.
4 Raster/image I/O Pillow Loads raster formats and converts to grayscale arrays.
5 PDF rendering pypdfium2 Renders PDF page 1 to a raster image at selected DPI.
6 SVG emission xml.etree.ElementTree Serializes traced contours to stroke-only SVG paths.
7 Testing unittest Verifies raster and PDF conversion paths.
8 Task runner Makefile Provides install, validate, compile, and test commands.

GitHub markdown note: This table maps each dependency to one clearly scoped responsibility, which keeps the pipeline maintainable.

Architecture

The project is organized as a linear conversion pipeline with explicit boundaries between loading, processing, and serialization. This keeps behavior easier to reason about when tuning contour parameters.

flowchart LR
	A[CLI args] --> B[VectorizeOptions]
	B --> C[load_grayscale_image]
	C --> D[threshold + optional blur]
	D --> E[findContours]
	E --> F[area filter + simplify]
	F --> G[resolve physical size mm]
	G --> H[write_svg]
	H --> I[SVG output file]
Loading

The module-level architecture separates concerns so each part can evolve independently.

flowchart TD
	CLI[cli.py] --> MODELS[models.py]
	CLI --> VEC[vectorizer.py]
	VEC --> RASTER[raster.py]
	VEC --> SVG[svg_writer.py]
	TESTS[tests/test_vectorizer.py] --> CLI
	TESTS --> VEC
Loading

Debug-visual flow for tuning threshold and contour parameters:

sequenceDiagram
    participant User as CLI User
    participant CLI as cli.py
    participant V as vectorizer.py
    participant FS as Filesystem

    User->>CLI: run with --debug-dir
    CLI->>V: build VectorizeOptions
    V->>V: load grayscale and threshold to binary
    V->>V: detect contours
    V->>FS: write 01_grayscale.png
    V->>FS: write 02_binary.png
    V->>FS: write 03_contours.png
	V->>FS: write 04_svg_preview.png
	V->>FS: write 05_contact_sheet.png
    V->>FS: write final SVG
Loading

Failure path handling and user-visible outcomes:

flowchart TD
	A[Start conversion] --> B{Source format supported?}
	B -- no --> E1[Raise ValueError: Unsupported source format]
	B -- yes --> C{Threshold in 0..255?}
	C -- no --> E2[Raise ValueError: Threshold must be between 0 and 255]
	C -- yes --> D{Debug directory valid?}
	D -- no --> E3[Raise ValueError: Debug directory path exists and is not a directory]
	D -- yes --> F[Continue conversion and write output artifacts]
Loading

Install

Create and activate a virtual environment, then install in editable mode:

python -m venv .venv
source .venv/bin/activate
pip install -e .

Tip

Editable mode is useful during parameter tuning because code and documentation updates are immediately reflected without reinstalling the package each time.

Quick Start

Convert a JPEG to SVG:

python -m laser_cut_vectorizer input.jpg output.svg

Convert a PDF page to SVG with explicit contour constraints:

python -m laser_cut_vectorizer drawing.pdf output.svg --dpi 300 --simplify 0.01 --min-area 50

Invert thresholding for dark artwork on light background:

python -m laser_cut_vectorizer sketch.jpg output.svg --invert

Set physical width and preserve aspect ratio automatically:

python -m laser_cut_vectorizer panel.png panel.svg --width-mm 180

CLI Reference

All options are available through the CLI parser in the source package.

# Argument Type Default Purpose
1 source Path required Input file (JPG/PNG/PDF and related raster formats).
2 output Path required Destination SVG file path.
3 --preset choice None Preset profile: clean-logo, noisy-scan, photo-edge.
4 --dpi int 300 PDF render DPI and default physical size basis.
5 --threshold int preset/default Binary threshold from 0 to 255.
6 --invert flag false Inverts thresholding mode.
7 --blur-kernel int 0 Optional odd Gaussian kernel size.
8 --min-area float preset/default Minimum contour area to keep.
9 --simplify float preset/default Simplification ratio for contour approximation.
10 --width-mm float None Optional explicit output width.
11 --height-mm float None Optional explicit output height.
12 --debug-dir Path None Optional folder for intermediate PNG visuals.
13 --report flag false Writes an HTML report with embedded debug images.

GitHub markdown note: This table is a quick command-line map for scripting and repeatable conversion presets.

Parameter Tuning Guide

# Scenario Suggested Changes Why These Values Help
1 Noisy scan with speckles Raise --min-area to 50-200 and try --blur-kernel 3 Suppresses micro-contours caused by sensor/paper noise.
2 Overly jagged outlines Increase --simplify from 0.01 to 0.02 or 0.03 Reduces point density and smooths path complexity.
3 Missing thin strokes Lower --threshold and reduce --min-area Keeps lighter or thinner features from being dropped.
4 Foreground/background swapped Use --invert Switches contour polarity when source contrast direction is opposite.
5 Wrong physical size in downstream tool Set --width-mm or --height-mm explicitly Makes output dimensions deterministic regardless of import defaults.

GitHub markdown note: This table provides practical tuning defaults for common first-pass failures.

Preset Profiles

# Preset Threshold Simplify Min Area Intended Source
1 clean-logo 200 0.008 12 Flat, high-contrast logos and line graphics.
2 noisy-scan 165 0.020 90 Scans with paper texture or sensor noise.
3 photo-edge 140 0.030 140 Photo-derived silhouettes or complex edges.

GitHub markdown note: Presets are starting points. Explicit flags still override preset values when you need fine control.

Examples

Additional example commands are listed in examples/README.md. You can keep source assets in the examples folder and write outputs to the output folder for repeatable local experiments.

python -m laser_cut_vectorizer examples/source.jpg output/source.svg
python -m laser_cut_vectorizer examples/source.pdf output/source.svg --dpi 300

Use this checklist before importing into cutter software:

  • Confirm only intended contours were traced
  • Remove small artifacts and duplicate loops
  • Verify dimensions in millimeters
  • Assign stroke/layer semantics required by your cutter profile

Visual Debug Mode

Visual tuning is usually the fastest way to dial in thresholding, inversion, and minimum-area values. The debug mode writes intermediary images so you can inspect exactly where contour quality is gained or lost.

Run conversion with debug outputs enabled:

python -m laser_cut_vectorizer input.jpg output.svg --invert --debug-dir output/debug

The debug directory contains deterministic filenames in pipeline order:

# File Meaning Why It Helps
1 01_grayscale.png Input converted to grayscale. Confirms tonal contrast before thresholding.
2 02_binary.png Thresholded binary image. Shows whether foreground/background separation is correct.
3 03_contours.png Detected contours overlaid on source. Reveals noise, missed edges, and contour density.
4 04_svg_preview.png Rasterized preview of the simplified final vector paths. Shows what the final SVG geometry will look like before export review.
5 05_contact_sheet.png 2x2 comparison grid of pipeline stages. Enables quick side-by-side diagnostics in one image.

GitHub markdown note: This table maps each generated debug image to the exact tuning decision it supports.

Important

Debug artifacts are diagnostic snapshots. They are not manufacturing output, but they can significantly reduce trial-and-error when preparing difficult artwork.

Report Mode

Report mode writes a lightweight HTML file beside the output SVG. The report embeds all debug visuals as data URLs and includes a parameter table with resolved values, which means you can archive or share one HTML file without external image dependencies.

python -m laser_cut_vectorizer input.jpg output.svg --preset noisy-scan --invert --report

When --report is used without an explicit --debug-dir, the tool automatically writes artifacts to <output_stem>_artifacts and writes the HTML report to <output_stem>_report.html in the same output folder.

Note

Report mode is intended for inspection and traceability. It does not replace CAD cleanup or machine-specific cut validation.

Output Model

The generated SVG is a stroke-first geometry file intended for post-processing in vector tools. Width and height are written with millimeter units, while path coordinates are emitted from contour points in image space.

Important

The tool emits closed paths (Z command) with no fill and black stroke. This is deliberate because many cutter workflows begin by mapping strokes to operations.

Tip

If your machine software expects specific colors or layer names, apply those conventions after conversion in your vector editor template.

Quality and Validation

The repository includes scaffold checks, compilation checks, and unit tests.

make validate
make compile
make test

Validation responsibilities at a glance:

# Command What It Verifies Why It Is Useful
1 make validate Project scaffold and expected files. Prevents missing-structure regressions.
2 make compile Python bytecode compilation across src/tests/scripts. Catches syntax issues quickly.
3 make test Raster and PDF conversion behavior via unittest. Protects core conversion path with executable checks.

GitHub markdown note: This table explains what each quality gate catches so contributors can run the right command first.

Troubleshooting

PDF input fails or behaves unexpectedly

Ensure dependencies are installed in the active environment and that the PDF contains at least one page. The current implementation processes only the first page, so multi-page documents require separate runs.

SVG contains too many tiny paths

Raise --min-area and consider a small blur kernel (--blur-kernel 3) before thresholding. This combination usually removes speckle-driven contours.

Output size is different than expected in the cutter software

Some tools interpret unit metadata differently on import. Set --width-mm or --height-mm explicitly and verify document units in your editor before exporting machine-specific formats.

Warning

Extremely complex photographic images can generate many paths and require substantial manual cleanup. For best results, pre-process images for high contrast before vectorization.

Limitations

  • The converter traces visible contours, not artistic or semantic intent.
  • Multi-page PDFs are processed one page at a time.
  • Complex tonal photos can require heavy post-cleanup.
  • Machine-specific toolpath rules (kerf, lead-ins, operation color mapping) are intentionally out of scope.

Project Layout

# Path Responsibility
1 src/laser_cut_vectorizer/cli.py Parses CLI args and runs conversion.
2 src/laser_cut_vectorizer/models.py Defines options and result data models.
3 src/laser_cut_vectorizer/raster.py Loads raster formats and renders PDF page 1.
4 src/laser_cut_vectorizer/vectorizer.py Runs thresholding, contouring, filtering, and sizing.
5 src/laser_cut_vectorizer/svg_writer.py Writes stroke-only SVG output.
6 tests/test_vectorizer.py Covers JPG and PDF conversion flows.
7 docs/workflow.md Practical workflow notes for laser prep.

GitHub markdown note: This table is a contributor quick-map for where to implement changes in each layer.

Documentation Tips for Contributors

When extending this README, prefer longer explanatory paragraphs over one-line bullets for process-heavy topics. For fabrication projects, readers benefit from understanding not only what a command does, but why a specific parameter matters in production contexts.

When adding new capabilities, document all three dimensions:

  1. What the feature is.
  2. What problem it solves in a real workflow.
  3. What failure modes or trade-offs users should expect.

That style keeps docs useful for both quick-start users and maintainers making architecture-level changes.

About

Laser Cut Vectorizer converts raster-like artwork into SVG contour paths that are easier to clean, organize, and prepare for laser cutting workflows. The tool focuses on predictable, scriptable preprocessing: thresholding, contour detection, geometric simplification, and physical-size-aware SVG output.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors