diff --git a/app.py b/app.py index c26bd2b..ae92f8a 100644 --- a/app.py +++ b/app.py @@ -183,6 +183,17 @@ class RechnungsApp(ThemeMixin, MeldungMixin, KorrekturMixin, EinstellungenMixin, """ leiste = ttk.Frame(self, padding=(16, 8, 16, 0)) leiste.pack(side="top", fill="x") + + # Das Programmlogo oben LINKS und gross. Es stand zuerst klein (18 px) + # unten in der Statuszeile - sein Befund am 07.09.2026: "ist mir zu + # klein geht unter mach es doch gros oben links weil da ist eh platz". + # Hier ist wirklich Platz: die Leiste traegt sonst nur den Knopf + # "Anordnen", und der sitzt rechts. + self._kopf_bild = wasserzeichen.kopf( + 34, master=self, dunkel=getattr(self, "_dark_mode", False)) + if self._kopf_bild is not None: + ttk.Label(leiste, image=self._kopf_bild).pack(side="left") + self.werkzeuge = ttk.Frame(leiste) self.werkzeuge.pack(side="right") @@ -784,13 +795,6 @@ class RechnungsApp(ThemeMixin, MeldungMixin, KorrekturMixin, EinstellungenMixin, def _build_summen(self): # Statuszeile ganz unten status = ttk.Frame(self, padding=(12, 2)) - # Das Programmlogo neben der Marke - klein, immer sichtbar. Es steht - # rechts bei "powered by ravokk", weil dort die Kennung des Werkzeugs - # sitzt und nicht die des Kunden. - self._kopf_bild = wasserzeichen.kopf(18, master=self, - dunkel=getattr(self, "_dark_mode", False)) - if self._kopf_bild is not None: - ttk.Label(status, image=self._kopf_bild).pack(side="right", padx=(0, 6)) status.pack(side="bottom", fill="x") ttk.Label(status, text=config.MARKE, foreground=self.col_muted, font=(theme.SCHRIFT_NAME, 8)).pack(side="right") diff --git a/assets/programm_dunkel.ico b/assets/programm_dunkel.ico index ce2d86d..56f97f7 100644 Binary files a/assets/programm_dunkel.ico and b/assets/programm_dunkel.ico differ diff --git a/wasserzeichen.py b/wasserzeichen.py index e582a93..495d72c 100644 --- a/wasserzeichen.py +++ b/wasserzeichen.py @@ -66,7 +66,7 @@ def symbol_datei_dunkel(): ziel = os.path.join(os.path.dirname(quelle), "programm_dunkel.ico") try: from PIL import Image - bild = _fuer_dunkel(Image.open(quelle).convert("RGBA")) + bild = _umfaerben(Image.open(quelle).convert("RGBA"), True) groessen = [(g, g) for g in (16, 24, 32, 48, 64, 128, 256)] try: bild.save(ziel, sizes=groessen) @@ -101,39 +101,45 @@ def symbol_setzen(fenster, melden=print, dunkel=False): return False -def _fuer_dunkel(bild): - """Das Logo fuer die dunkle Darstellung aufhellen. +# Die Farben des Logos - gemessen, nicht geraten: +# #004860 das dunkle Blaugruen (Wolke, Pfeile) +# #181818 das fast schwarze Grau (Dokument bzw. Paragraphenzeichen) +# +# Seine Ansage am 07.09.2026: *"das dunkel blaue machen wir in unserm tuerkis +# gruen und die andere seite in weiss ... wenn es dunkel ist, und beim hellen +# machen wir weiss in dunkel grau"*. Das Zeichen traegt damit dieselbe Farbe +# wie das Programm - und die zweite Haelfte steht in beiden Darstellungen im +# Kontrast statt unterzugehen. +TUERKIS = (0x06, 0xC6, 0xA4) # die Programmfarbe, wie col_accent +NEUTRAL_DUNKEL = (0xF2, 0xF3, 0xF5) # fast weiss - auf dunklem Grund +NEUTRAL_HELL = (0x33, 0x36, 0x3B) # dunkelgrau - auf hellem Grund - Sein Befund am 07.09.2026: *"wir muessen mal schauen das wir die svg fuer - das dunkle heller machen weil die geht nun unter"*. - Gemessen sind es zwei Farben: das Petrol #004860 (Helligkeit 53) und ein - fast schwarzes #181818 (Helligkeit 24). Der zweite Wert liegt genau auf der - Kachelfarbe #15171b - deshalb verschwindet die Haelfte des Zeichens. +def _umfaerben(bild, dunkel): + """Das Logo auf die Programmfarben umsetzen. - Umgestellt wird nur die HELLIGKEIT, Farbton und Saettigung bleiben: sonst - waere es nicht mehr sein Logo, sondern ein anderes. Aus dunkel wird hell, - aus hell dunkel (L -> 1-L), und weil eine reine Umkehr das kraeftige Petrol - fast weiss werden liesse, wird sie auf 0.78 gedeckelt. + Unterschieden wird nach SAETTIGUNG, nicht nach dem genauen Farbwert: das + Blaugruen ist kraeftig gesaettigt, das Grau gar nicht. So bleibt die + Zuordnung auch dann richtig, wenn die Vorlage einmal in einem anderen Ton + gezeichnet wird - und die weichen Kanten aus dem Skalieren gehen denselben + Weg wie die Flaeche, zu der sie gehoeren. - Die Kanten (halbdurchsichtige Punkte aus dem Skalieren) gehen denselben Weg - - deshalb Pixel fuer Pixel und nicht ein Farbtausch mit Toleranz. + Die Deckkraft bleibt unangetastet; die Form kommt aus dem Alphakanal. """ import colorsys bild = bild.convert("RGBA") + neutral = NEUTRAL_DUNKEL if dunkel else NEUTRAL_HELL punkte = list(bild.getdata()) - neu = [] zwischen = {} + neu = [] for r, g, b, a in punkte: if a == 0: neu.append((r, g, b, a)) continue schluessel = (r, g, b) if schluessel not in zwischen: - h, l, s2 = colorsys.rgb_to_hls(r / 255, g / 255, b / 255) - hell = min(1.0 - l, 0.78) - r2, g2, b2 = colorsys.hls_to_rgb(h, hell, s2) - zwischen[schluessel] = (int(r2 * 255), int(g2 * 255), int(b2 * 255)) + _, _, saettigung = colorsys.rgb_to_hls(r / 255, g / 255, b / 255) + zwischen[schluessel] = TUERKIS if saettigung > 0.25 else neutral neu.append(zwischen[schluessel] + (a,)) bild.putdata(neu) return bild @@ -162,8 +168,7 @@ def hole(groesse=240, deckkraft=0.06, master=None, melden=print, dunkel=False): try: from PIL import Image, ImageTk bild = Image.open(p).convert("RGBA").resize((groesse, groesse), Image.LANCZOS) - if dunkel: - bild = _fuer_dunkel(bild) + bild = _umfaerben(bild, dunkel) bild.putalpha(bild.getchannel("A").point(lambda w: int(w * deckkraft))) fertig = ImageTk.PhotoImage(bild, master=fenster) except Exception as e: # noqa: BLE001 - ein Wasserzeichen darf nichts blockieren