Skip to main content

Convert images to hatched SVG files for Cricut pen plotters

Project description

hatchsvg

Turn raster images into pen-plotted hatched SVGs. Optimized for Cricut, Axidraw, and any pen plotter that reads SVG.

CI License: MIT Python 3.11+ PyPI

What's new in 2.0.0

  • Package renamed to hatchsvg (was png2svg). Matches the repo name. Install: pip install hatchsvg. Use: hatchsvg photo.jpg out.svg.
  • All v1.2.0 features still ship: --preview, --split-layers, --optimize-travel, --hatch-angles, plus 5 inline examples in --help.
  • Pure Python — no C compiler required. Works on every platform pip supports.

What it does

hatchsvg converts raster images (PNG, JPG, WebP, BMP, GIF, TIFF) into hatched SVG vector files. Each color in the image becomes a separate SVG layer, and each layer is filled with parallel hatch lines sized to match a physical marker set. The output is optimized for Cricut pen plotters and similar pen-plotting machines — it includes continuous serpentine paths, arc smoothing at row ends, and connected-component chaining to minimize pen lifts and ringing artifacts.

Quickstart

pip install hatchsvg
hatchsvg photo.jpg drawing.svg --preset portrait

That's it. Open drawing.svg in Inkscape, Cricut Design Space, or any vector editor. The output uses Inkscape-compatible layer names so each color is selectable individually.

No SVG file? Try it on the included sample:

hatchsvg examples/scene.png /tmp/scene.svg --preset fast

Why use hatchsvg?

Problem with naive "image → SVG" converters How hatchsvg solves it
Tracer output is dense, jittery, and pen plotter hates it. Uses scanline hatching at a configurable line step — predictable pen motion.
Pen lifts between every line segment cause visible artifacts on Cricut. Serpentine continuous paths chain rows together (zigzag motion).
Sharp 180° U-turns vibrate the pen carriage. Arc smoothing at row-end reversals (configurable radius).
Color matching to physical markers is hard. Built-in Crayola and Jot marker palettes; bring your own JSON.
Re-rendering with slightly different settings breaks reproducibility. --save-session writes a JSON snapshot; --use-session replays it bit-for-bit.

Comparison with similar tools

Tool Input Output Pen-plotter aware Marker palettes
hatchsvg Raster Hatched SVG (per-color layers) Yes — serpentine + arc smoothing + chain components Yes — Crayola, Jot, custom JSON
potrace Bitmap Smooth traced paths No — fills entire region No
vtracer Bitmap Smooth traced paths Partial No
inkscape --trace-bitmap Bitmap Smooth traced paths No No
stipplegen, penkit, etc. Raster Various pen-plotter art Yes (each is its own niche) No

hatchsvg is the right choice when you want stylized, low-pen-lift, marker-accurate output rather than a photo-faithful trace.

Presets

Presets are named combinations of parameters tuned for common use cases. Apply one with --preset NAME. You can still override any individual flag on top of the preset.

Preset Use case
portrait Photographic portraits, faces, soft gradients. Tight hatch + arc smoothing.
logo Brand marks, flat colors, clean edges. Separate outline for crisp boundaries.
line-art Pencil sketches, ink drawings, fine line illustrations. Low min-pixels preserves thin strokes.
photo Detailed photos, landscapes, complex gradients. High palette + fine hatch.
sketch Hand-drawn rough aesthetic. Wider hatch + visible U-turns.
fast Quick preview. Few colors, wide hatch, no optimization. Renders in seconds.
hatchsvg drawing.png out.svg --preset portrait
hatchsvg drawing.png out.svg --preset logo --max-palette 4  # override one flag

See hatchsvg --help for full preset descriptions.

Installation

pip install hatchsvg

Pure Python: hatchsvg has zero C extensions. No compiler needed, no potracer/pypotrace build failures. Works on Windows, macOS, Linux, ARM, anywhere Python 3.11+ runs.

Optional extras:

pip install hatchsvg[plot]      # progress bars (rich) + scipy for component chaining
pip install hatchsvg[palette]   # Streamlit app to build custom palettes from photos

