48 lines
1.9 KiB
Python
48 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Build a non-production grid placement guide with centered safe envelopes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--rows", type=int, required=True)
|
|
parser.add_argument("--cols", type=int, required=True)
|
|
parser.add_argument("--width", type=int, required=True)
|
|
parser.add_argument("--height", type=int, required=True)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> None:
|
|
args = parse_args()
|
|
if min(args.rows, args.cols, args.width, args.height) < 1:
|
|
raise SystemExit("all dimensions must be positive")
|
|
image = Image.new("RGB", (args.width, args.height), (0, 255, 0))
|
|
draw = ImageDraw.Draw(image)
|
|
for row in range(args.rows):
|
|
for col in range(args.cols):
|
|
left = round(col * args.width / args.cols)
|
|
right = round((col + 1) * args.width / args.cols)
|
|
top = round(row * args.height / args.rows)
|
|
bottom = round((row + 1) * args.height / args.rows)
|
|
cell_w, cell_h = right - left, bottom - top
|
|
margin_x, margin_y = round(cell_w * 0.23), round(cell_h * 0.23)
|
|
box = (left + margin_x, top + margin_y, right - margin_x, bottom - margin_y)
|
|
draw.rectangle(box, outline=(42, 48, 60), width=6)
|
|
cx, cy = (left + right) // 2, (top + bottom) // 2
|
|
draw.line((cx - 18, cy, cx + 18, cy), fill=(240, 240, 232), width=4)
|
|
draw.line((cx, cy - 18, cx, cy + 18), fill=(240, 240, 232), width=4)
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
image.save(args.output, optimize=True)
|
|
print(f"GRID_LAYOUT_GUIDE_OK cells={args.rows * args.cols} output={args.output}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|