Files
klarbild-oss/README.md
T
till a371646238
CI / check (push) Canceled after 0s
Container image / image (push) Canceled after 0s
1.1.0: changelog, README quick start without a clone, help and in-app changelog
The quick start downloads two files and pulls the image; no clone, no
build. README figures brought up to date (it still said Astro 5, 124
tests, 16 migrations). Upgrade notes for 1.0 installs: the volume
ownership change and the basic-ftp NAT behaviour. Help page and in-app
changelog in English and German.
2026-10-10 06:40:18 +00:00

194 lines
9.0 KiB
Markdown
Raw 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
**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.
**[Lay out a sheet in your browser →](https://klarbild-demo.heidrich-digital.de)** — the demo
page runs this repository's own layout engine client-side and hands you the PDF. No account,
nothing uploaded.
```bash
mkdir klarbild && cd klarbild
curl -fsSLO https://raw.githubusercontent.com/tillheidrich/klarbild/main/docker-compose.yaml
curl -fsSL https://raw.githubusercontent.com/tillheidrich/klarbild/main/.env.example -o .env
nano .env # four values at the top; the file says which
docker compose up -d
docker compose logs app # your admin password is printed here, once
```
No clone, no build: the compose file pulls a prebuilt image for amd64 and arm64
(a Raspberry Pi 4 or 5 runs it). Open `http://localhost:4321`, sign in, and press
**Try it with a sample photo** if you have no picture at hand.
![Klarbild's print studio: eight passport photos laid out on one A4 sheet with corner marks](docs/screenshots/print-studio.png)
---
## 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 A1 — 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 — plus the library, with folders, flags and a 30-day trash | a key for an images API (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.
![The studio with the AI module on: four tasks, saved presets, exact output size](docs/screenshots/studio.png)
### Which image model
The `ai` module posts to `{IMAGE_API_BASE_URL}/images` in the OpenAI image shape.
The default base is OpenRouter — one key, many models, and the model list in the
admin area fills itself in. Point `IMAGE_API_BASE_URL` at a LiteLLM gateway, a
company proxy or a server of your own and Klarbild talks to that instead; you then
type the model id rather than picking it from a list. Either way the pictures go to
exactly one endpoint and you chose which.
## 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 7 (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,800 lines across 115 files, 130 tests, 17 forward-only idempotent
migrations that run themselves on boot. English and German interface — 1,095
entries, covering every translatable string in the source. The English sentence is
the translation key, so there is no key file to keep in sync and a missing entry
degrades to readable English rather than to `print.sheet.title`.
## 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.
Both pull `ghcr.io/tillheidrich/klarbild:1`, which follows every 1.x release.
Updating is
```bash
docker compose pull && docker compose up -d
```
and the migrations run themselves on the next boot. The container runs as uid
1000, not root. Prefer to build the image yourself? Swap the `image:` line in the
compose file for `build: .` and run it from a clone.
**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
[klarbild-demo.heidrich-digital.de](https://klarbild-demo.heidrich-digital.de) is the product
page.
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).