Files
bea-edit/plan/done/stamp-plan.md
T
2026-10-06 22:52:35 +02:00

140 lines
6.2 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.
# Plan: Stempeln — Textstempel auf PDFs
## Goal
Add a new tool **"Stempeln"** (`/tools/stamp`) that places opaque, framed text stamps on PDF
pages — "BEGLAUBIGT", "EILT", "ENTWURF", "KOPIE", "AUSFERTIGUNG", plus free text with an optional
date, or an image. This is a staple of German legal/case-file work and is deliberately separate from the
watermark tool:
- Watermark = semi-transparent, decorative/repetitive, many positions.
- Stamp = fully opaque, framed, authoritative marking, usually one per page.
Pure pdf-lib drawing (text + rectangle border): lossless, instant. No new dependencies.
---
## Open decisions (defaults marked ✅)
### D1 — Stamp look
- ✅ **A. Uppercase bold text inside a plain rectangle border** (2 pt border, padding 8 pt,
default color red `#cc1a1a`, matching the existing brand red used by the watermark default).
pdf-lib has no rounded-rectangle primitive; plain rectangle is the honest option.
- B. Borderless colored text. Possible but reads as a watermark, not a stamp.
### D2 — Presets
- ✅ **Editable preset chips + free text.** Chips: BEGLAUBIGT, AUSFERTIGUNG, KOPIE, EILT,
ENTWURF, ERLEDIGT. Selecting a chip fills the text input; the input stays editable. Optional
checkbox "Datum anhängen" appends `dd.mm.yyyy` (German format).
- B. Fixed presets only. Rejected: courts/firms love their own wording.
### D3 — Relation to the watermark tool
- ✅ **Separate tool**, sharing extracted helpers from `src/lib/pdf-overlay.ts`
(position coordinate computation + hex color parsing — see page-numbers-plan; whichever plan is
implemented first creates the module). Keeps discovery simple (one tile per job) and avoids
overloading the watermark UI with a mode switch.
---
## UX
- Route `/tools/stamp`, new `src/lib/tools.ts` entry:
`{ slug: 'stamp', title: 'Stempeln', description: 'Versehen Sie Seiten mit Textstempeln wie „Beglaubigt“ oder „Eilt“.', icon: 'stamp' }`
(`stamp` is a real Lucide icon name) + icon map entry.
- After load (`loadPdfDocument` for thumbnails):
- **Options card**:
- Preset chip row (buttons; selected chip highlighted).
- Text input (bound, default "BEGLAUBIGT"), "Datum anhängen" checkbox.
- Schriftgröße slider (12–48 pt, default 24).
- Farbe color input (default `#cc1a1a`).
- Position select — same six positions + center as watermark
(reuses shared position helper; no "diagonal" for stamps).
- Rotation slider (−45°…45°, default 0) — stamps are often applied slightly tilted.
- Apply-to: "Auf alle Seiten anwenden" checkbox + `PdfPageGrid` selection when off
(watermark pattern).
- **Live preview**: rendered current page (pdfjs) with an absolutely-positioned overlay div
styled like the stamp (border, uppercase, color, rotation) at the chosen position; page
navigation. Approximation is fine, same approach as page-numbers-plan.
- Primary button **"Stempel anwenden & herunterladen"** → `{baseName}_stempel.pdf`.
## Technical approach
### Export (pdf-lib)
```ts
const font = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
const stampText = `${textInput.trim().toUpperCase()}${withDate ? ` ${formatGermanDate(new Date())}` : ''}`;
const textWidth = font.widthOfTextAtSize(stampText, size);
const boxWidth = textWidth + 2 * padding;
const boxHeight = font.heightAtSize(size) + 2 * padding;
for (const pageIndex of targetPages) {
const { width, height } = pages[pageIndex].getSize();
const { x, y } = getPositionCoords(width, height, boxWidth, boxHeight, position); // shared helper
pages[pageIndex].drawRectangle({
x, y, width: boxWidth, height: boxHeight,
borderColor: parseHexColor(colorValue), borderWidth: 2
});
pages[pageIndex].drawText(stampText, {
x: x + padding, y: y + padding + /* baseline adjust */, size, font,
color: parseHexColor(colorValue), rotate: degrees(rotationValue)
});
}
```
Details:
- Rotation is applied to the text; the border rectangle stays axis-aligned for v1 (rotated
rectangles need manual path drawing — follow-up if users care).
- Baseline adjustment: use `font.heightAtSize(size) * 0.2` descent approximation; verify visually.
- Uppercasing happens in JS (`toUpperCase()` — German umlauts are fine in WinAnsi: ä/ö/ü/ß are
supported except ẞ; uppercase ß → SS via `toLocaleUpperCase('de')` acceptable).
- Encrypted input → German error + decrypt hint (shared pattern).
### Shared helpers
Depends on `src/lib/pdf-overlay.ts` (position presets + `parseHexColor`). If page-numbers or
stamp ships first, it creates the module and rewires watermark; the second consumer just imports.
## Files changed
- `src/routes/tools/stamp/+page.svelte` — new route.
- `src/lib/pdf-overlay.ts` — shared helpers (created here if not already present).
- `src/lib/tools.ts`, `src/routes/+page.svelte` — registry + icon map.
- `tests/e2e/toolbox.spec.ts` — spec block.
- `agents.md` — structure update.
## Implementation phases
1. Shared overlay helpers (or import if they exist) — watermark regression must stay green.
2. Route UI: presets, inputs, preview overlay, page selection.
3. Export + download.
4. Registry + icon.
5. Playwright: preset "EILT" on all pages of a 3-page PDF → output valid, 3 pages; custom text
- date checkbox adds text; selection-only mode leaves other pages unmodified (compare page
content-stream sizes via pdf-lib if practical, else file-level validity + count).
6. Polish + command gauntlet.
## Verification
- Every preset chip fills the input; the stamp renders uppercase in preview and output.
- Date uses German `dd.mm.yyyy` and updates on the export day (not cached).
- Rotation visually matches preview within tolerance.
- Watermark tool unchanged (regression).
## Risks
- **Text width overflow** on small pages with long custom text + huge font: clamp computed box to
page size minus margins and shrink font if needed (simple guard loop), with a German hint.
- Preview overlay approximation may differ a few points from export — acceptable, labeled.
## Out of scope
- Image stamps (logo stamps) — users can route through the watermark image mode for that.
- Rotated border rectangles, multi-stamps per page in one run (run the tool twice; output can be
re-loaded).
- Stamp "libraries" persisted across sessions.