--- // Öffentliche Vorstellungsseite für das Druckmodul. // Bewusst ohne Login und ohne Bedienelemente: Sie zeigt, was das Werkzeug kann, // man kann es hier aber nicht benutzen. Gedacht als Landeseite für ein // Open-Source-Release (Gitea/GitHub) und zum Herzeigen. import Base from '../layouts/Base.astro'; import { PHOTO_SIZES, PAPERS } from '../lib/paper'; import { layout, cutMarks, type SheetSpec } from '../lib/printlayout'; const anzahlFormate = PHOTO_SIZES.length; const anzahlPapiere = PAPERS.length; const anzahlGruppen = new Set(PHOTO_SIZES.map((p) => p.group)).size; const koennen = [ { kicker: 'Maßhaltig', titel: 'Millimeter statt „ungefähr“', text: 'Jedes Endmaß wird in Millimetern gerechnet und erst beim Rendern in Pixel umgesetzt. ' + 'Das PDF hat exakt das Bogenmaß, jedes Bild darin exakt sein Zielmaß. Nachgemessen wird nicht geschätzt, ' + 'sondern gemessen: Wir rastern die fertigen PDFs mit 254 dpi und zählen die Pixelkanten nach.', beleg: '13 × 18 cm → gemessen 130,1 × 180,1 mm', }, { kicker: 'Platz', titel: 'Mehrere Bilder auf einen Bogen', text: 'Gleich große Bilder kommen in ein exaktes Raster. Bei gemischten Formaten sucht ein Packer ' + '(MaxRects, „Best Short Side Fit“) die Anordnung mit den wenigsten Bogen — und probiert dafür jede ' + 'Kombination aus Hoch- und Querlage durch. Ein Passbild-Satz und ein 13 × 18 passen so auf dasselbe Blatt.', beleg: 'Kita-Satz: 9 Teile statt 3 auf einem A4-Bogen', }, { kicker: 'Schneiden', titel: 'Schnittmarken wie in der Druckvorstufe', text: 'Feine Eckmarken außerhalb jedes Bildes oder durchgehende Rasterlinien über den ganzen Bogen. ' + 'Die Linien werden dort unterbrochen, wo ein anderes Motiv liegt — es wird also nie quer über ein ' + 'Bild gezeichnet. Länge und Abstand sind einstellbar, Beschnittzugabe ebenso.', beleg: 'Eckmarken · durchgehendes Raster · Beschnittzugabe 0–10 mm', }, { kicker: 'Zu groß', titel: '20 × 30 auf A4 — trotzdem', text: 'Der Alltagsfall: Es soll ein 20 × 30 werden, im Haus liegt aber nur A4-Fotopapier. ' + 'Statt „geht nicht“ gibt es zwei Wege. Überstehen legt das Bild mittig aufs ganze Blatt; ' + 'was hinausragt, fehlt hinterher — und wie viel das ist, steht vorher da.', beleg: '20 × 30 cm auf A4: es fehlen genau 3 mm in der Höhe', }, { kicker: 'Poster', titel: 'Ein Bild, mehrere Blätter', text: 'Der zweite Weg für große Maße: Das Bild wird auf mehrere Blätter verteilt. Die Kacheln ' + 'überlappen sich um einen Klebefalz, der auf beiden Nachbarblättern gedruckt und gestrichelt ' + 'markiert wird. Jedes Blatt trägt seine Nummer samt Reihe und Spalte.', beleg: '30 × 40 cm auf A4 → 2 × 2 Blätter, 10 mm Klebefalz', }, { kicker: 'Zuschnitt', titel: 'Der Ausschnitt bleibt deiner', text: 'Passt das Seitenverhältnis nicht, entscheidest du: zuschneiden oder Rand lassen. ' + 'Im Zuschnitt-Fenster verschiebst und zoomst du das Original im Zielrahmen — mit Maus, Finger, ' + 'Doppeltipp oder Pfeiltasten. Der Ausschnitt wird relativ gespeichert und überlebt jede Auflösung.', beleg: 'EXIF-Drehung wird vorab eingerechnet — Handyfotos stehen richtig', }, ]; const daten = [ { zahl: String(anzahlFormate), label: 'Bildformate', fein: `in ${anzahlGruppen} Gruppen — Passbild bis 100 × 140 cm` }, { zahl: String(anzahlPapiere), label: 'Papierformate', fein: 'DIN A7–A0, Fotopapier, US-Maße, freies Maß' }, { zahl: '0', label: 'KI im Spiel', fein: 'reine Geometrie, kein Modell, kein Upload nach außen' }, { zahl: '1:1', label: 'Ausgabe', fein: 'PDF in Originalgröße, 72–1200 dpi' }, ]; // Der Beispielbogen unten wird nicht gezeichnet, sondern gerechnet — mit genau // demselben Packer, den das Werkzeug benutzt. Ändert sich der Algorithmus, // ändert sich das Bild auf dieser Seite mit. const musterBogen: SheetSpec = { wMm: 210, hMm: 297, marginMm: 5, gapMm: 8, bleedMm: 0, center: true }; const musterPlan = layout([ { id: 'gross', wMm: 130, hMm: 180, count: 1, allowRotate: true }, { id: 'klein', wMm: 90, hMm: 130, count: 1, allowRotate: true }, { id: 'pass', wMm: 35, hMm: 45, count: 6, allowRotate: true }, ], musterBogen); const musterSeite = musterPlan.pages[0]; const musterMarken = musterSeite ? cutMarks(musterSeite, musterBogen, { mode: 'corner', lengthMm: 3, offsetMm: 1 }) : []; const musterFarbe: Record = { gross: 'oklch(45% 0.23 267 / 0.09)', klein: 'oklch(45% 0.23 267 / 0.20)', pass: 'oklch(45% 0.23 267 / 0.34)', }; const musterAnzahl = musterSeite ? musterSeite.placements.length : 0; /** Kompaktes Maß fürs Kästchen: unter 10 cm in mm, sonst in cm. */ const kurzMass = (w: number, h: number) => w < 100 && h < 100 ? `${Math.round(w)}×${Math.round(h)}` : `${Math.round(w / 10)}×${Math.round(h / 10)} cm`; const schritte = [ { n: '01', t: 'Bilder wählen', d: 'Hochladen, aus der Bibliothek holen oder ein vorhandenes Bild duplizieren, um es in zwei Maßen zu drucken.' }, { n: '02', t: 'Maße setzen', d: 'Je Bild ein Zielmaß, Anzahl, Hoch oder Quer, zuschneiden oder Rand lassen.' }, { n: '03', t: 'Bogen einstellen', d: 'Papier, Schnittmarken, Ränder, Auflösung. Die Vorschau zeigt sofort, wie viele Bogen es werden.' }, { n: '04', t: 'Drucken', d: 'PDF erzeugen und im Druckdialog „Tatsächliche Größe / 100 %“ wählen. Fertig.' }, ]; ---

