11 KiB
11 KiB
Changelog
All notable changes to Klarbild are documented here. Newest first.
2026-08-18 (3) — Code review: fixes
Fixed
- EXIF orientation was ignored. Phone photos carry their rotation as metadata only.
sharp cropped the unrotated raster, so a portrait shot came out of the printer sideways
and with the wrong framing. Orientation is now applied before any geometry, and
/api/uploadsreports oriented dimensions so the crop editor agrees with the render. - Memory blow-up on "Rand lassen". The padded image was materialised at source resolution before the resize. A panorama into a narrow contain target built a ~960 MB intermediate and then failed outright; it is one extract→resize→extend chain now (sharp's own order) — 90 ms and a few MB.
bleedMmwas unbounded in/api/print/single(the sheet endpoint clamped it).- Delivery gallery could escape the target's base folder —
posixpath.joinhappily resolves../.., and the folder is created before upload. Names are validated now. - Denial of service: sheet requests are capped at 500 pieces and the packer has a step budget, so a degenerate request can no longer block the single-threaded server.
- Print presets: delete only your own (admins all), config size and count limits,
and
by_namehonoursanonymous_generations. - Telegram callbacks now require an active pairing, like every other path.
- Error responses no longer leak storage paths or delivery hostnames.
allowRotate: undefinedmeant "no rotation" in one place and "rotation allowed" in two others — a picture that only fits rotated was reported as unplaceable.- The many-formats shortcut dropped a format that only fits rotated.
unplacedblamed the first format instead of the one actually missing.- Corner marks could land inside the printed bleed; the offset is raised to clear it.
capacity()silently capped at 200.- Image keys could collide with a cell literally named
x::rot. labelMmrounded away real decimals (11,25 cm became 11,3);parseSizeMmignored the order ina:b, so3:4/15and4:3/15produced the same portrait size.- The footer was drawn over the artwork when the margin was small.
- The UI now warns when corner marks do not fit the margin, and when continuous guides are combined with mixed sizes (they cannot run through).
Changed
- Tests grew from 21 to 31 — every finding above has a regression test.
2026-08-18 (2) — Passbildfunktion: all sizes, fit rules, mobile
Added
- Renamed to "Passbilder" — the tab, page and Telegram button now say what it is.
/druckpermanently redirects to/passbilder. - Every size the AI pipeline knows is now printable too: 9×13 … 60×90, DIN A6–A2, squares, plus poster/frame sizes up to 70×100 and the screen ratios (16:9 "The Frame", 9:16, 3:2, 4:3, 5:4) as physical measurements. 41 presets in seven groups.
- Fit rule per image — when the picture does not match the target ratio, choose
Zuschneiden (fill the format, crop the overflow — default) or Rand lassen
(keep the whole picture, pad with a border colour: white, black, paper or custom).
Nothing is ever distorted. Works in the crop editor, the sheet preview, the PDF,
/api/print/*(fit,bg) and the saved templates. - Mobile layout — image cards become a row on phones, touch targets grow to ~40 px, the crop editor turns into a full-width bottom sheet, no horizontal overflow. Verified at 390 / 820 / 1440 px; all three produce the identical PDF.
Fixed
- Sheet cells could come out oversized. sharp applies
extendafterresize, so padding was added on top of the finished size — a 35×45 mm cell became 35×171 mm in "Rand lassen" mode, and bleed near an image edge was off too. Crop and padding now run in their own pass. Covered bytests/printrender.test.ts. - Orientation is no longer overridden. A single portrait passport photo was laid down sideways just because more would fit that way. Rotation now only happens when it actually saves a sheet.
2026-08-18 — Print module: exact sizes, sheets & crop marks (no AI)
Added
- Print module (
/druck) — a lab-style, completely AI-free path: crop, scale and place images at exact physical sizes. No model call, no cost, no queue. - Interactive crop editor — pan and zoom on a fixed target aspect ratio (rule-of-thirds overlay); the crop is stored relative (0..1) so it survives any source resolution.
- Size presets & free input — biometric passport 35 × 45 mm, 2 × 3 / 3 × 4 / 4 × 5 / 4,5 × 6 cm,
9 × 13 … 50 × 70 cm, squares, DIN. Free input understands
12x15(cm),35x45mm,5(= 5 × 5 cm) and4:3/15(ratio + long edge). - Sheet layout — paper presets DIN A6–A2 incl. A3+ (329 × 483 mm), photo-paper cuts (9 × 13 … 20 × 30), US Letter/Legal, plus any custom paper size. Portrait/landscape, printer margin, centering, per-image copy count.
- Automatic nesting — identical sizes produce an exact grid; mixed sizes go through a MaxRects packer that fixes one orientation per format and tries every combination, so eight passport photos land in the free space next to the 13 × 18.
- Crop marks —
corner(fine 0.25 pt marks outside the trim box, Photoshop/InDesign convention, 4 mm long / 3 mm offset by default) orgrid(continuous guides across the sheet that never cross another image). Gap between images adapts to the chosen marks. - Bleed (0–10 mm) — the image extends past the trim box, edge pixels are copied rather than stretched; the gap is always ≥ 2 × bleed so neighbouring bleeds cannot overlap.
- PDF output at 1:1 — the PDF page is exactly the sheet size (pdf-lib), with a footer stating the sizes, dpi and the "print at 100 %, not fit-to-page" reminder.
- Single export — one image at an exact size as PNG/JPG with dpi metadata, plus a resolution warning when the source cannot hold the requested dpi.
- Sheet templates — save the whole sheet setup (paper, marks, formats, counts) as a
reusable preset (
print_presets, migration013). - All three entrances —
/druckin the web app,📐 Druckbogenin Telegram (fully button-driven, returns an A4 PDF), and the MCP toolsexact_size/print_sheet. - API —
POST /api/print/single,GET /api/print/single?size=…(mm → px calculator),POST /api/print/sheet,GET|POST|DELETE /api/print/presets. Documented in/llms.txt. - Seeded sheet templates — "Kita-Satz (A4)", "Schulsatz klein (A4)", "Passbildbogen 35×45 (A4)" and "2 × 10×7,5 auf Fotopapier 10×15". Loading a multi-format template with a single image clones that image into every format, so one click produces the whole set.
- Margin profiles — borderless (0 mm), standard (5 mm) and safe (10 mm) as one-click buttons.
- Deliver the sheet — the finished PDF can additionally be pushed to Picdrop, the NAS or any
extra delivery target (
deliverin the sheet request). - Tests —
tests/printlayout.test.ts(npm test) covers size parsing, exact mm → px, non-overlap, margins, bleed spacing, mark geometry and multi-sheet paging.
2026-07-23 — Compose, generate & second backup
Added
- Compose mode — combine multiple images + a text description into one new image.
- Generate mode — create images from text only, no source needed.
- The Frame "extend" — outpaint more scene around the motif instead of only cropping.
- Reuse — take a finished result back into the studio as a new source to edit further.
- Alternatives — generate additional versions of the same image, grouped with a switcher.
- Folders — filter, rename and delete in the library; per-folder delivery gallery mapping.
- Bulk actions — download selected results as a ZIP, move several into a folder at once.
- Thumbnails — low-res previews for the library grid.
- Models — quality tiers incl. open-source (FLUX.2); the used model is shown per image.
- Color tags — Picdrop-style flags (red / orange / green / final) per image, filterable, and
written into the companion
.mdmetadata. - Tap-to-save — "Laden" opens the image full-bleed so on iPhone/iPad a long-press offers "Save to Photos" (plus a classic file download).
- Access control & privacy — library visibility (own-only vs shared), optional anonymous generations (creator hidden from non-admins), admins always see all.
- Private sessions — generate-and-forget: no library entry, no delivery/backup, no stored prompt, sources purged, result auto-deleted shortly after. Enabled globally by admin or forced per user.
- NSFW gate — models flagged NSFW are only selectable/visible when the admin enables it. Operator responsibility; content involving minors is never permitted.
- Single-image transform — compose now accepts one image, so a single photo can be transformed by prompt (e.g. "make it an oil painting") and put onto a format.
- Multiple delivery targets — besides the default Picdrop, add any number of FTP/SFTP destinations; selectable in the studio ("Wohin?", incl. NAS); a preset or folder can be hard-wired to a specific target + gallery.
- Backup to any target — mark any target as a backup destination (like the NAS); one-click "back up all images" mirrors to all backup destinations.
- Metadata sidecar — optionally ship a companion
.md(prompt, model, format …) next to each image on Picdrop/NAS/FTP. - Prompt view — every generated image shows its prompt in the library (with copy).
- Preset manager — save current settings as a preset, load and delete presets.
- API token + MCP server — programmatic access so an assistant can push images from a
local folder or iMessage into Klarbild (
mcp/klarbild-mcp.mjs). - The Frame preset now delivers to its own gallery ("TheFrame-Backgrounds").
- Second backup — mirror every result over SFTP/FTPS to a NAS (works over Tailscale too), with a "NAS ✓" badge and a "mirror all existing images" action.
- Storage management — thumbnails, delete sources after processing, auto-retention.
- Telegram — fully button-driven (persistent keyboard + command menu): edit, compose, "new image", reuse — no slash commands required.
- Reset — wipe library, jobs and folders cleanly (keeps users, settings, models, recipes), guarded by a typed confirmation.
- Help page, in-app changelog, and a NAS reachability diagnostic.
Fixed / hardened
- Real per-image cost cap (monthly budget) enforced by the worker.
- Idempotent job completion (no duplicate delivery/notification).
- Before/after comparison works for composed images; hidden for text-only results.
2026-07-22 — Foundation
Added
- Astro 5 + React islands UI (mobile-first), PostgreSQL, fs/S3 storage abstraction.
- pg-boss job queue with in-process worker; sharp pipeline (exact cm/dpi print sizes, sticker contour).
- OpenRouter image gateway; admin-managed models.
- Picdrop delivery over SFTP/FTPS; recipes; library with before/after.
- Telegram bot (grammY webhook); argon2 auth; AES-256-GCM secret encryption.