Files
till 5ebe8026e0 feat: oversize sheets, image duplication, free labelling and a new layout
Prints larger than the sheet no longer just fail. Each cell can now spill over
the whole sheet (20x30 on A4 loses exactly 3 mm, and says so beforehand) or be
tiled across several sheets with a dashed glue fold and a sheet number. The
maths lives in printoversize.ts, dependency-free, so the browser preview and the
server PDF compute the same thing -- including the note strip that keeps the
sheet number off the picture.

The same image can now appear as several cells, so a portrait can be printed at
two sizes on one sheet without copying and re-uploading the file. The footer
line can be switched off, given custom text and placed at one of six positions;
it is only drawn where that edge is free.

Layout reworked for all three widths: work left, sticky preview right on the
desktop, collapsed setting groups paired in a two-column grid that expands full
width; preview first and a fixed action bar on the phone. Verified at 390, 820,
1440 and 1680 px -- no horizontal overflow, no dead white space.

Also a public presentation page at /vorstellung (no login, nothing operable),
whose sample sheet is computed by the real packer rather than drawn.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BNhLunz586g6DeYMa7Qsd1
2026-08-20 10:55:11 +00:00

88 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```bash
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/*`.
- **Drucken (`/drucken`, 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.
86 Bildmaße in 10 Gruppen (Passbild bis 100 × 140 cm), 19 Papierformate.
**Größer als der Bogen** (20 × 30 cm auf A4): je Zelle `oversize` = `fit` (melden) ·
`overflow` (mittig aufs ganze Blatt, Verlust wird vorab beziffert — hier genau 3 mm) ·
`tile` (Posterdruck auf mehrere Blätter mit gestricheltem Klebefalz und Blattnummer).
**Beschriftung** frei: aus, automatisch oder eigener Text an einer von sechs Stellen;
sie entfällt automatisch, wenn an der Kante kein Platz frei ist.
Dasselbe Bild darf mehrfach als Zelle vorkommen („Duplizieren"), um es in zwei Maßen zu drucken.
Kern: `src/lib/paper.ts` (Formate), `src/lib/printlayout.ts` (reine Mathematik, getestet),
`src/lib/printoversize.ts` (Überstand & Kachelung, getestet), `src/lib/printrender.ts`
(sharp + pdf-lib). Browser-Vorschau und Server-PDF benutzen denselben Rechenkern.
Auch per Telegram („🖨 Drucken") und MCP (`exact_size`, `print_sheet`).
Öffentliche Vorstellungsseite ohne Login: `/vorstellung`.
- **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 mit nativem Type-Stripping (`node --experimental-strip-types`).
**Kein `tsx`, kein `playwright` in `package.json`** — der Docker-Build installiert devDependencies,
und deren native postinstall-Schritte haben den Deploy schon zweimal zerlegt. Testwerkzeug gehört
außerhalb des Projekts installiert. 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`.