Building a custom palette

If you have a set of physical markers (Crayola, Jot, Copic, Sharpie, whatever), you can take a photo and turn it into a hatchsvg palette JSON in ~30 seconds:

pip install hatchsvg[palette]
streamlit run scripts/palette_extractor.py

Upload a photo of your markers, edit the names, click Download palette JSON, and pass it to hatchsvg via --palette-file. You can also download a standalone HTML preview to keep alongside the JSON for visual reference:

# Generate the JSON via the Streamlit app, then:
python scripts/palette_preview.py my_palette.json
# Writes my_palette.html — open in any browser.

For development:

git clone https://github.com/Veedubin/hatchsvg
cd hatchsvg
python -m venv .venv
.venv/bin/pip install -e ".[dev,plot]"

CLI Reference

hatchsvg [OPTIONS] INPUT OUTPUT_SVG
Flag Default Description
--preset NAME (none) Apply a named preset (see table above).
--max-palette N 12 Maximum number of colors in the quantized output.
--line-step N 4 Spacing between hatch lines (pixels). Lower = denser.
--alpha-threshold N 10 Pixels with alpha below this are treated as transparent.
--min-pixels N 200 Minimum pixel count for a layer to be rendered.
--stroke-width N auto Stroke width for hatch lines (uses marker tip_width_mm if a palette is set).
--outline-width N auto Stroke width for outline paths.
--no-skip-background (off) Include the background color as a layer.
--white-medium (off) Use white as a medium color instead of skipping near-white.
--paper-white-soft N 20 Soft threshold for "paper white" detection.
--scale N 1.0 Scale factor for the output SVG.
--separate-outline (off) Generate outline paths as a separate SVG group.
--palette-file FILE (none) Path to a JSON marker palette.
--naming-mode {inkscape,flat} inkscape Layer naming convention.
--continuous-paths (off) Generate serpentine paths (huge pen-lift reduction).
--arc-radius N 0.0 Arc radius at U-turns (0 = disabled; try 3-5).
--save-session (off) Write a *.session.json for reproducibility.
--use-session FILE (none) Replay a previous session (overrides all flags).
--preview (off) Open output SVG in default viewer after render.
--split-layers (off) Write one SVG file per color layer.
--optimize-travel (off) Reorder layers to minimize pen travel distance.
--hatch-angles ANGLES (none) Comma-separated hatch angles per layer (degrees).
--progress (off) Show Rich progress bars (requires pip install hatchsvg[plot]).
--stats (off) Show processing statistics on completion.
--version Print the version and exit.

Cookbook

Basic conversion

hatchsvg photo.jpg drawing.svg

Recommended for Cricut pen plotters

The two flags that matter most:

hatchsvg photo.jpg drawing.svg --continuous-paths --arc-radius 5
  • --continuous-paths chains rows into a single zigzag, eliminating the thousands of micro-pen-lifts that cause "ringing" artifacts.
  • --arc-radius 5 smooths the 180° U-turns with arc commands so the pen carriage doesn't slam to a stop.

Use a bundled marker palette

hatchsvg photo.jpg drawing.svg --palette-file color_palettes/crayola_10ct_fine_line_classic.json

Bundled palettes: crayola_10ct_fine_line_classic.json and jot_20ct_washable_fineline.json.

Reproducible output

# First run: save the exact config used
hatchsvg photo.jpg drawing.svg --preset portrait --save-session

# Later: replay the exact same config
hatchsvg photo.jpg drawing2.svg --use-session drawing.svg.session.json

Multi-format input

hatchsvg scan.webp out.svg        # WebP
hatchsvg photo.bmp out.svg        # BMP
hatchsvg photo.tiff out.svg       # TIFF
hatchsvg anim.gif out.svg         # GIF (uses first frame)

Show processing stats

hatchsvg photo.jpg out.svg --progress --stats

Outputs a Rich table with image dimensions, color count, layer count, pen-lift reduction percentage, and estimated plot time savings.

Project Structure

