253 lines
8.3 KiB
Markdown
253 lines
8.3 KiB
Markdown
# Kerf
|
||
|
||
Modular raster-to-vector conversion engine paired with a 2D sign and patch design canvas. Upload a raster image (PNG, JPEG, BMP), trace it into clean vector paths using Potrace or VTracer, and export as SVG or DXF — ready for CNC routers, vinyl cutters, laser engravers, and embroidery machines.
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
Once both services are healthy:
|
||
|
||
- **Web App** → [http://localhost:3000](http://localhost:3000)
|
||
- **Engine API** → [http://localhost:8000/engine/health](http://localhost:8000/engine/health)
|
||
- **Interactive API Docs** → [http://localhost:8000/docs](http://localhost:8000/docs)
|
||
|
||
Check service health:
|
||
|
||
```bash
|
||
docker compose ps
|
||
```
|
||
|
||
Tear down:
|
||
|
||
```bash
|
||
docker compose down
|
||
```
|
||
|
||
## Repository Structure
|
||
|
||
```
|
||
engine/ Kerf Engine — standalone Python/FastAPI vectorization API
|
||
api/ API route definitions
|
||
pipeline/ Preprocessing, vectorization, and post-processing stages
|
||
output/ SVG, DXF, and JSON output generators
|
||
presets/ Built-in preset configurations (JSON)
|
||
tests/ Engine test suite (pytest)
|
||
app/ Kerf App — React/TypeScript design canvas (Vite + Konva)
|
||
src/ Application source code
|
||
public/ Static assets including bundled fonts
|
||
docker/ Dockerfiles and nginx configuration
|
||
Dockerfile.engine Multi-stage build for the engine (Python 3.11)
|
||
Dockerfile.app Multi-stage build for the app (Node 22 → nginx 1.27)
|
||
nginx.conf SPA routing + /engine reverse-proxy
|
||
docker-compose.yml Full-stack orchestration with healthchecks
|
||
```
|
||
|
||
## Engine API Reference
|
||
|
||
The engine exposes four endpoints under the `/engine` prefix. All endpoints accept and return JSON unless otherwise noted.
|
||
|
||
### `GET /engine/health`
|
||
|
||
Healthcheck endpoint for container orchestration.
|
||
|
||
**Response:**
|
||
|
||
```json
|
||
{ "status": "ok" }
|
||
```
|
||
|
||
### `GET /engine/presets`
|
||
|
||
List all available presets and their parameter values.
|
||
|
||
**Response:**
|
||
|
||
```json
|
||
{
|
||
"presets": {
|
||
"sign": { "name": "sign", "description": "Metal signage, bold text cutouts", "..." : "..." },
|
||
"patch": { "name": "patch", "description": "Embroidered patches, fabric cutting", "..." : "..." }
|
||
}
|
||
}
|
||
```
|
||
|
||
### `POST /engine/trace`
|
||
|
||
Convert a raster image to vector output through the full preprocessing → vectorization → post-processing pipeline.
|
||
|
||
**Content-Type:** `multipart/form-data`
|
||
|
||
| Field | Type | Default | Description |
|
||
|-----------------|--------|------------|-------------|
|
||
| `file` | file | (required) | Raster image (PNG, JPEG, BMP) |
|
||
| `mode` | string | from preset | Vectorization engine: `potrace` or `vtracer` |
|
||
| `output_format` | string | `svg` | Output format: `svg`, `dxf`, or `json` |
|
||
| `preset` | string | `sign` | Preset name (see [Presets](#presets)) |
|
||
| `params` | string | `{}` | JSON string of parameter overrides |
|
||
|
||
**Example — trace with the sign preset:**
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/engine/trace \
|
||
-F file=@logo.png \
|
||
-F preset=sign \
|
||
-F output_format=svg
|
||
```
|
||
|
||
**Example — trace with custom parameters:**
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/engine/trace \
|
||
-F file=@photo.jpg \
|
||
-F preset=detailed \
|
||
-F mode=vtracer \
|
||
-F 'params={"filter_speckle": 4, "epsilon": 0.3}'
|
||
```
|
||
|
||
**Response (SVG/JSON formats):**
|
||
|
||
```json
|
||
{
|
||
"output": "<svg ...>...</svg>",
|
||
"format": "svg",
|
||
"metadata": {
|
||
"format": "svg",
|
||
"path_count": 12,
|
||
"node_count_total": 483,
|
||
"open_paths": 0,
|
||
"island_count": 2,
|
||
"warnings": [],
|
||
"processing_ms": 142.57
|
||
}
|
||
}
|
||
```
|
||
|
||
**Response (DXF format):** Raw DXF bytes with `Content-Type: application/dxf` and metadata in the `X-Kerf-Metadata` response header.
|
||
|
||
### `POST /engine/simplify`
|
||
|
||
Simplify an existing SVG using Ramer–Douglas–Peucker path simplification. Optionally export to DXF with unit and scale control.
|
||
|
||
**Content-Type:** `multipart/form-data`
|
||
|
||
| Field | Type | Default | Description |
|
||
|-----------------|--------|------------|-------------|
|
||
| `file` | file | (required) | SVG file to simplify |
|
||
| `epsilon` | float | `1.0` | RDP simplification tolerance (higher = fewer points) |
|
||
| `output_format` | string | `svg` | Output format: `svg`, `dxf`, or `json` |
|
||
| `units` | string | none | DXF unit metadata: `inches` or `mm` |
|
||
| `scale_factor` | float | `1.0` | DXF coordinate scale factor |
|
||
|
||
**Example — simplify and export to DXF in millimeters:**
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/engine/simplify \
|
||
-F file=@drawing.svg \
|
||
-F epsilon=2.0 \
|
||
-F output_format=dxf \
|
||
-F units=mm \
|
||
-F scale_factor=25.4
|
||
```
|
||
|
||
## Presets
|
||
|
||
Presets bundle tuned parameter sets for each pipeline stage — preprocessing, vectorization, and post-processing — optimized for specific use cases.
|
||
|
||
| Preset | Description | Mode | Epsilon | Notes |
|
||
|------------|------------------------------------|----------|---------|-------|
|
||
| `sign` | Metal signage, bold text cutouts | potrace | 2.5 | Aggressive denoising, auto-close enabled |
|
||
| `patch` | Embroidered patches, fabric cutting| potrace | 1.0 | Moderate smoothing, fine detail retention |
|
||
| `stencil` | Physical stencil cutting | potrace | 3.0 | Heavy simplification, fixed threshold at 128 |
|
||
| `detailed` | High-fidelity illustration work | potrace | 0.5 | Minimal smoothing, preserves fine curves |
|
||
| `custom` | All params exposed, no defaults | potrace | — | Pass all parameters explicitly via `params` |
|
||
|
||
Use the `params` field on `/engine/trace` to override any preset value. For example, to use the `sign` preset but switch to VTracer mode:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/engine/trace \
|
||
-F file=@image.png \
|
||
-F preset=sign \
|
||
-F 'params={"mode": "vtracer"}'
|
||
```
|
||
|
||
## Font System
|
||
|
||
The web app bundles three fonts for text-to-path conversion, enabling text elements to be converted to SVG outlines for cutting/engraving:
|
||
|
||
| Font | File |
|
||
|------------|-------------------------|
|
||
| Roboto | `Roboto-Regular.ttf` |
|
||
| Open Sans | `OpenSans-Regular.ttf` |
|
||
| Lato | `Lato-Regular.ttf` |
|
||
|
||
Fonts are parsed client-side using [opentype.js](https://opentype.js.org/) and converted to SVG path data with configurable font size and letter spacing. The conversion handles glyph positioning, coordinate system flipping, and path assembly — no server round-trip required.
|
||
|
||
## Engine Standalone Usage
|
||
|
||
The engine runs independently of the web app. Use it as a standalone API service or build just the engine Docker image:
|
||
|
||
**Docker (standalone):**
|
||
|
||
```bash
|
||
docker build -f docker/Dockerfile.engine -t kerf-engine .
|
||
docker run -p 8000:8000 kerf-engine
|
||
```
|
||
|
||
**Local development (Python):**
|
||
|
||
```bash
|
||
cd engine
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -e ".[dev]"
|
||
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
|
||
```
|
||
|
||
API docs are available at [http://localhost:8000/docs](http://localhost:8000/docs) (Swagger UI) and [http://localhost:8000/redoc](http://localhost:8000/redoc) (ReDoc).
|
||
|
||
## Development
|
||
|
||
### Engine (Python)
|
||
|
||
```bash
|
||
cd engine
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -e ".[dev]"
|
||
|
||
# Run the API server with auto-reload
|
||
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
|
||
|
||
# Run tests
|
||
pytest
|
||
```
|
||
|
||
System dependencies for pypotrace: `libpotrace-dev`, `libpotrace0`, `libagg-dev` (Debian/Ubuntu).
|
||
|
||
### App (React/TypeScript)
|
||
|
||
```bash
|
||
npm install
|
||
npm run dev --workspace=app
|
||
```
|
||
|
||
The Vite dev server proxies `/engine/*` requests to `http://localhost:8000` — start the engine first for full functionality.
|
||
|
||
### Full Stack (Docker Compose)
|
||
|
||
```bash
|
||
docker compose up --build
|
||
```
|
||
|
||
The app is served on port 3000 with nginx reverse-proxying `/engine/*` to the engine container.
|
||
|
||
## Known Limitations
|
||
|
||
- **Single-image processing** — the engine processes one image per request; batch endpoints are not yet available.
|
||
- **Binary vectorization only** — both Potrace and VTracer operate in binary (black/white) mode; color/multi-layer tracing is not supported.
|
||
- **No authentication** — the API is open; add a reverse proxy with auth for production deployments.
|
||
- **Font selection** — the app ships with three bundled fonts; custom font upload is not yet supported.
|
||
- **DXF fidelity** — DXF export covers basic polyline geometry; advanced CAD features (layers, blocks, hatches) are not included.
|