Files
gta6/tools/extract/leonida/tiles.py
T
2026-09-12 13:50:20 +02:00

60 lines
2.1 KiB
Python

import time
import urllib.error
import urllib.request
from pathlib import Path
import numpy as np
from PIL import Image
from .coords import SLICE, TILE_PX, mosaic_origin_px, slice_tiles
COMMIT = "4093e8c874e480d47c38b37fe7a404f8b0c5275e"
BASE = f"https://raw.githubusercontent.com/rolux/gtadb.org/{COMMIT}/maps/tiles/6/yanis%2C15/5"
UA = {"User-Agent": "leonida-extract/0.1 (local hobby project)"}
def download_tiles(cache: Path) -> None:
"""Lädt alle Kacheln des Ausschnitts; vorhandene werden übersprungen."""
cache.mkdir(parents=True, exist_ok=True)
missing = []
for row, col in slice_tiles():
name = f"5,{row},{col}.jpg"
dst = cache / name
if dst.exists():
continue
for attempt in range(3):
try:
req = urllib.request.Request(f"{BASE}/{name}", headers=UA)
dst.write_bytes(urllib.request.urlopen(req, timeout=30).read())
break
except (urllib.error.URLError, TimeoutError):
time.sleep(2 ** attempt)
else:
missing.append(name)
if missing:
raise RuntimeError(f"{len(missing)} Kacheln fehlen: {missing[:5]} ...")
def assemble(load_tile) -> np.ndarray:
"""Setzt die Kacheln zusammen und schneidet auf den Ausschnitt zu."""
tiles = slice_tiles()
r0 = min(r for r, _ in tiles)
c0 = min(c for _, c in tiles)
rows = max(r for r, _ in tiles) - r0 + 1
cols = max(c for _, c in tiles) - c0 + 1
full = np.zeros((rows * TILE_PX, cols * TILE_PX, 3), dtype=np.uint8)
for row, col in tiles:
y, x = (row - r0) * TILE_PX, (col - c0) * TILE_PX
full[y:y + TILE_PX, x:x + TILE_PX] = load_tile(row, col)
ox, oy = mosaic_origin_px()
w = SLICE["x1"] - SLICE["x0"]
h = SLICE["y1"] - SLICE["y0"]
return full[oy:oy + h, ox:ox + w]
def load_mosaic(cache: Path) -> np.ndarray:
def load_tile(row: int, col: int) -> np.ndarray:
with Image.open(cache / f"5,{row},{col}.jpg") as img:
return np.asarray(img.convert("RGB"))
return assemble(load_tile)