chore: fork setup — tidy ignores, untrack runtime state, add AGENTS.md
- Ignore .venv/, .posit/, and .scanslicer/ (runtime state) - Untrack .scanslicer/ defaults/presets JSON files - Add AGENTS.md project guide for LLM-assisted work
This commit is contained in:
parent
af7656145e
commit
047ea60fa5
4 changed files with 125 additions and 24 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,6 +3,9 @@
|
||||||
/.idea/
|
/.idea/
|
||||||
/out/
|
/out/
|
||||||
/venv/
|
/venv/
|
||||||
|
.venv/
|
||||||
|
.posit/
|
||||||
|
.scanslicer/
|
||||||
/__pycache__/
|
/__pycache__/
|
||||||
/scanslicer/__pycache__/
|
/scanslicer/__pycache__/
|
||||||
/scanslicer.egg-info/
|
/scanslicer.egg-info/
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"aspect_ratio_max": 600,
|
|
||||||
"aspect_ratio_min": 100,
|
|
||||||
"bbox_fill_thresh": 4,
|
|
||||||
"bbox_max_size": 50,
|
|
||||||
"bbox_min_size": 8,
|
|
||||||
"border_ignore": 0,
|
|
||||||
"bw_adaptive_c": 2,
|
|
||||||
"bw_gauss": 0,
|
|
||||||
"bw_method": 0,
|
|
||||||
"bw_thresh": 210,
|
|
||||||
"canny_high": 150,
|
|
||||||
"canny_low": 50,
|
|
||||||
"clahe_clip": 0,
|
|
||||||
"contour_approx_pct": 0,
|
|
||||||
"detect_pipeline": 0,
|
|
||||||
"dilate_kernel": 14,
|
|
||||||
"expected_count": 0,
|
|
||||||
"gaussian": 0,
|
|
||||||
"invert_mode": 0,
|
|
||||||
"iou_merge_thresh": 3,
|
|
||||||
"morph_op": 3
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
{}
|
|
||||||
122
AGENTS.md
Normal file
122
AGENTS.md
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
# ScanSlicer (fork) — Project Guide
|
||||||
|
|
||||||
|
Purpose of this file: give any LLM working in this repo enough context to be
|
||||||
|
effective without re-reading everything. Keep it current as the code changes.
|
||||||
|
|
||||||
|
## What this project is
|
||||||
|
|
||||||
|
ScanSlicer is a desktop Qt application (Python/PySide6) that detects multiple
|
||||||
|
photos in a flatbed scan image, lets the user correct each box manually, then
|
||||||
|
exports perspective-corrected crops. Inspired by
|
||||||
|
[PhotoSlicer](https://github.com/francescovannini/photoslicer) (Francesco
|
||||||
|
Vannini). Runs on Linux over Wayland or X11.
|
||||||
|
|
||||||
|
This repo is a **local fork** of
|
||||||
|
[macrodev8/ScanSlicer](https://github.com/macrodev8/ScanSlicer) (upstream owner
|
||||||
|
inactive). License: GNU GPL v3 (must be preserved). Attribution: keep upstream
|
||||||
|
credit and the "inspired by PhotoSlicer" note.
|
||||||
|
|
||||||
|
## Goals of this fork
|
||||||
|
|
||||||
|
1. Fix a mirrored-export orientation bug and add an explicit left/right
|
||||||
|
orientation workflow (see below). This is the primary patch.
|
||||||
|
2. Keep the app usable on the maintainer's own photo scans; afterwards only
|
||||||
|
minimal maintenance is expected.
|
||||||
|
3. Push to the maintainer's Forgejo instance at `code.dgerdesmann.de` (no
|
||||||
|
GitHub fork). Keep licensing, attribution, and repository description proper.
|
||||||
|
|
||||||
|
The maintainer is primarily an R user and new to Python/Git. Changes should be
|
||||||
|
small, self-checked, clean, and secure; do not assume the maintainer can vet
|
||||||
|
Python code.
|
||||||
|
|
||||||
|
## The orientation bug (primary work item)
|
||||||
|
|
||||||
|
- Exported slices can come out mirrored (left/right swapped).
|
||||||
|
- Manual workaround: drag-switch the two corners of the top edge so the red
|
||||||
|
edge (edge 0) becomes the true top.
|
||||||
|
- Problem: `squarize()` and `reset_rotation()` re-run `normalize_top_left()`,
|
||||||
|
which re-derives "top" from geometry and silently overwrites the manual fix.
|
||||||
|
|
||||||
|
Desired outcome:
|
||||||
|
|
||||||
|
1. A visual indication of left vs. right edges/corners (in addition to the
|
||||||
|
existing red top edge).
|
||||||
|
2. A "swap left/right" button for the active slice.
|
||||||
|
3. The corrected orientation must persist through `squarize()` /
|
||||||
|
`reset_rotation()`.
|
||||||
|
|
||||||
|
## Key implementation facts
|
||||||
|
|
||||||
|
- `PhotoSlice.bbox` is a 4×2 numpy array in the order
|
||||||
|
`[top-left, top-right, bottom-right, bottom-left]`.
|
||||||
|
- `PhotoSlice.normalize_top_left()` (in `slices.py`) picks a top-left corner and
|
||||||
|
resolves winding so edge 0→1 is the "most horizontal top" edge. This is the
|
||||||
|
source of the ambiguity.
|
||||||
|
- `PhotoSlice.squarize()` and `reset_rotation()` both call
|
||||||
|
`normalize_top_left()` at the end, discarding any manual orientation.
|
||||||
|
- `Autoslicer.save_slice()` (in `autoslicer.py`) builds the perspective
|
||||||
|
transform assuming the `[TL,TR,BR,BL]` order; mirroring arises upstream of
|
||||||
|
this from a wrongly "normalized" quad.
|
||||||
|
- Edge 0 is drawn red in `CanvasRenderMixin.paintEvent()` (`canvas_render.py`).
|
||||||
|
|
||||||
|
A persistent orientation flag on `PhotoSlice` (respected by
|
||||||
|
`normalize_top_left`/`squarize`/`reset_rotation`) plus a swap action is the
|
||||||
|
likely shape of the fix. Do not change the `[TL,TR,BR,BL]` contract of
|
||||||
|
`save_slice` without updating every consumer.
|
||||||
|
|
||||||
|
## Repository structure
|
||||||
|
|
||||||
|
```
|
||||||
|
scanslicer/ application source (package)
|
||||||
|
entry.py CLI parsing, Wayland/X11 backend selection
|
||||||
|
main.py QtScanSlicer main window, theme, app bootstrap
|
||||||
|
controller*.py UI action handlers (status, canvas, detection,
|
||||||
|
image I/O, params)
|
||||||
|
ui_builders*.py widget construction (controls, preview, shared)
|
||||||
|
canvas*.py interactive canvas (interaction/render/state mixins)
|
||||||
|
slices.py PhotoSlice geometry model + polys_iou
|
||||||
|
autoslicer.py detection/export engine wrapper (save_slice)
|
||||||
|
autoslicer_detection.py detection pipelines, contour→box extraction
|
||||||
|
autoslicer_feedback.py auto-tune profiles, scoring, feedback persistence
|
||||||
|
params.py parameter model, defaults, presets
|
||||||
|
packaging/appimage/ AppImage recipe + build scripts (preferred deploy)
|
||||||
|
Dockerfile container runtime image
|
||||||
|
docker-compose.yml GUI container wiring
|
||||||
|
pyproject.toml package metadata + dependencies (uv.lock pinned)
|
||||||
|
docs/ user-guide, architecture, parameters, autotune,
|
||||||
|
runtime-config, appimage, development
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture in brief
|
||||||
|
|
||||||
|
- `QtScanSlicer` (`main.py`) is a `QMainWindow` composed from UI builder mixins
|
||||||
|
and controller mixins.
|
||||||
|
- `QtSlicingCanvas` (`canvas.py`) = interaction + render + state mixins; holds
|
||||||
|
the image, zoom/pan state, and the list of `PhotoSlice` objects.
|
||||||
|
- Background work (detection, auto-tune) runs on a single-worker `QThreadPool`;
|
||||||
|
results are delivered back to the UI via Qt signals.
|
||||||
|
- Export flow: `save_all()` (`controller_image_io.py`) loops over locked slices
|
||||||
|
and calls `Autoslicer.save_slice(bbox, path, params)` for each.
|
||||||
|
|
||||||
|
## Run / build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv sync --frozen
|
||||||
|
uv run scanslicer /path/to/scans # or: python -m scanslicer
|
||||||
|
```
|
||||||
|
|
||||||
|
- AppImage (preferred): `bash packaging/appimage/build-appimage.sh`
|
||||||
|
- Docker: `docker compose up --build`
|
||||||
|
- Dependencies (from `pyproject.toml`): PySide6, opencv-python, numpy, Pillow.
|
||||||
|
- Python >= 3.10; dev env is Python 3.12 in `.venv`.
|
||||||
|
|
||||||
|
## Config / persistence
|
||||||
|
|
||||||
|
Runtime files live in `~/.config/scanslicer/` (or `$XDG_CONFIG_HOME/scanslicer/`)
|
||||||
|
by default: `defaults.json`, `presets.json`, `autotune-feedback.json`,
|
||||||
|
`status.log`. Paths are overridable via `SCANSLICER_*_PATH` env vars. In the
|
||||||
|
Docker setup these land in `./.scanslicer/` on the host.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- No automated test suite exists; validate changes by running the app on sample scans (startup, detection, save, auto-tune).
|
||||||
Loading…
Add table
Add a link
Reference in a new issue