hatchsvg 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hatchsvg-2.0.0/.github/workflows/ci.yml +50 -0
- hatchsvg-2.0.0/.github/workflows/workflow.yml +75 -0
- hatchsvg-2.0.0/.gitignore +100 -0
- hatchsvg-2.0.0/Bluey-orig.png +0 -0
- hatchsvg-2.0.0/Bluey.png +0 -0
- hatchsvg-2.0.0/CHANGELOG.md +198 -0
- hatchsvg-2.0.0/LICENSE +21 -0
- hatchsvg-2.0.0/PKG-INFO +310 -0
- hatchsvg-2.0.0/README.md +274 -0
- hatchsvg-2.0.0/color_palettes/crayola_10ct_fine_line_classic.json +17 -0
- hatchsvg-2.0.0/color_palettes/jot_20ct_washable_fineline.json +27 -0
- hatchsvg-2.0.0/examples/README.md +50 -0
- hatchsvg-2.0.0/examples/scene.png +0 -0
- hatchsvg-2.0.0/examples/scene_fast.svg +6 -0
- hatchsvg-2.0.0/examples/scene_logo.svg +10 -0
- hatchsvg-2.0.0/examples/scene_portrait.svg +6 -0
- hatchsvg-2.0.0/examples/scene_sketch.svg +6 -0
- hatchsvg-2.0.0/notebooks/README.md +125 -0
- hatchsvg-2.0.0/notebooks/craft.ipynb +560 -0
- hatchsvg-2.0.0/notebooks/craft_executed.ipynb +835 -0
- hatchsvg-2.0.0/notebooks/explore.ipynb +345 -0
- hatchsvg-2.0.0/notebooks/explore_executed.ipynb +667 -0
- hatchsvg-2.0.0/notebooks/notebook_helpers.py +756 -0
- hatchsvg-2.0.0/notebooks/quickstart.ipynb +205 -0
- hatchsvg-2.0.0/notebooks/quickstart_executed.ipynb +406 -0
- hatchsvg-2.0.0/pyproject.toml +103 -0
- hatchsvg-2.0.0/scripts/build_notebooks.py +711 -0
- hatchsvg-2.0.0/scripts/png2svg_legacy.py +1328 -0
- hatchsvg-2.0.0/scripts/verify_notebooks.sh +90 -0
- hatchsvg-2.0.0/scripts/verify_notebooks_helpers.py +115 -0
- hatchsvg-2.0.0/src/hatchsvg/__init__.py +15 -0
- hatchsvg-2.0.0/src/hatchsvg/__main__.py +6 -0
- hatchsvg-2.0.0/src/hatchsvg/cli.py +411 -0
- hatchsvg-2.0.0/src/hatchsvg/core.py +1662 -0
- hatchsvg-2.0.0/src/hatchsvg/presets.py +114 -0
- hatchsvg-2.0.0/tests/__init__.py +0 -0
- hatchsvg-2.0.0/tests/conftest.py +59 -0
- hatchsvg-2.0.0/tests/fixtures/bluey_golden.svg +5 -0
- hatchsvg-2.0.0/tests/integration/__init__.py +0 -0
- hatchsvg-2.0.0/tests/integration/test_cli.py +387 -0
- hatchsvg-2.0.0/tests/integration/test_e2e.py +130 -0
- hatchsvg-2.0.0/tests/integration/test_notebook_helpers.py +190 -0
- hatchsvg-2.0.0/tests/integration/test_verify_notebook_helpers.py +272 -0
- hatchsvg-2.0.0/tests/unit/__init__.py +0 -0
- hatchsvg-2.0.0/tests/unit/test_color.py +54 -0
- hatchsvg-2.0.0/tests/unit/test_hatch.py +57 -0
- hatchsvg-2.0.0/tests/unit/test_input_formats.py +49 -0
- hatchsvg-2.0.0/tests/unit/test_optimize_layer_order.py +77 -0
- hatchsvg-2.0.0/tests/unit/test_palette.py +33 -0
- hatchsvg-2.0.0/tests/unit/test_preset_config.py +148 -0
- hatchsvg-2.0.0/tests/unit/test_presets.py +104 -0
- hatchsvg-2.0.0/tests/unit/test_render_layer.py +110 -0
- hatchsvg-2.0.0/tests/unit/test_sanitize_filename.py +47 -0
- hatchsvg-2.0.0/tests/unit/test_segments.py +31 -0
- hatchsvg-2.0.0/tests/unit/test_session.py +45 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: test (${{ matrix.os }}, Python ${{ matrix.python-version }})
|
|
12
|
+
runs-on: ${{ matrix.os }}
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, macos-latest]
|
|
17
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check out repository
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
cache: pip
|
|
28
|
+
cache-dependency-path: pyproject.toml
|
|
29
|
+
|
|
30
|
+
- name: Install package with dev and plot extras
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install --upgrade pip
|
|
33
|
+
pip install -e ".[dev,plot]"
|
|
34
|
+
|
|
35
|
+
- name: Lint with ruff
|
|
36
|
+
run: |
|
|
37
|
+
ruff check src tests
|
|
38
|
+
ruff format --check src tests
|
|
39
|
+
|
|
40
|
+
- name: Run tests with coverage
|
|
41
|
+
run: |
|
|
42
|
+
pytest --cov=png2svg --cov-report=xml --cov-report=term-missing
|
|
43
|
+
|
|
44
|
+
- name: Upload coverage to Codecov
|
|
45
|
+
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
|
|
46
|
+
uses: codecov/codecov-action@v4
|
|
47
|
+
with:
|
|
48
|
+
file: coverage.xml
|
|
49
|
+
flags: unittests
|
|
50
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Trusted publishing workflow for hatchsvg.
|
|
4
|
+
# PyPI was configured to trust this workflow via:
|
|
5
|
+
# Project: hatchsvg
|
|
6
|
+
# Repository: Veedubin/hatchsvg
|
|
7
|
+
# Workflow: workflow.yml
|
|
8
|
+
# Environment: pypi
|
|
9
|
+
#
|
|
10
|
+
# Trigger options:
|
|
11
|
+
# 1. workflow_dispatch: manual run from the Actions tab (useful for re-publishing
|
|
12
|
+
# a tag or publishing from a non-tag commit)
|
|
13
|
+
# 2. push tag v*: automatic publish on every v*.*.* tag push
|
|
14
|
+
#
|
|
15
|
+
# To publish a new release:
|
|
16
|
+
# - Update __version__ in src/hatchsvg/__init__.py
|
|
17
|
+
# - Commit, tag: git tag -a v2.1.0 -m "..." && git push origin v2.1.0
|
|
18
|
+
# - The tag push triggers this workflow automatically
|
|
19
|
+
# - Or trigger manually via the Actions tab for ad-hoc publishes
|
|
20
|
+
|
|
21
|
+
on:
|
|
22
|
+
workflow_dispatch:
|
|
23
|
+
push:
|
|
24
|
+
tags:
|
|
25
|
+
- "v*.*.*"
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
build:
|
|
29
|
+
name: Build sdist + wheel
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- name: Check out repository
|
|
33
|
+
uses: actions/checkout@v4
|
|
34
|
+
|
|
35
|
+
- name: Set up Python
|
|
36
|
+
uses: actions/setup-python@v5
|
|
37
|
+
with:
|
|
38
|
+
python-version: "3.12"
|
|
39
|
+
|
|
40
|
+
- name: Install build tooling
|
|
41
|
+
run: python -m pip install --upgrade build
|
|
42
|
+
|
|
43
|
+
- name: Build distributions
|
|
44
|
+
run: python -m build
|
|
45
|
+
|
|
46
|
+
- name: Check distributions
|
|
47
|
+
run: python -m pip install twine && twine check dist/*
|
|
48
|
+
|
|
49
|
+
- name: Upload build artifacts
|
|
50
|
+
uses: actions/upload-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
|
|
55
|
+
publish:
|
|
56
|
+
name: Publish to PyPI
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
needs: build
|
|
59
|
+
environment:
|
|
60
|
+
name: pypi
|
|
61
|
+
url: https://pypi.org/p/hatchsvg
|
|
62
|
+
permissions:
|
|
63
|
+
# OIDC token for PyPI trusted publishing
|
|
64
|
+
id-token: write
|
|
65
|
+
steps:
|
|
66
|
+
- name: Download build artifacts
|
|
67
|
+
uses: actions/download-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: dist
|
|
70
|
+
path: dist/
|
|
71
|
+
|
|
72
|
+
- name: Publish to PyPI
|
|
73
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
74
|
+
# No environment, no token — PyPI trusted publishing handles auth
|
|
75
|
+
# automatically via the GitHub OIDC token exchange.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
.Python
|
|
8
|
+
build/
|
|
9
|
+
develop-eggs/
|
|
10
|
+
dist/
|
|
11
|
+
downloads/
|
|
12
|
+
eggs/
|
|
13
|
+
.eggs/
|
|
14
|
+
lib/
|
|
15
|
+
lib64/
|
|
16
|
+
parts/
|
|
17
|
+
sdist/
|
|
18
|
+
var/
|
|
19
|
+
wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# Installer logs
|
|
25
|
+
pip-log.txt
|
|
26
|
+
pip-delete-this-directory.txt
|
|
27
|
+
|
|
28
|
+
# Unit test / coverage reports
|
|
29
|
+
htmlcov/
|
|
30
|
+
.tox/
|
|
31
|
+
.nox/
|
|
32
|
+
.coverage
|
|
33
|
+
.coverage.*
|
|
34
|
+
.cache
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
coverage.xml
|
|
37
|
+
*.cover
|
|
38
|
+
|
|
39
|
+
# uv lockfile (dev environment)
|
|
40
|
+
uv.lock
|
|
41
|
+
|
|
42
|
+
# ruff / mypy
|
|
43
|
+
.ruff_cache/
|
|
44
|
+
.mypy_cache/
|
|
45
|
+
|
|
46
|
+
# Environments
|
|
47
|
+
.env
|
|
48
|
+
.venv
|
|
49
|
+
env/
|
|
50
|
+
venv/
|
|
51
|
+
ENV/
|
|
52
|
+
env.bak/
|
|
53
|
+
venv.bak/
|
|
54
|
+
|
|
55
|
+
# IDEs
|
|
56
|
+
.idea/
|
|
57
|
+
.vscode/
|
|
58
|
+
*.swp
|
|
59
|
+
*.swo
|
|
60
|
+
.DS_Store
|
|
61
|
+
|
|
62
|
+
# png2svg-specific
|
|
63
|
+
*.session.json
|
|
64
|
+
!color_palettes/
|
|
65
|
+
memory_data/
|
|
66
|
+
|
|
67
|
+
# Boomerang plugin / session artifacts — these are tooling for the
|
|
68
|
+
# development environment that lives alongside this repo, NOT part
|
|
69
|
+
# of the png2svg project itself. They should never be committed to
|
|
70
|
+
# this repo. (If you want to track plugin behavior, use a separate
|
|
71
|
+
# repo for the plugin.)
|
|
72
|
+
.opencode/
|
|
73
|
+
AGENTS.md
|
|
74
|
+
PLAN.md
|
|
75
|
+
REVIEW.md
|
|
76
|
+
|
|
77
|
+
# AI assistant session documents — internal development notes that
|
|
78
|
+
# were committed in error before .gitignore patterns were added.
|
|
79
|
+
# The package, tests, and user-facing docs (README, CHANGELOG, LICENSE)
|
|
80
|
+
# are the only public artifacts that should ever ship on GitHub.
|
|
81
|
+
CONTEXT_png2svg.md
|
|
82
|
+
GUI_ARCHITECTURE.md
|
|
83
|
+
HANDOFF.md
|
|
84
|
+
ROADMAP.md
|
|
85
|
+
SETUP.md
|
|
86
|
+
TASKS.md
|
|
87
|
+
|
|
88
|
+
# AI session memory backup (when memini-ai MCP transport is down)
|
|
89
|
+
.session-memory/
|
|
90
|
+
|
|
91
|
+
# Notebook runtime outputs (created when users run the notebooks)
|
|
92
|
+
# Keep the *_executed.ipynb files (committed for reviewers) but
|
|
93
|
+
# exclude user-generated outputs that appear in the working tree
|
|
94
|
+
notebooks/my_*.svg
|
|
95
|
+
notebooks/my_*.json
|
|
96
|
+
notebooks/explore_output.svg
|
|
97
|
+
notebooks/explore_session.json
|
|
98
|
+
notebooks/craft_session.json
|
|
99
|
+
notebooks/batch_output/
|
|
100
|
+
notebooks/__pycache__/
|
|
Binary file
|
hatchsvg-2.0.0/Bluey.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [2.0.0] - 2026-06-17
|
|
9
|
+
|
|
10
|
+
### ⚠️ BREAKING CHANGE: rename `png2svg` → `hatchsvg`
|
|
11
|
+
|
|
12
|
+
The package has been renamed from `png2svg` to `hatchsvg` to match
|
|
13
|
+
the GitHub repository name (`github.com/Veedubin/hatchsvg`) and to
|
|
14
|
+
better describe the algorithm. **The repo was renamed to `hatchsvg`
|
|
15
|
+
in v1.1.1; this release brings the package in line.**
|
|
16
|
+
|
|
17
|
+
### Migration guide
|
|
18
|
+
|
|
19
|
+
| Old (v1.2.0) | New (v2.0.0) |
|
|
20
|
+
|--------------|--------------|
|
|
21
|
+
| `pip install png2svg` | `pip install hatchsvg` |
|
|
22
|
+
| `import png2svg` | `import hatchsvg` |
|
|
23
|
+
| `png2svg photo.jpg out.svg` | `hatchsvg photo.jpg out.svg` |
|
|
24
|
+
| `python -m png2svg` | `python -m hatchsvg` |
|
|
25
|
+
| `from png2svg.core import ...` | `from hatchsvg.core import ...` |
|
|
26
|
+
| `from png2svg.presets import ...` | `from hatchsvg.presets import ...` |
|
|
27
|
+
| `src/png2svg/` directory | `src/hatchsvg/` directory |
|
|
28
|
+
| Internal attribute `_png2svg_parser` | `_hatchsvg_parser` |
|
|
29
|
+
|
|
30
|
+
### Why a major bump (v2.0.0)?
|
|
31
|
+
|
|
32
|
+
Per [SemVer](https://semver.org/), any backward-incompatible change
|
|
33
|
+
to the public API requires a major version bump. The rename touches:
|
|
34
|
+
|
|
35
|
+
- **PyPI package name** (`pip install` no longer finds `png2svg`)
|
|
36
|
+
- **Import name** (`import png2svg` raises `ModuleNotFoundError`)
|
|
37
|
+
- **CLI command** (`png2svg` command no longer exists)
|
|
38
|
+
- **Module path** (`python -m png2svg` fails)
|
|
39
|
+
|
|
40
|
+
The CLI flags, file output, session JSON schema, palette JSON
|
|
41
|
+
schema, and Python API function signatures are unchanged.
|
|
42
|
+
|
|
43
|
+
### What did NOT change
|
|
44
|
+
|
|
45
|
+
- 114 tests still pass
|
|
46
|
+
- Golden file is byte-identical
|
|
47
|
+
- All v1.2.0 CLI flags work the same
|
|
48
|
+
- Output SVG format unchanged
|
|
49
|
+
|
|
50
|
+
### Migration shim
|
|
51
|
+
|
|
52
|
+
A compatibility shim is **not** shipped in v2.0.0. If you need to
|
|
53
|
+
keep `png2svg` working for existing scripts, add this to your
|
|
54
|
+
project's `requirements.txt`:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
hatchsvg>=2.0.0
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then in your code, change `import png2svg` to `import hatchsvg as png2svg`.
|
|
61
|
+
A standalone `png2svg` PyPI shim package that depends on `hatchsvg`
|
|
62
|
+
may be added in v2.1.0 if user demand warrants it.
|
|
63
|
+
|
|
64
|
+
## [1.2.0] - 2026-06-17
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- **`--preview`** — opens the output SVG in the default system viewer after render (uses stdlib `webbrowser`)
|
|
68
|
+
- **`--split-layers`** — writes one SVG file per color layer alongside the main output (`<stem>_<NN>_<color>.svg`)
|
|
69
|
+
- **`--optimize-travel`** — reorders layers using greedy nearest-neighbor to minimize pen-up travel distance
|
|
70
|
+
- **`--hatch-angles`** — comma-separated hatch rotation per layer in degrees (e.g. `--hatch-angles=0,45,90,135`)
|
|
71
|
+
- **`--help` examples** — 5 inline examples below the presets block in `hatchsvg --help` output
|
|
72
|
+
- **ViewBox normalization** — viewBox values are now always integer strings (no floats) for Cricut Design Space compatibility
|
|
73
|
+
- **`render_single_layer_svg()`** — new public function in `core.py` for per-layer SVG rendering (used by `--split-layers`)
|
|
74
|
+
- **`optimize_layer_order()`** — new public function in `core.py` for nearest-neighbor layer reordering (used by `--optimize-travel`)
|
|
75
|
+
- **Test count** — 88 → 98 (new tests for all 6 features)
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
- `RenderParams` gained two additive fields: `hatch_angles: Optional[List[float]]` and `hatch_angle: float` (both backward-compatible defaults)
|
|
79
|
+
- `process_image_to_hatched_svg()` gained an `optimize_travel: bool = False` parameter (backward-compatible)
|
|
80
|
+
|
|
81
|
+
## [1.1.1] - 2026-06-16
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- **`save_session` JSON serialization bug** (`src/hatchsvg/core.py:484`) — when
|
|
85
|
+
`--save-session` was used, the color_map contained numpy `uint32` scalars
|
|
86
|
+
from the quantization path and `json.dump` raised
|
|
87
|
+
`TypeError: Object of type uint32 is not JSON serializable`. The bug
|
|
88
|
+
was in the codebase since v1.0.0 but only ever triggered for users
|
|
89
|
+
who ran `--save-session`. The fix coerces each RGB value to a plain
|
|
90
|
+
Python `int` at the serialization boundary (RGB is conceptually 8-bit
|
|
91
|
+
so no precision is lost). Caught by a new test, not by a linter or
|
|
92
|
+
type-checker — see [Discipline note](#discipline-note).
|
|
93
|
+
- **Notebook byte-stability** (`scripts/build_notebooks.py`,
|
|
94
|
+
`scripts/verify_notebooks_helpers.py`) — three non-determinism sources
|
|
95
|
+
in the executed notebooks: (1) random `cell.id` values assigned by
|
|
96
|
+
`nbformat.v4.new_code_cell` — fixed with `_assign_stable_ids(nb, prefix)`
|
|
97
|
+
producing `f"{prefix}-cell-{i:02d}"` IDs; (2) wall-clock timing
|
|
98
|
+
prints (`print(f'Render took ...s')`) and timing fields in
|
|
99
|
+
`format_quantize_report` / `format_render_report` — removed; (3)
|
|
100
|
+
Jupyter kernel execution timestamps in
|
|
101
|
+
`cell.metadata.execution` (note: nested, not in
|
|
102
|
+
`output.metadata.execution`) — stripped post-execution. Three
|
|
103
|
+
consecutive `verify_notebooks.sh` runs now produce identical `sha256`.
|
|
104
|
+
|
|
105
|
+
### Removed
|
|
106
|
+
- **Duplicate `main()` in `src/hatchsvg/core.py`** (54 lines, lines
|
|
107
|
+
1405-1458 prior to removal) — never called, dead code. The real CLI
|
|
108
|
+
entry point is `hatchsvg.cli:main` per the `[project.scripts]`
|
|
109
|
+
table in `pyproject.toml`. Removed along with an unused
|
|
110
|
+
`import argparse` that was the only consumer.
|
|
111
|
+
- **Untracked planning/session documents** — `AGENTS.md`, `PLAN.md`,
|
|
112
|
+
`REVIEW.md`, `CONTEXT_hatchsvg.md`, `GUI_ARCHITECTURE.md`, `HANDOFF.md`,
|
|
113
|
+
`ROADMAP.md`, `SETUP.md`, `TASKS.md`, and `.opencode/` are now in
|
|
114
|
+
`.gitignore` and removed from tracking. These are internal AI
|
|
115
|
+
development notes that should never have been in a public repo.
|
|
116
|
+
The package, tests, and user-facing docs (`README`, `CHANGELOG`,
|
|
117
|
+
`LICENSE`) are the only public artifacts that ship on GitHub.
|
|
118
|
+
|
|
119
|
+
### Changed
|
|
120
|
+
- **Per-file ruff ignores** in `pyproject.toml` — added `notebooks/*.ipynb`
|
|
121
|
+
(ignores `I001`/`E402`/`F811` for Jupyter cell architecture) and
|
|
122
|
+
`notebooks/*_executed.ipynb` (ignores all rules for generated output).
|
|
123
|
+
`scripts/hatchsvg_legacy.py` now ignores `I001` in addition to its
|
|
124
|
+
existing rule groups. Resolves 50 lint errors without restructuring
|
|
125
|
+
notebook sources.
|
|
126
|
+
- **`scripts/verify_notebooks_helpers.py`** (new) — Python module
|
|
127
|
+
extracted from inline `python - <<PY` heredocs in
|
|
128
|
+
`verify_notebooks.sh`. Two functions, `check_for_errors(nb_path)`
|
|
129
|
+
and `strip_execution_timestamps(nb_path)`, plus a `__main__` CLI
|
|
130
|
+
(`check` and `strip` subcommands). Enables 15 new unit tests
|
|
131
|
+
for previously-untestable inline code.
|
|
132
|
+
- **Test count** — 70 → 88 tests; coverage 58% → 60%.
|
|
133
|
+
|
|
134
|
+
### Discipline note
|
|
135
|
+
|
|
136
|
+
The `save_session` JSON bug had been in the codebase since v1.0.0
|
|
137
|
+
and was *only* caught by writing a new test
|
|
138
|
+
(`test_cli_save_session_roundtrip`). Neither `ruff`, `ruff format`,
|
|
139
|
+
nor static type analysis flagged it. A linter will never find a
|
|
140
|
+
type that survives the boundary between numpy and stdlib. **Always
|
|
141
|
+
include a "test quality" agent in any code review pass, and always
|
|
142
|
+
run the new tests before declaring the review done.** The same
|
|
143
|
+
session also caught — and shipped the fix for — a subtle Jupyter
|
|
144
|
+
internals issue: kernel execution timestamps live in
|
|
145
|
+
`cell.metadata.execution` (a *nested* dict), not in
|
|
146
|
+
`output.metadata.execution`. The wrong-tree-level bug took two
|
|
147
|
+
debug iterations to diagnose.
|
|
148
|
+
|
|
149
|
+
## [1.1.0] - 2026-06-16
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
- **Three tutorial notebooks** in `notebooks/`:
|
|
153
|
+
- `quickstart.ipynb` — 5 cells, ~5 minutes, copy-paste-done path
|
|
154
|
+
- `explore.ipynb` — 6 cells, 4-stage walkthrough with explanations and 2a/2b/2c branches for color matching
|
|
155
|
+
- `craft.ipynb` — 5 cells, advanced usage: custom palettes, per-color remap, session save/load, batch processing, parameter deep-dive, comparison with adjacent tools
|
|
156
|
+
- **Shared `notebooks/notebook_helpers.py`** — thin wrappers around `hatchsvg.core` (load_image, quantize_image, match_to_palette, render_svg, snapshot_session, etc.). No magic — every function is a one-liner around a `core` call.
|
|
157
|
+
- **`notebooks/README.md`** — entry point that says "start with quickstart, then explore, then craft"
|
|
158
|
+
- **`scripts/build_notebooks.py`** — programmatic notebook builder (notebooks are reviewable as Python in PRs, not as JSON)
|
|
159
|
+
- **`scripts/verify_notebooks.sh`** — CI script that runs all 3 notebooks end-to-end via `nbconvert --execute` and checks for errors
|
|
160
|
+
- **10 smoke tests** in `tests/integration/test_notebook_helpers.py` covering helper imports, palette loading, quantization, session save/load
|
|
161
|
+
- **`[notebook]` extra** in `pyproject.toml`: `jupyter`, `ipykernel`, `matplotlib`, `nbformat`
|
|
162
|
+
- **Per-file ruff ignores** for `scripts/hatchsvg_legacy.py` (pre-existing bugs in the preserved legacy file)
|
|
163
|
+
- **Named presets** — `--preset portrait|logo|line-art|photo|sketch|fast` for common use cases; explicit CLI flags override preset values
|
|
164
|
+
- **Multi-format input** — CLI now accepts `.png`, `.jpg`, `.jpeg`, `.webp`, `.bmp`, `.gif`, `.tiff`, `.tif` (Pillow decodes; CLI validates extension with a friendly error)
|
|
165
|
+
- **New module `hatchsvg.presets`** — typed `PRESETS` dict with 6 hand-tuned presets, `list_presets()`, `get_preset()`, `apply_preset()`; ships with 6 hand-tuned presets
|
|
166
|
+
- **`get_run_configuration(args, preset_name=...)`** — preset-aware variant of the CLI config loader; explicit CLI flags still win over preset defaults
|
|
167
|
+
- **21 new tests** in `test_presets.py` (13 tests) and `test_preset_config.py` (8 tests); all preset fields validated against `RenderParams` dataclass
|
|
168
|
+
- **8 new CLI integration tests** in `tests/integration/test_cli.py` — full subprocess coverage of `--version`, `--help`, presets, multi-format input, error handling
|
|
169
|
+
- **`examples/` directory** with `scene.png` (procedural 200×200 input) and 4 output SVGs demonstrating each preset (fast/portrait/logo/sketch)
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
- **README rewrite** — new quickstart, comparison table vs potrace/vtracer/Inkscape, full CLI flag table, 5+ Cookbook recipes, expanded project structure
|
|
173
|
+
- **Test count** — 27 → 70 tests; coverage 49% → 58%; `presets.py` 100% covered, `notebook_helpers.py` ~60% covered
|
|
174
|
+
|
|
175
|
+
## [1.0.0] - 2026-06-15
|
|
176
|
+
|
|
177
|
+
### Added
|
|
178
|
+
- MIT license
|
|
179
|
+
- `pyproject.toml` with hatchling build system
|
|
180
|
+
- `--version` flag (`hatchsvg --version` → `hatchsvg 1.0.0`)
|
|
181
|
+
- Friendly error messages for `SystemExit` and palette loading failures
|
|
182
|
+
- Test suite: 8 unit tests + 1 end-to-end integration test with golden-file comparison
|
|
183
|
+
- GitHub Actions CI matrix (Linux + macOS, Python 3.11 / 3.12 / 3.13)
|
|
184
|
+
- `CHANGELOG.md` (this file)
|
|
185
|
+
- `.gitignore` with standard Python exclusions
|
|
186
|
+
|
|
187
|
+
### Changed
|
|
188
|
+
- Project restructured into `src/hatchsvg/` package layout
|
|
189
|
+
- `core.py` extracted from `hatchsvg.py` (algorithm preserved verbatim)
|
|
190
|
+
- CLI entry point moved to `hatchsvg.cli:main` (script `hatchsvg.py` retained as reference)
|
|
191
|
+
- Python requirement raised to 3.11+
|
|
192
|
+
|
|
193
|
+
### Fixed
|
|
194
|
+
- Cryptic `SystemExit` errors now show actionable advice
|
|
195
|
+
- Missing `--version` flag
|
|
196
|
+
|
|
197
|
+
[1.0.0]: https://github.com/Veedubin/hatchsvg/releases/tag/v1.0.0
|
|
198
|
+
[1.1.0]: https://github.com/Veedubin/hatchsvg/compare/v1.0.0...v1.1.0
|
hatchsvg-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 png2svg contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|