till 7d42782c41 feat: all AI formats printable, crop-vs-border rule, mobile layout, Passbilder rename
Print now offers every format the AI pipeline knows (9x13 to 60x90, DIN A6-A2,
squares, poster/frame sizes to 70x100, and the screen ratios as physical sizes).
When a picture does not match the target ratio the user picks per image between
cropping to fill and keeping the whole picture on a border colour - never a
stretch. The module is called Passbilder now; /druck redirects.

Fixes two real defects: sharp runs extend after resize, so padded cells came out
oversized (a 35x45 mm cell became 35x171 mm with a border), and the grid packer
rotated a single portrait photo just because more would fit sideways.

Mobile: cards become rows, touch targets ~40px, crop editor as a bottom sheet.
Verified at 390/820/1440px - all three produce the same PDF.
2026-08-18 07:04:08 +00:00

Klarbild

Verwandelt Screenshots und Fundstücke in saubere, druckfertige Bilder — Rahmen und Shop-Oberflächen entfernen, exakte Fotoformate (30×40 cm etc.), The-Frame-Querformat, für den Cricut freistellen, und automatisch nach Picdrop ausliefern.

Claim: „Screenshot rein, sauberes Bild raus."

Stack

Astro 5 (SSR, Node standalone) + React-Inseln · Postgres · S3 (MinIO) · pg-boss · sharp · pdf-lib (Druckbogen) · grammY (Telegram) · OKLCH-Tokens, kein Tailwind. Deploy: Gitea → Coolify → Hetzner.

Entwicklung

npm install
cp .env.example .env   # Werte eintragen
npm run dev

Migrationen und Seeds laufen beim Serverstart automatisch. Erststart-Passwörter über SEED_TILL_PASSWORD / SEED_LEA_PASSWORD.

Funktionen (Kurzüberblick)

  • Modi: Bereinigen (Screenshot säubern/freistellen/formatieren), Umwandeln (ein Bild + Text, z. B. Foto → Ölgemälde), Kombinieren (mehrere Bilder + Text), Neu erzeugen (nur Text).
  • Formate: feste cm-/DIN-/Screen-Formate und frei definierbare — Schlüssel WxH (z. B. 25x35) oder sticker<N> (sticker5 = 5×5 cm). Parsing in src/lib/format.ts, keine Migration nötig.
  • Dateiformat: PNG (verlustfrei, Transparenz) oder JPG (klein, Picdrop-freundlich). Global über settings.output_ext, pro Rezept via recipes.output_ext, pro Umwandlung im Studio. JPG nur ohne Alpha.
  • Auslieferung: Picdrop (SFTP/FTPS) + beliebige Zusatzziele; NAS/Backup-Ziele; optionaler .md-Metadaten-Beileger pro Ziel schaltbar. Nicht-transparente Ergebnisse gehen als JPG an Picdrop.
  • Bibliothek: Ordner, Farbmarkierungen, Prompt-Anzeige, Vorher/Nachher, Vollbild + „In Fotos sichern".
  • Rechte/Datenschutz: Sichtbarkeit (eigene/alle), anonyme Generierungen, private Sessions, NSFW-Gate.
  • Telegram-Bot (grammY-Webhook) als vollwertiger Website-Ersatz. API-Token (Bearer) für /api/*.
  • Passbilder & Druckbogen (/passbilder, ohne KI): Bilder exakt auf physische Maße bringen (interaktiver Zuschnitt mit Zoom/Verschieben) und mehrere davon in 100-%-Größe mit Schnittmarken auf einen Bogen setzen — Passbildsatz, Kita-Satz, Sticker. Papier DIN A6A2 inkl. A3+, Fotopapier 9×1320×30, Letter/Legal oder freies Maß. Marken: Eckmarken (0,25 pt, außerhalb des Endformats) oder durchgehende Linien. Beschnittzugabe 010 mm. Ausgabe: PDF in 1:1 (pdf-lib) bzw. Einzelbild mit dpi-Metadaten. Layout: gleiche Größen → exaktes Raster, gemischte Größen → MaxRects-Packer. Alle Formate der KI-Generierung sind auch hier wählbar; passt das Bild nicht zum Format, entscheidet man je Bild zwischen Zuschneiden und Rand lassen (mit Randfarbe) — nie verzerren. Kern: src/lib/paper.ts (Formate), src/lib/printlayout.ts (reine Mathematik, getestet), src/lib/printrender.ts (sharp + pdf-lib). Auch per Telegram („📐 Passbilder") und MCP (exact_size, print_sheet).
  • Admin: Key/Picdrop/Modelle/Nutzer/Kostendeckel/Presets/Speicherverwaltung, Picdrop-Diagnose.

Datenmodell / Migrationen

Nummerierte SQL in migrations/, beim Start automatisch (kein ORM-Push). Wichtige Spalten: items.has_alpha, jobs.status (inkl. failed), jobs.finished_at, settings.output_ext / recipes.output_ext, settings.*_metadata_sidecar, delivery_targets.*, print_presets (Bogen-Vorlagen, 013).

Tests

npm test — Node-Testrunner über tsx. Deckt die Druck-Layoutmathematik ab (Maß-Parsing, mm → px exakt, Überlappungsfreiheit, Ränder, Beschnittzugabe, Markengeometrie, Mehrseitigkeit).

Stolpersteine & Lösungen (Learnings)

  • „Bild bei Picdrop ✓, aber nicht in der Galerie": Fehldiagnose vermeiden — die Dateien lagen die ganze Zeit korrekt per SFTP in /POSTER LEA (per Admin → Picdrop → „Ordner anzeigen" verifizierbar). Der eigentliche Grund war die Sortierung in der Picdrop-Weboberfläche, nicht das Format. Unabhängig davon liefern wir nicht-transparente Ergebnisse jetzt als JPG aus (src/lib/delivery.ts, deliverableBuffer): ~25 MB PNG → ~2 MB JPG, schneller und handlicher — plus wählbares Ausgabeformat (output_ext).
  • „Unbekanntes Format: sticker5": Seed legte ein Rezept mit Formatschlüssel sticker5 an, den der Resolver nicht kannte → jeder Lauf schlug fehl. Lösung: generisches Parsen von sticker<N>/WxH.
  • Auftrag trotz Fehler grün: jobs.status kannte kein failed; alle Positionen fehlgeschlagen wurde trotzdem done. Lösung: Status failed, wenn done=0 && failed>0 (src/worker.ts maybeComplete).
  • Doppelte Datums-/UUID-Namen: \b-Wortgrenzen greifen nicht an Unterstrichen. Lösung: \b entfernt, Datum/UUID/Hex global ersetzt (src/lib/pipeline.ts cleanMotif).
  • Content-Type bei gemischten PNG/JPG-Ergebnissen: file.ts snifft jetzt die Magic Bytes.
  • .tmp--Reste auf Picdrop: früher Temp-Rename-Bug; cleanupTmp + Admin-Knopf „Reste aufräumen".

Status

Reihenfolge und Nachweise siehe CLAUDE.md. Anforderungen im Handover-Paket (Imagetool-Lea/00..07). Führend: 01-anforderungen.md.

S
Description
Klarbild — Screenshots & Fundstuecke zu druckfertigen Bildern (Astro+Postgres+S3)
Readme 1.4 MiB
Languages
TypeScript 86.2%
Astro 10.8%
JavaScript 2.4%
CSS 0.5%
Dockerfile 0.1%