Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions scripts/contact_sheet_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
"""Tweet contact-sheet registry for the 201+ hand-drawn style gallery.

G-category sheets are 4x4 (CAPACITY=16) contact sheets named
``G_{start:03}-{end:03}.png`` under ``images/``; the final sheet may be
incomplete. The active-sheet bookkeeping lives in
``handdraw-style-prompter/references/contact_sheet_state.json``.

This module was previously missing from the published repository. The
implementation is reconstructed from the contracts enforced by
``handdraw-style-prompter/scripts/validate_library.py``.
"""
from __future__ import annotations

import re
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
IMAGES = ROOT / "images"
STATE_FILE = ROOT / "handdraw-style-prompter" / "references" / "contact_sheet_state.json"

# 4x4 tile grid per contact sheet.
CAPACITY = 16

SHEET = re.compile(r"^G_(\d{3})(?:-(\d{3}))?\.png$")


def parse_sheet(path: Path) -> tuple[int, int] | None:
"""Return (start, end) style numbers encoded in a G-sheet filename.

A bare ``G_201.png`` counts as a single-style sheet (start == end).
Non-matching names return ``None`` so callers can skip them.
"""
match = SHEET.match(Path(path).name)
if not match:
return None
start = int(match.group(1))
end = int(match.group(2)) if match.group(2) else start
if end < start:
return None
return start, end


def sheet_path(start: int, end: int) -> Path:
"""Canonical path for the sheet covering styles ``start``–``end``."""
if start == end:
return IMAGES / f"G_{start:03}.png"
return IMAGES / f"G_{start:03}-{end:03}.png"
54 changes: 54 additions & 0 deletions scripts/style_asset_paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""Numbered style asset path helpers (single source of truth for layout).

Assets live in 200-number buckets under ``images/individual/``:

- ``001-200/001.png`` … ``401-600/xxx.png`` — per-style single images
- ``001-200/048_grid.jpg`` — optional four-panel grid,
same bucket as the matching single image; takes priority as a
generation reference when present.

This module was previously missing from the published repository. The
implementation is reconstructed from the contracts enforced by
``handdraw-style-prompter/scripts/validate_library.py``.
"""
from __future__ import annotations

from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
INDIVIDUAL = ROOT / "images" / "individual"
BUCKET_SIZE = 200


def _number(value: int | str) -> int:
try:
number = int(value)
except (TypeError, ValueError):
raise ValueError(f"Style number must be an integer, got {value!r}")
if number < 1:
raise ValueError(f"Style number must be >= 1, got {number}")
return number


def bucket_name(value: int | str) -> str:
"""Return the 200-style bucket directory name, e.g. 1 -> '001-200'."""
number = _number(value)
start = (number - 1) // BUCKET_SIZE * BUCKET_SIZE + 1
return f"{start:03}-{start + BUCKET_SIZE - 1:03}"


def bucket_dir(value: int | str) -> Path:
return INDIVIDUAL / bucket_name(value)


def single_path(value: int | str) -> Path:
"""Path to the numbered single image, e.g. 48 -> .../001-200/048.png."""
number = _number(value)
return bucket_dir(number) / f"{number:03}.png"


def grid_path(value: int | str) -> Path:
"""Path to the four-panel grid image, e.g. 217 -> .../201-400/217_grid.jpg."""
number = _number(value)
return bucket_dir(number) / f"{number:03}_grid.jpg"