Popups kommen nach Klick woanders / Alt+Tab wieder nach vorn; Büroklammer im Tipp des Tages
Windows-Build / windows-exe (push) Failing after 3m10s
Windows-Build / windows-exe (push) Failing after 3m10s
Fehler: War ein Popup offen und man klickte in ein anderes Programm, ließ sich das Popup über Hauptfenster, Taskleiste oder Alt+Tab nicht mehr nach vorn holen. Ursache: Rahmenlose Tk-Fenster mit transient() legt Tk unter Windows als Kindfenster des Desktops (WS_CHILD) an – ohne Besitzer, daher kam beim Zurückholen nur das (gesperrte) Hauptfenster nach vorn. - Popups (Dialoge, Rückfragen, Rundgang) ohne transient(), stattdessen Windows-Besitzer + Sperre des aufrufenden Fensters wie bei echten modalen Windows-Dialogen (gui/win32.py) - Rundgang: neue Sprechblase erscheint vor dem Entfernen der alten (sonst springt Windows weg) - Alt+F4 und Modalsperre robust gegen Timing (Sperre wird bei Bedarf nachgeholt) - Tests (nur unter Windows/Wine): Besitzer, Sperre, Stapelreihenfolge nach „woanders klicken“ und Zurückholen, verschachtelte Rückfragen, Rundgang - Tipp des Tages mit freigestelltem Büroklammer-Bild (build/make_tipp_bild.py), in der .exe enthalten und vom Selbsttest geprüft Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0bcc22d8c9
commit
9f05cab952
10 files changed
+417
-29
No files matched your search
@@ -0,0 +1,61 @@
|
||||
"""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 <foto>"""
|
||||
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")
|
||||
Reference in new issue
Block a user