A self-hosted print studio: images at exact physical sizes, sheet layout with crop marks, tiling, 1:1 PDF. Everything else — image generation, delivery, share links, mail, Telegram — is an optional module that is off by default. This is the neutral public twin of a private tool. Compared to that original: - optional modules behind KLARBILD_MODULES; the default install is print-only - English interface with German as a full second language (1,038 strings); the English sentence is the translation key - no built-in accounts — first boot creates one admin from ADMIN_USERNAME / ADMIN_PASSWORD, or generates a password and logs it once - delivery and backup targets are generic SFTP/FTPS endpoints, off by default - English routes, English identifiers, English comments throughout - two compose files: print-only by default, everything in the full one - AGPL-3.0, CI (build, tests, type check, secret scan), CONTRIBUTING, SECURITY 124 tests green, type check clean, verified end to end against a live instance. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nh4A79bbqT9dcd2inzYUdg
This commit is contained in:
164 files changed
+27190
No files matched your search
@@ -0,0 +1,157 @@
|
||||
# Klarbild
|
||||
|
||||
**Print pictures at the size you actually asked for.**
|
||||
|
||||
Your printer driver has a checkbox called "fit to page". Tick it and a 35 × 45 mm
|
||||
passport photo comes out 34 × 44. Untick it and you are guessing. Photo shops have
|
||||
software for this; the rest of us have a ruler and a bad afternoon.
|
||||
|
||||
Klarbild is that software, self-hosted. Give it an image and a physical size, and
|
||||
it produces a PDF that measures exactly that on paper — with crop marks, with
|
||||
bleed if you want it, with as many pictures on one sheet as fit, and with the
|
||||
oversize cases handled rather than silently scaled.
|
||||
|
||||
It also does AI image generation, delivery to a server, share links, mail and a
|
||||
Telegram bot. **All of that is optional.** The default install is the print studio,
|
||||
a database, and nothing else — no API key, no model, no object store, no account
|
||||
anywhere.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/tillheidrich/klarbild.git && cd klarbild
|
||||
cp .env.example .env # fill in three secrets, the file says which
|
||||
docker compose up -d
|
||||
docker compose logs app # your admin password is printed here, once
|
||||
```
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## What the print studio does
|
||||
|
||||
**Exact physical sizes.** 86 sizes in 10 groups — passport photo, small prints,
|
||||
photo formats, US inches, instant-camera, poster and frame sizes, squares, DIN,
|
||||
cards, plain aspect ratios — or type your own (`25x35`, `13x18`, `10x7,5`). The
|
||||
output is a PDF laid out in millimetres, not a scaled bitmap, so 30 × 40 cm is
|
||||
30 × 40 cm.
|
||||
|
||||
**Sheet layout.** Put several pictures on one sheet at 100 % with crop marks:
|
||||
corner marks (0.25 pt, outside the trim) or continuous lines. Equal sizes snap to
|
||||
an exact grid; mixed sizes go through a MaxRects packer. Bleed 0–10 mm. 19 paper
|
||||
formats from A6 to A2 — including A3+ and photo paper 9 × 13 to 20 × 30, Letter
|
||||
and Legal — or a custom sheet.
|
||||
|
||||
**Pictures bigger than the sheet, handled three ways.** A 20 × 30 cm print on A4
|
||||
is not an error message. Choose **fit** (it tells you it will not fit), **overflow**
|
||||
(centred across the whole sheet, and it quantifies the loss before you print —
|
||||
"3 mm off each side"), or **tile** (poster print across several sheets, with a
|
||||
dashed glue flap and a page number on each).
|
||||
|
||||
**Crop or letterbox, never distort.** When a picture does not match its target
|
||||
ratio you decide per picture: crop it (with an interactive zoom-and-pan preview)
|
||||
or leave a border in a colour you pick. Nothing is ever stretched.
|
||||
|
||||
**Captions, duplicates, presets.** A caption in one of six positions, automatic or
|
||||
your own text — and it disappears by itself when there is no room at that edge.
|
||||
The same picture can appear twice on one sheet at two different sizes. Presets for
|
||||
the layouts you repeat; a history of the last 100 runs per account that stores the
|
||||
*instructions*, never the PDF, so "print that again" costs 1–3 KB instead of 80 MB.
|
||||
|
||||
**The browser preview and the server PDF share one engine.** `printlayout.ts` is
|
||||
pure arithmetic with its own tests. What you see is what gets rendered — the page
|
||||
of the PDF above measures 210.00 × 297.00 mm, because that is what A4 is.
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/print-de.png" width="49%" alt="The same screen in German" />
|
||||
<img src="docs/screenshots/help-en.png" width="49%" alt="The built-in manual" />
|
||||
</p>
|
||||
|
||||
## What else is in the box, if you switch it on
|
||||
|
||||
| Module | What it adds | What it needs |
|
||||
|---|---|---|
|
||||
| `print` | everything above | nothing — always on |
|
||||
| `ai` | clean up screenshots, convert, combine, generate | an OpenRouter key (paid per image) |
|
||||
| `delivery` | push finished files to an SFTP/FTPS server you already have | that server |
|
||||
| `mirror` | a second copy of every result, sorted by month | a second target |
|
||||
| `share` | public links: expiring, revocable, optional passphrase, ZIP download | a public URL |
|
||||
| `mail` | password reset, job notices, sending share links | your own SMTP mailbox |
|
||||
| `telegram` | the whole tool from a chat window | a bot token |
|
||||
|
||||
```bash
|
||||
KLARBILD_MODULES=print # the default
|
||||
KLARBILD_MODULES=print,ai,share # pick what you want
|
||||
KLARBILD_MODULES=all # everything
|
||||
```
|
||||
|
||||
A module that is off is off: no navigation entry, no settings card, and its API
|
||||
routes answer 404 rather than 403 — a disabled instance does not advertise what it
|
||||
could have done.
|
||||
|
||||
## Why self-hosted matters here
|
||||
|
||||
The pictures are family photos, passport photos, ID pictures and client work.
|
||||
Klarbild keeps them on your machine. The print studio never makes an outbound
|
||||
request at all — it is arithmetic, `sharp` and `pdf-lib`. Even with the AI module
|
||||
on, only what you send to the model leaves the building, and the API key is yours.
|
||||
|
||||
Share links are built to be careful rather than convenient: they expire (30 days by
|
||||
default), they can be revoked, they can carry a passphrase, downloads can be
|
||||
switched off, and they are `noindex`. Access hangs on the link, not on the image, so
|
||||
guessing an image id gets you a 404. The view counter records *when* and *with what*,
|
||||
never *who*: the IP is hashed with a server secret **and** the link id, one row per
|
||||
visitor per hour, deleted after 90 days.
|
||||
|
||||
## Stack and shape
|
||||
|
||||
Astro 5 (SSR, Node standalone) with React islands · PostgreSQL · `sharp` ·
|
||||
`pdf-lib` · `pg-boss` · OKLCH design tokens, no Tailwind. Files go to a volume by
|
||||
default; S3/MinIO is available but not required.
|
||||
|
||||
About 13,600 lines across 116 files, 124 tests, 16 forward-only idempotent
|
||||
migrations that run themselves on boot. English and German interface, 1,038
|
||||
translated strings; the English sentence is the translation key, so there is no key
|
||||
file to keep in sync.
|
||||
|
||||
## Install
|
||||
|
||||
**Docker (recommended).** `docker-compose.yaml` is the print-only stack: the app
|
||||
and Postgres, files on a volume. `docker-compose.full.yaml` adds MinIO and turns
|
||||
every module on. Both read their secrets from `.env` and refuse to start rather than
|
||||
boot with a default password.
|
||||
|
||||
**From source.**
|
||||
|
||||
```bash
|
||||
npm install
|
||||
cp .env.example .env
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Migrations and first-run setup happen on the first request. There are no built-in
|
||||
accounts: the first boot creates one administrator from `ADMIN_USERNAME` /
|
||||
`ADMIN_PASSWORD`, or generates a password and prints it to the log once.
|
||||
|
||||
**Behind a reverse proxy**, set `PUBLIC_BASE_URL` to the address the browser sees.
|
||||
Coolify users: both compose files carry a commented `SERVICE_FQDN_APP_4321` line.
|
||||
|
||||
## For agents and scripts
|
||||
|
||||
`GET /llms.txt` describes the whole API in a form a model can read. `/api/*` accepts
|
||||
a `Bearer` token from the admin area. `mcp/` contains an MCP server, so an assistant
|
||||
can lay out and fetch a print sheet directly — `exact_size` and `print_sheet` are
|
||||
the two tools worth knowing.
|
||||
|
||||
## Contributing
|
||||
|
||||
Issues and pull requests are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for
|
||||
how the code is laid out and what the house style is. Security reports go to the
|
||||
address in [SECURITY.md](SECURITY.md), not to the issue tracker.
|
||||
|
||||
## Licence
|
||||
|
||||
[GNU AGPL-3.0](LICENSE). Use it, change it, run it for yourself or for others — if
|
||||
you run a modified version as a service, the people using it get your changes too.
|
||||
|
||||
Klarbild grew out of a private tool for getting family photos onto paper at the
|
||||
right size. It is maintained by [Till Heidrich](https://github.com/tillheidrich).
|
||||
Reference in new issue
Block a user