feat: Logo-Upload mit automatischem Freistellen
Findet die automatische Suche kein Logo, kann pro Kunde eine Bilddatei hochgeladen werden. Ein Upload hat Vorrang vor der Suche. Freistellen: - remove_logo_background() entfernt den Hintergrund per Flood Fill von den Bildraendern her. Bewusst kein globaler Farbvergleich - sonst verschwindet auch Weiss innerhalb des Logos (etwa Text in einer Flaeche). Weiche Kante gegen Treppeneffekte. - Umgesetzt mit Pillow, das ueber qrcode[pil] ohnehin vorhanden ist. Bewusst kein ML-Modell wie rembg: der Container laeuft mit read-only Root-FS, ein Modell-Cache zur Laufzeit waere dort nicht moeglich. - Bereits transparente Bilder bleiben unangetastet. Ist der Bildrand nicht einfarbig, wird nicht freigestellt und die Oberflaeche weist darauf hin, statt ein beschaedigtes Logo zu liefern. - Checkbox "Hintergrund behalten" schaltet das Freistellen pro Kunde ab. - Gespeichert wird immer als PNG (JPEG kann keine Transparenz), grosse Bilder werden auf 800px verkleinert. Ablage unter media/<site>/logos/logo_<slot>.png, neue Route /media/<site>/logos/<datei>. Die URL traegt einen Zeitstempel, damit Player kein altes Logo aus dem Cache zeigen. Nebenbei behoben: welcome_data speicherte nur die erfolgreichen Kunden statt der Felder 1-3. Fiel Kunde 1 aus, rutschte Kunde 2 beim naechsten Aufruf in Feld 1 und Logo wie Ansprechpartner verschoben sich mit. Jetzt feldweise - dadurch bleibt auch ein hochgeladenes Logo beim erneuten Generieren erhalten, solange der Kundenname im selben Feld steht. Die drei Kundenbloecke im Formular sind zu einer Schleife zusammengefasst, damit die Upload-Felder nicht dreifach gepflegt werden muessen. README, AGENTS.md und Hilfeseite nachgezogen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -104,6 +104,14 @@
|
||||
{% if success %}
|
||||
<div class="alert alert-success">{{ success }}</div>
|
||||
{% endif %}
|
||||
{% if logo_hinweise %}
|
||||
<div class="alert alert-warning">
|
||||
<strong>Hinweise zu den hochgeladenen Logos:</strong>
|
||||
<ul class="mb-0">
|
||||
{% for h in logo_hinweise %}<li>{{ h }}</li>{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- ─── Logo-Vorschau (wird nach POST angezeigt) ─── -->
|
||||
<div class="row g-3 mb-4">
|
||||
@@ -122,36 +130,46 @@
|
||||
</div>
|
||||
|
||||
<!-- ─── Eingabeformular (bis zu 3 Kunden) ─── -->
|
||||
<form method="POST">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="site" value="{{ site }}">
|
||||
|
||||
{# Echte Zeilenumbrueche statt - in einer Variablen wuerde Jinja
|
||||
das kaufmaennische Und escapen und die Entity waere als Text sichtbar. #}
|
||||
{% set slots = [
|
||||
("z. B. Beispiel GmbH", "**Max Mustermann**\n+49 123 4567890\n*E-Mail*: max@beispiel.de"),
|
||||
("z. B. Muster AG", "**Maria Schmidt**\n+49 456 7890123\n*E-Mail*: maria@muster.de"),
|
||||
("z. B. Firma GmbH", "**Sabine Weber**\n+49 789 0123456\n*E-Mail*: sabine@firma.de")
|
||||
] %}
|
||||
|
||||
<div class="row g-3 mb-3">
|
||||
{% for i in range(3) %}
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="customer_name_1">Kunde 1</label>
|
||||
<input type="text" class="form-control" id="customer_name_1"
|
||||
name="customer_name_1" placeholder="z. B. Beispiel GmbH"
|
||||
value="{{ customer_names[0] if customer_names else '' }}">
|
||||
<label class="form-label mt-2" for="contact_1">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_1" name="contact_1" rows="4"
|
||||
placeholder="**Max Mustermann** +49 123 4567890 *E-Mail*: max@beispiel.de">{{ contacts[0] if contacts else '' }}</textarea>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="customer_name_2">Kunde 2 (optional)</label>
|
||||
<input type="text" class="form-control" id="customer_name_2"
|
||||
name="customer_name_2" placeholder="z. B. Muster AG"
|
||||
value="{{ customer_names[1] if customer_names else '' }}">
|
||||
<label class="form-label mt-2" for="contact_2">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_2" name="contact_2" rows="4"
|
||||
placeholder="**Maria Schmidt** +49 456 7890123 *E-Mail*: maria@muster.de">{{ contacts[1] if contacts else '' }}</textarea>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="customer_name_3">Kunde 3 (optional)</label>
|
||||
<input type="text" class="form-control" id="customer_name_3"
|
||||
name="customer_name_3" placeholder="z. B. Firma GmbH"
|
||||
value="{{ customer_names[2] if customer_names else '' }}">
|
||||
<label class="form-label mt-2" for="contact_3">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_3" name="contact_3" rows="4"
|
||||
placeholder="**Sabine Weber** +49 789 0123456 *E-Mail*: sabine@firma.de">{{ contacts[2] if contacts else '' }}</textarea>
|
||||
<label class="form-label" for="customer_name_{{ i + 1 }}">Kunde {{ i + 1 }}{% if i > 0 %} (optional){% endif %}</label>
|
||||
<input type="text" class="form-control" id="customer_name_{{ i + 1 }}"
|
||||
name="customer_name_{{ i + 1 }}" placeholder="{{ slots[i][0] }}"
|
||||
value="{{ customer_names[i] if customer_names else '' }}">
|
||||
|
||||
<label class="form-label mt-2" for="contact_{{ i + 1 }}">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_{{ i + 1 }}" name="contact_{{ i + 1 }}" rows="4"
|
||||
placeholder="{{ slots[i][1] }}">{{ contacts[i] if contacts else '' }}</textarea>
|
||||
|
||||
<label class="form-label mt-2" for="logo_file_{{ i + 1 }}">Logo hochladen (optional)</label>
|
||||
<input type="file" class="form-control" id="logo_file_{{ i + 1 }}"
|
||||
name="logo_file_{{ i + 1 }}" accept="image/*">
|
||||
<div class="form-check mt-1">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
id="logo_keep_bg_{{ i + 1 }}" name="logo_keep_bg_{{ i + 1 }}">
|
||||
<label class="form-check-label small" for="logo_keep_bg_{{ i + 1 }}">Hintergrund behalten</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="text-muted small mb-3">
|
||||
<i class="ti ti-info-circle me-1"></i>Ein hochgeladenes Logo hat Vorrang vor der automatischen Suche.
|
||||
Der Hintergrund wird automatisch freigestellt, damit das Logo auf der Willkommensseite nicht in einem
|
||||
weissen Kasten steht. Am besten funktioniert das bei einem Logo auf einfarbigem Grund; ein PNG mit
|
||||
bereits transparentem Hintergrund wird unverändert übernommen.
|
||||
</div>
|
||||
|
||||
<hr class="mt-4 mb-3">
|
||||
|
||||
@@ -252,6 +252,9 @@
|
||||
<li><strong>Zielscreens:</strong> Die generierte <code>welcome.html</code> wird automatisch an den Anfang der Playlist <em>jedes</em> Screens gesetzt, bei dem im Tab "Einstellungen" die Option <em>Willkommensseite hier anzeigen</em> aktiv ist. So lässt sich dieselbe Begrüßung auf mehreren Screens zeigen, ohne sie mehrfach anzulegen. Ist an einem Standort nichts eingestellt, geht sie wie bisher in die Lobby.</li>
|
||||
<li>Wird ein Screen später abgewählt, verschwindet die Willkommensseite dort beim nächsten Generieren automatisch.</li>
|
||||
<li><strong>Anzeigen bis:</strong> Optionales Datum im Formular. Ist es gesetzt, verschwindet die Willkommensseite nach diesem Tag auf allen Screens von selbst – kein manuelles Aufräumen nach dem Besuch. Ohne Angabe bleibt sie stehen.</li>
|
||||
<li><strong>Logo hochladen:</strong> Findet die automatische Suche kein Logo oder passt es nicht, kann pro Kunde eine eigene Bilddatei hochgeladen werden. Ein Upload hat immer Vorrang vor der automatischen Suche.</li>
|
||||
<li><strong>Freistellen:</strong> Der Hintergrund eines hochgeladenen Logos wird automatisch entfernt, damit es auf der Willkommensseite nicht in einem weissen Kasten steht. Das gelingt am besten bei einem Logo auf einfarbigem Grund – ein PNG mit bereits transparentem Hintergrund wird unverändert übernommen. Bei unruhigem Bildrand bleibt das Bild unangetastet und es erscheint ein Hinweis. Mit „Hintergrund behalten" lässt sich das Freistellen abschalten.</li>
|
||||
<li>Ein einmal hochgeladenes Logo bleibt beim erneuten Generieren erhalten, solange der Kundenname im selben Feld steht.</li>
|
||||
<li>Pro Standort kann ein eigenes Hintergrundbild hochgeladen werden (Tab "Medien" im Standort-Dashboard)</li>
|
||||
<li>Pro Kunde können <strong>Ansprechpartner</strong> eingegeben werden (Markdown-Format):
|
||||
<ul>
|
||||
|
||||
Reference in New Issue
Block a user