hatchsvg/
├── src/
│   └── hatchsvg/
│       ├── __init__.py        # __version__
│       ├── __main__.py        # python -m hatchsvg
│       ├── core.py            # Algorithm (hatching, color matching, SVG emission)
│       ├── cli.py             # CLI + friendly error handling
│       └── presets.py         # Named presets (portrait, logo, line-art, photo, sketch, fast)
├── tests/
│   ├── unit/                  # 51 unit tests (segments, color, palette, session, hatch, presets)
│   ├── integration/           # 9 integration tests (golden file + CLI subprocess)
│   ├── fixtures/              # Golden SVG for regression
│   └── conftest.py
├── examples/                  # Sample input/output pairs (4 presets × 1 image)
├── color_palettes/            # Bundled Crayola + Jot palettes
├── .github/workflows/ci.yml   # CI: ruff + pytest on Linux+macOS × 3.11/3.12/3.13
├── pyproject.toml             # Build + project config
├── LICENSE                    # MIT
├── CHANGELOG.md               # Version history
├── REVIEW.md                  # Audit + release plan
├── PLAN.md                    # v1.0.0 implementation plan
└── README.md                  # This file

Tech Stack

  • Python 3.11+ (uses PEP 604 unions, tomllib, modern type hints)
  • NumPy — image array processing and color quantization
  • Pillow — image decoding (PNG, JPG, WebP, BMP, GIF, TIFF)
  • dataclassesRenderParams, LayerResult, StrokeStyle
  • Rich (optional) — progress bars and statistics table
  • scipy (optional) — connected component detection for pen-lift reduction

Development

# Run all tests with coverage
.venv/bin/pytest

# Lint
.venv/bin/ruff check src tests
.venv/bin/ruff format --check src tests

# Build a wheel for local testing
.venv/bin/python -m build

See PLAN.md for the v1.0.0 implementation plan and REVIEW.md for the comprehensive audit, feature roadmap, and 30-day release timeline.

Compatibility

  • Python: 3.11, 3.12, 3.13 (CI matrix covers all three on Linux + macOS)
  • Input formats: PNG, JPG, JPEG, WebP, BMP, GIF, TIFF, TIF
  • Output: SVG 1.1 with Inkscape-compatible layer names
  • Consumers: Inkscape, Cricut Design Space, Illustrator, browser preview

License

MIT — see LICENSE.

Credits

Algorithm extracted from the original hatchsvg.py script. Bundled marker palettes (Crayola, Jot) are trademarks of their respective owners and are included only as practical examples.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hatchsvg-2.2.5.tar.gz (171.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hatchsvg-2.2.5-py3-none-any.whl (33.3 kB view details)

Uploaded Python 3

File details

Details for the file hatchsvg-2.2.5.tar.gz.

File metadata

  • Download URL: hatchsvg-2.2.5.tar.gz
  • Upload date:
  • Size: 171.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hatchsvg-2.2.5.tar.gz
Algorithm Hash digest
SHA256 5fffa50144c34a99980f68624c2c9889e03b14cb36ada4636ac21e7473f279f3
MD5 0c50bdc46dd9295d3d16e2f25f020bc6
BLAKE2b-256 945929edcedfccceeb8408a94abfa1c539a85837ba68c95f71029c524b45bfda

See more details on using hashes here.

Provenance

The following attestation bundles were made for hatchsvg-2.2.5.tar.gz:

Publisher: workflow.yml on Veedubin/hatchsvg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hatchsvg-2.2.5-py3-none-any.whl.

File metadata

  • Download URL: hatchsvg-2.2.5-py3-none-any.whl
  • Upload date:
  • Size: 33.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hatchsvg-2.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 c42005ce12c4eb3a2a7ec6d3aaa4a22282eab3650ddba70c3ebd837bb0b7aa27
MD5 c8a996f3f5df7d2a75244188b2bc9f84
BLAKE2b-256 483f184f5e5bd59a0749042401d07c1cac318e21090cd35df2fe4d788121de60

See more details on using hashes here.

Provenance

The following attestation bundles were made for hatchsvg-2.2.5-py3-none-any.whl:

Publisher: workflow.yml on Veedubin/hatchsvg

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page