--- title: 'Hook-Referenz: Templates und Medien' description: 'tpl, image und pdf im Hook-JS: Signaturen aus internal/hook, je ein Beispiel und je ein belegter Fehlerfall.' --- In Hooks sprichst du diese drei Pakete über `context` an, z. B. `context.tpl.execute(...)` oder `context.pdf.fromHTML(...)`. Die Signaturen stammen aus den `// args:`- bzw. `// JS signature:`-Kommentaren in `internal/hook/context_*.go` im tibi-server; wo so ein Kommentar fehlt, ist die Signatur aus Funktionsrumpf und Options-Auswertung abgeleitet und entsprechend markiert. Jede Funktion zeigt genau einen Fehlerfall mit dem originalen Error-Text aus dem Code (Status-Code aus den Hook-Tests, meist `500`). ## tpl – Templates rendern Quelle: `context_tpl.go`, registriert per `RegisterPackageFunctions("tpl", ...)` mit `execute`. Rendert Pongo2-Templates (Django/Jinja2-Syntax); übergebene Funktionen in `contextData` bleiben aufrufbar (`WrapFunctions`). ### tpl.execute **Signatur:** `tpl.execute(code: string, contextData?: object): string` — aus `// args: code:string, contextData:map[string]interface{}` (`context_tpl.go:17`). `contextData` ist optional; ohne Daten renderst du statischen Text. ```js title="tpl.execute – Beispiel" ;(function () { const html = context.tpl.execute("Hallo {{ name }}! Du hast {{ count }} Nachrichten.", { name: "John", count: 5 }) throw { status: 200, json: { html: html } } })() ``` **Fehlerfall (Error):** Aufruf ohne Code brichst du mit `missing code in tpl.execute function` ab (`context_tpl.go:20`); ein `contextData` vom falschen Typ meldet `contextData must be object in tpl.execute function` (`context_tpl.go:34`). Der erste Fall ist durch Tests belegt und endet mit Status `500` (`error - missing code`, `context_tpl_test.go:78`). ## image – Bilder verarbeiten Quelle: `context_image.go`, registriert per `RegisterPackageFunctions("image", ...)` mit `filter`. Beide Pfade werden per `CleanFilePath` gegen das Config-Verzeichnis aufgelöst. Die Funktion gibt nichts zurück (`nil`). ### image.filter **Signatur:** `image.filter(sourceFilename: string, targetFilename: string, filters: Array): void` — aus `// args: sourceFilename:string targetFilename:string filters:[]interface{}` (`context_image.go:18`). Jedes Filter-Objekt ist optional bestückt: `width`, `height`, `fit`, `fill`, `resampling`, `anchor`, `brightness`, `saturation`, `contrast`, `gamma`, `blur`, `sharpen`, `invert`, `grayscale`, `quality`, `lossless`, `skipLargerDimension`, `skipLargerFilesize`, `outputType`. ```js title="image.filter – Beispiel" ;(function () { context.image.filter("uploads/foto.jpg", "uploads/foto-klein.webp", [ { width: 800, fit: true, quality: 80, outputType: "webp" } ]) throw { status: 200, json: { filtered: true } } })() ``` **Fehlerfall (Error):** Weniger als drei Argumente: `missing sourceFile, targetFile and filters in image.filter function` (`context_image.go:43`); ein leeres Filter-Array: `filters is empty array in image.filter function` (`context_image.go:73`); ein Filter-Eintrag, der kein Objekt ist: `filter index %d is not an object in image.filter function` (`context_image.go:236`). ## pdf – PDFs erzeugen und bearbeiten Quelle: `context_pdf.go`, registriert per `RegisterPackageFunctions("pdf", ...)` mit `fromHTML`, `cpu`. Beide Funktionen liefern PDF-Bytes zurück. ### pdf.fromHTML **Signatur (abgeleitet):** `pdf.fromHTML(html: string, options?: object): bytes` — kein `args:`-Kommentar (nur `// get request object`, `context_pdf.go:28`), abgeleitet aus dem Rumpf (`context_pdf.go:29`): `html` ist Pflicht, `options` optional. `options` kennt unter anderem `orientation` (`Portrait` oder `Landscape`), `marginTop`, `marginBottom`, `marginLeft`, `marginRight`, `dpi`, `title`, `headerHTML`, `footerHTML` und `printMediaType`. ```js title="pdf.fromHTML – Beispiel" ;(function () { const pdfBytes = context.pdf.fromHTML("

Report

", { orientation: "Portrait", marginTop: 10, title: "Report" }) throw { status: 200, bytes: pdfBytes } })() ``` **Fehlerfall (Error):** Aufruf ohne HTML: `missing html in pdf.fromHTML` (`context_pdf.go:31`); ein `orientation`-Wert ungleich `Portrait`/`Landscape`: `orientation is not Portrait or Landscape` (`context_pdf.go:152`). ### pdf.cpu **Signatur (abgeleitet):** `pdf.cpu(command: string, pdfData: bytes | Array | object, options?: object): bytes` — kein `args:`-Kommentar, abgeleitet aus dem Rumpf (`context_pdf.go:249`). Kommandos: `create`, `rotate`, `merge`, `stamp`, `watermark`; `merge` nimmt ein Byte-Array, `create` zusätzlich ein JSON-Objekt als Bauplan. Wichtige `options`: `rotation` (Integer-Literal, für `rotate` — goja übergibt Ganzzahlen als `int64`, Fließkomma wie `90.0` scheitert mit `rotation option must be integer in pdf.cpu`), `pages` (Array), `mode` (`text`, `image` oder `pdf` für `stamp`/`watermark`), `text`, `bytes`, `file`, `description`. ```js title="pdf.cpu – Beispiel" ;(function () { const base = context.pdf.fromHTML("

Hi

") const rotated = context.pdf.cpu("rotate", base, { rotation: 90 }) throw { status: 200, bytes: rotated } })() ``` **Fehlerfall (Error):** Aufruf ohne Kommando: `missing command in pdf.cpu` (`context_pdf.go:251`); ohne PDF-Daten: `missing pdf input in pdf.cpu` (`context_pdf.go:254`); ein unbekanntes Kommando meldet ` is unkown command in pdf.cpu` — so wörtlich im Code, inklusive Tippfehler (`context_pdf.go:446`). Weiter: [Hook-Kontexte](/reference/hook-kontexte/) als Paket-Index, [Hooks schreiben](/projekt/hooks-schreiben/) für Lifecycle und Starter-Muster. Verifiziert am 68b42785 2026-10-16 (tibi-server)