"""Erzeugt provtool/gui/bilder/tipp.png (freigestellt, verkleinert, ohne Metadaten) aus dem Foto für den „Tipp des Tages“. Nur zum Entwickeln nötig (Pillow): python build/make_tipp_bild.py """ import sys from collections import deque from pathlib import Path from PIL import Image ZIEL_HOEHE = 170 ROOT = Path(__file__).resolve().parents[1] def freistellen(im: Image.Image, schwelle: int = 232, min_flaeche: int = 6000) -> Image.Image: """Weißen Hintergrund transparent machen: alle hellen Flächen, die den Rand berühren ODER groß sind (z. B. das Innere der Büroklammer-Schlaufen). Kleine helle Flächen (Augenweiß) bleiben.""" im = im.convert("RGBA") w, h = im.size px = im.load() hell = lambda p: p[0] >= schwelle and p[1] >= schwelle and p[2] >= schwelle # noqa: E731 gesehen = bytearray(w * h) for sy in range(h): for sx in range(w): if gesehen[sy * w + sx] or not hell(px[sx, sy]): continue flaeche, rand, q = [], False, deque([(sx, sy)]) gesehen[sy * w + sx] = 1 while q: x, y = q.popleft() flaeche.append((x, y)) if x in (0, w - 1) or y in (0, h - 1): rand = True for nx, ny in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)): if 0 <= nx < w and 0 <= ny < h and not gesehen[ny * w + nx] and hell(px[nx, ny]): gesehen[ny * w + nx] = 1 q.append((nx, ny)) if rand or len(flaeche) >= min_flaeche: for x, y in flaeche: px[x, y] = (255, 255, 255, 0) return im.crop(im.getbbox()) def main(foto: str, ziel: Path, modus: str = "lanczos"): im = freistellen(Image.open(foto)) faktor = ZIEL_HOEHE / im.height groesse = (max(1, round(im.width * faktor)), ZIEL_HOEHE) if modus == "raster": # erst auf das Pixel-Raster (ca. 8 px) mitteln, dann hochskalieren klein = im.resize((im.width // 8, im.height // 8), Image.BOX) im = klein.resize(groesse, Image.NEAREST) else: im = im.resize(groesse, Image.LANCZOS) # Halbtransparente Randpixel hart machen (Tk/Win95-Optik, keine weißen Säume) alpha = im.getchannel("A").point(lambda a: 255 if a >= 128 else 0) im.putalpha(alpha) ziel.parent.mkdir(parents=True, exist_ok=True) im.save(ziel, optimize=True) # PNG ohne EXIF-Metadaten print(ziel, im.size) if __name__ == "__main__": main(sys.argv[1], Path(sys.argv[2]) if len(sys.argv) > 2 else ROOT / "provtool" / "gui" / "bilder" / "tipp.png", sys.argv[3] if len(sys.argv) > 3 else "lanczos")