| 16 | |
| 17 | |
| 18 | def parse_args() -> argparse.Namespace: |
| 19 | parser = argparse.ArgumentParser( |
| 20 | description=( |
| 21 | "Extract one horizontal strip into fixed-size frames using a shared " |
| 22 | "global scale and bottom-center alignment." |
| 23 | ) |
| 24 | ) |
| 25 | parser.add_argument("--input", required=True, help="Path to the raw strip image.") |
| 26 | parser.add_argument("--out-dir", required=True, help="Output directory for frames.") |
| 27 | parser.add_argument( |
| 28 | "--frames", |
| 29 | type=int, |
| 30 | required=True, |
| 31 | help="Number of horizontal frames in the strip.", |
| 32 | ) |
| 33 | parser.add_argument( |
| 34 | "--frame-size", |
| 35 | type=int, |
| 36 | default=64, |
| 37 | help="Output square frame size in pixels. Default: 64.", |
| 38 | ) |
| 39 | parser.add_argument( |
| 40 | "--anchor", |
| 41 | help="Optional anchor frame used to stabilize global scale and frame 01 output.", |
| 42 | ) |
| 43 | parser.add_argument( |
| 44 | "--lock-frame1", |
| 45 | action="store_true", |
| 46 | help="Replace frame 01 with the provided anchor frame after normalization.", |
| 47 | ) |
| 48 | parser.add_argument( |
| 49 | "--alpha-threshold", |
| 50 | type=int, |
| 51 | default=8, |
| 52 | help="Pixels with alpha above this threshold count as sprite content. Default: 8.", |
| 53 | ) |
| 54 | return parser.parse_args() |
| 55 | |
| 56 | |
| 57 | def threshold_bbox(image: Image.Image, alpha_threshold: int) -> tuple[int, int, int, int] | None: |