Klarbild · Druckmodul

Bilder auf exakte Maße bringen.
Ohne KI.

Ein Passbild ist 35 × 45 Millimeter. Ein Rahmen ist 13 × 18 Zentimeter. Beides sind Maße, keine Meinungen — und trotzdem ist es erstaunlich mühsam, ein Foto genau so aus dem Drucker zu bekommen. Dieses Werkzeug macht daraus einen Handgriff: Zielmaß eintragen, Ausschnitt wählen, PDF drucken. Millimetergenau, mit Schnittmarken, mehrere Bilder auf einem Blatt.

{daten.map((d) => (
{d.zahl} {d.label}

{d.fein}

))}

Das Problem

Der übliche Weg führt über ein Layoutprogramm oder über den Druckertreiber, und beide meinen es zu gut: „an Seitengröße anpassen“, „einpassen“, „randlos skalieren“. Am Ende liegt ein Ausdruck vor, der fast stimmt. Für ein Passbild ist „fast“ zu wenig, und für ein 4 × 3-Bildchen ein ganzes DIN-A4-Blatt zu verbrauchen, nur weil es sonst nicht in 100 % Größe auf die Seite passt, ist schlicht Verschwendung.

Klarbild Drucken rechnet stattdessen in Millimetern, packt so viele Bilder auf einen Bogen, wie hineingehen, und legt Schnittmarken dorthin, wo geschnitten wird. Was aus dem Drucker kommt, hat das Maß, das du eingetragen hast.

Ein Bogen, gerechnet

Ein 13 × 18, ein 9 × 13 und sechs Passbilder — auf einem einzigen DIN-A4-Bogen, alle in 100 % Größe, mit Eckmarken zum Schneiden. Diese Zeichnung ist kein Entwurf: Sie stammt aus demselben Packer, der auch das PDF erzeugt.

{musterSeite?.placements.map((pl) => ( {kurzMass(pl.w, pl.h)} ))} {musterMarken.map((l) => ( ))}
  • 1 × 13 × 18 cm
  • 1 × 9 × 13 cm
  • 6 × 35 × 45 mm
  • {musterAnzahl} Teile auf {musterPlan.pages.length} Bogen · 5 mm Rand · 8 mm Abstand

Was es kann

{koennen.map((k) => (

{k.kicker}

{k.titel}

{k.text}

{k.beleg}

))}

In vier Schritten

    {schritte.map((s) => (
  1. {s.n}{s.t}

    {s.d}

  2. ))}

Unter der Haube

Einheit
Millimeter. Pixel entstehen erst beim Rendern (px = mm / 25,4 × dpi), PDF-Punkte über mm / 25,4 × 72.
Rechenkern
Abhängigkeitsfreies TypeScript. Browser-Vorschau und Server-PDF benutzen buchstäblich denselben Code — was du siehst, wird gedruckt.
Packen
Exaktes Raster bei gleichen Maßen, MaxRects (Best Short Side Fit) bei gemischten. Bewertet nach wenigsten Bogen, vollster erster Seite, wenigsten Drehungen.
Bild
sharp in einer einzigen Kette: EXIF-Drehung, Ausschnitt, Skalierung, Rand. Der Zuschnitt wird relativ (0…1) gespeichert und ist damit auflösungsunabhängig.
PDF
pdf-lib. Seitengröße exakt das Bogenmaß, Bilder 1 : 1 platziert, Schnittmarken als Vektorlinien, Klebefalze gestrichelt.
Nachweis
Automatische Tests für die Geometrie plus Rasterprobe der fertigen PDFs bei 254 dpi (= 10 px/mm) mit Kantenmessung.

Selbst betreiben

Klarbild läuft auf einem eigenen Server: Astro mit Node, PostgreSQL, eine Warteschlange im selben Prozess, Dateien lokal oder auf S3. Das Druckmodul kommt ohne jeden externen Dienst aus — kein Modell, kein Schlüssel, keine Bilder, die das Haus verlassen. Wer nur drucken will, braucht die KI-Teile gar nicht erst zu konfigurieren.

Diese Seite ist eine Vorstellung, keine Bedienoberfläche — hier lässt sich nichts hochladen und nichts erzeugen.

Klarbild · Druckmodul