Kostenlos entwickeln und testen

Die Full-Stack-PDF-Bibliothek

brevier ist in Python geschrieben. Es erzeugt PDFs aus den einfachsten Web-Werkzeugen: HTML, CSS, JSON und Handlebars. Oder Sie schreiben die Vorlage in Markdown, das KI-Agenten mühelos lesen und schreiben.

pip install brevier
Beispiel wählen
rechnung

rechnung/rechnung.html

<!DOCTYPE html>
<html lang="de">
<head><meta charset="utf-8"><title>Rechnung {{ rechnung.nummer }}</title></head>
<body>
  <p class="absender">{{ firma.name }}, {{ firma.anschrift }}</p>
  <address>{{ kunde.name }}<br>{{ kunde.strasse }}<br>{{ kunde.ort }}</address>

  <h1>Beitragsrechnung {{ rechnung.nummer }}</h1>
  <p>Datum: {{ rechnung.datum | date }}</p>

  <table>
    <thead>
      <tr><th>Pos.</th><th>Leistung</th><th>Betrag</th></tr>
    </thead>
    <tbody>
      {{#each rechnung.positionen}}
      <tr><td>{{ pos }}</td><td>{{ text }}</td><td>{{ betrag | money }}</td></tr>
      {{/each}}
    </tbody>
  </table>
  <p class="summe">Summe {{ rechnung.summe | money }}</p>
</body>
</html>

rechnung/rechnung.css

@page {
  size: A4;
  margin: 25mm 20mm 25mm 25mm;
  @bottom-right {
    content: "Seite " counter(page) " von " counter(pages);
    font: 8pt sans-serif;
  }
}
body { font: 10pt/1.4 sans-serif; color: #16181c; }
.absender { font-size: 7pt; border-bottom: 0.5pt solid #16181c; }
address { font-style: normal; margin: 2mm 0 20mm; }
h1 { font-size: 14pt; }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; border-bottom: 1pt solid #16181c; }
td { padding: 1.5mm 0; border-bottom: 0.5pt solid #d5d9df; }
td:first-child { width: 14mm; }
td:nth-child(2) { width: 34mm; }
td:last-child, th:last-child { text-align: right; }
.summe { text-align: right; font-weight: bold; }

rechnung/rechnung.json

{
  "firma": { "name": "Muster Versicherung AG", "anschrift": "Hauptstraße 1, 10115 Berlin" },
  "kunde": { "name": "Erika Mustermann", "strasse": "Beispielweg 7", "ort": "50667 Köln" },
  "rechnung": {
    "nummer": "R-2026-0142",
    "datum": "2026-09-25",
    "positionen": [
      { "pos": 1, "text": "Berufsunfähigkeitsversicherung", "betrag": 84.2 },
      { "pos": 2, "text": "Haftpflichtversicherung", "betrag": 7.9 },
      { "pos": 3, "text": "Hausratversicherung", "betrag": 12.4 }
    ],
    "summe": 104.5
  }
}

rechnung/rechnung.schema.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "firma": { "$ref": "#/$defs/Firma" },
    "kunde": { "$ref": "#/$defs/Kunde" },
    "rechnung": { "$ref": "#/$defs/Rechnung" }
  },
  "required": ["firma", "kunde", "rechnung"],
  "$defs": {
    "Firma": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "anschrift": { "type": "string" }
      },
      "required": ["name", "anschrift"]
    },
    "Kunde": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "strasse": { "type": "string" },
        "ort": { "type": "string" }
      },
      "required": ["name", "strasse", "ort"]
    },
    "Rechnung": {
      "type": "object",
      "properties": {
        "nummer": { "type": "string", "title": "Rechnungsnummer" },
        "datum": { "type": "string", "format": "date", "title": "Rechnungsdatum" },
        "positionen": { "type": "array", "items": { "$ref": "#/$defs/Position" } },
        "summe": { "type": "number", "format": "decimal", "title": "Gesamtbetrag" }
      },
      "required": ["nummer", "datum", "positionen", "summe"]
    },
    "Position": {
      "type": "object",
      "properties": {
        "pos": { "type": "integer" },
        "text": { "type": "string" },
        "betrag": { "type": "number", "format": "decimal" }
      },
      "required": ["pos", "text", "betrag"]
    }
  }
}

rechnung/rechnung.pdf

Seite 1 der Rechnung, so wie brevier sie aus diesen Dateien erzeugt hat.
rechnung

rechnung/rechnung.md

---
style: rechnung.css
---

{{ firma.name }}, {{ firma.anschrift }}

An: {{ kunde.name }}, {{ kunde.strasse }}, {{ kunde.ort }}

# Beitragsrechnung {{ rechnung.nummer }}

Datum: {{ rechnung.datum | date }}

| Pos. | Leistung | Betrag |
| --- | --- | ---: |
{{#each rechnung.positionen}}
| {{ pos }} | {{ text }} | {{ betrag | money }} |
{{/each}}

**Summe {{ rechnung.summe | money }}**

rechnung/rechnung.css

@page {
  size: A4;
  margin: 25mm 20mm 25mm 25mm;
  @bottom-right {
    content: "Seite " counter(page) " von " counter(pages);
    font: 8pt sans-serif;
  }
}
body { font: 10pt/1.4 sans-serif; color: #16181c; }
.absender { font-size: 7pt; border-bottom: 0.5pt solid #16181c; }
address { font-style: normal; margin: 2mm 0 20mm; }
h1 { font-size: 14pt; }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; border-bottom: 1pt solid #16181c; }
td { padding: 1.5mm 0; border-bottom: 0.5pt solid #d5d9df; }
td:first-child { width: 14mm; }
td:nth-child(2) { width: 34mm; }
td:last-child, th:last-child { text-align: right; }
.summe { text-align: right; font-weight: bold; }

rechnung/rechnung.json

{
  "firma": { "name": "Muster Versicherung AG", "anschrift": "Hauptstraße 1, 10115 Berlin" },
  "kunde": { "name": "Erika Mustermann", "strasse": "Beispielweg 7", "ort": "50667 Köln" },
  "rechnung": {
    "nummer": "R-2026-0142",
    "datum": "2026-09-25",
    "positionen": [
      { "pos": 1, "text": "Berufsunfähigkeitsversicherung", "betrag": 84.2 },
      { "pos": 2, "text": "Haftpflichtversicherung", "betrag": 7.9 },
      { "pos": 3, "text": "Hausratversicherung", "betrag": 12.4 }
    ],
    "summe": 104.5
  }
}
src/main/java

src/main/java/RechnungService.java

import com.brevier.Brevier;

public class RechnungService {

    public byte[] pdf(Firma firma, Rechnung rechnung, Kunde kunde) {
        return Brevier.template("rechnung")
                      .render(firma, rechnung, kunde);
    }
}
app

app/rechnung.py

import brevier


def pdf(firma, rechnung, kunde) -> bytes:
    return brevier.template("rechnung").render(firma, rechnung, kunde)

Alles, was ein Geschäftsdokument braucht

brevier kümmert sich um die Druckregeln. Sie kümmern sich um Ihre Daten.

  • Vorlagen in HTML und CSS

    Die Seite ist HTML mit CSS. Kein proprietäres Format, kein Zeichencode.

  • Markdown für einfache Dokumente

    Schreiben Sie einen Brief in Markdown mit Front Matter. brevier eject macht daraus das HTML, in das er übersetzt wird.

  • Datenbindung

    Handlebars-Syntax bindet JSON in die Vorlage: Werte, Schleifen und Bedingungen.

  • Vorlagen gegen ein Schema geprüft

    Ein falsch geschriebenes Feld fällt bei der Prüfung auf, bevor etwas gedruckt wird.

  • from-code: Start bei Ihren Klassen

    Liest Java-Klassen oder Python-Modelle und schreibt ein Schema, eine Vorlage und Beispieldaten.

  • Die sichtbare Mitte

    --emit-html schreibt genau das HTML, das die Engine erhalten hat, und --format html rendert eine Webansicht desselben Dokuments.

  • Deutsche und englische Silbentrennung

    Komposita werden an der Fuge getrennt: Berufsunfähigkeits-versicherung, nicht Beruf-sunfähigkeit. Firmen ergänzen eigene Wörter.

  • Tabellen über mehrere Seiten

    Festgelegte Spaltenbreiten und ein Tabellenkopf, der auf jeder Seite wiederkehrt.

  • Übertrag

    Die laufende Summe steht unten auf jeder Seite und oben auf der nächsten.

  • Kopf- und Fußzeilen mit Seitenzähler

    Seite 3 von 12, in einem bearbeitbaren Block, auf jeder Seite.

  • Verträge und Kleingedrucktes

    Nummerierte Klauseln, ein Inhaltsverzeichnis mit Seitenzahlen und Kleingedrucktes, das lesbar bleibt. Keine Überschrift bleibt allein am Seitenende.

  • Alle Funktionen, jeweils mit Status

    Zur Funktionsliste

Ein Brevier ist ein Gebetbuch: das kleine Buch, das man immer bei sich hat und jeden Tag benutzt. Das will brevier für Entwickler sein, die Code schreiben müssen, der PDFs erzeugt. Ich musste diese Arbeit selbst machen, mit Werkzeugen, die es einem schwer machen. Deshalb habe ich brevier gebaut: damit PDF-Erzeugung für Entwickler einfach wird.

Liviu IonesiAutor von brevier

Gebaut auf dem, was Sie schon kennen

HTML, CSS, JSON und Ihr eigener Code. Nichts Neues zu lernen.

  • HTML für die Seite

    Die Vorlage ist eine HTML-Seite. Handlebars füllt sie mit Ihren Daten: Werte, Schleifen und Bedingungen.

    developer.mozilla.org
  • CSS für das Aussehen

    CSS bestimmt Schriften und Farben und auch die gedruckte Seite: Format, Ränder, Kopf- und Fußzeilen, Seitenzahlen.

    CSS @page
  • JSON für die Daten

    Ihre Daten kommen als JSON. Ein JSON Schema prüft jedes Feld, bevor etwas gedruckt wird.

    json-schema.org
  • Ihr eigener Code

    Übergeben Sie die Objekte, die Sie schon haben, aus Java, Python und anderen Sprachen. brevier macht daraus die Daten.

    Zu den Clients

Überall installieren

Installieren Sie brevier mit pip, einem Einzeiler-Skript oder Docker. Es läuft unter Linux, macOS und Windows.

Aus Ihrer Sprache aufrufen
Installationsweg wählen

Für Python-3-Nutzer. pip braucht die Bibliothek Pango auf Ihrem System.

  1. brevier installieren
    pip install brevier
  2. Prüfen, ob es läuft
    brevier --version
  3. Das Beispiel oben auf dieser Seite erzeugen
    brevier render rechnung.html --data rechnung.json -o rechnung.pdf

Das Skript installiert brevier in einem eigenen Ordner und legt den Befehl brevier in ~/.local/bin ab. Unter macOS installiert es auch Pango.

  1. brevier installieren
    curl -fsSL https://get.brevier.dev | sh
  2. Prüfen, ob es läuft
    brevier --version
  3. Das Beispiel oben auf dieser Seite erzeugen
    brevier render rechnung.html --data rechnung.json -o rechnung.pdf

Das PowerShell-Skript installiert Pango über MSYS2, dann brevier für Ihren Benutzer, und trägt es in Ihren PATH ein.

  1. brevier installieren
    iwr -useb https://get.brevier.dev/ps1 | iex
  2. Prüfen, ob es läuft
    brevier --version
  3. Das Beispiel oben auf dieser Seite erzeugen
    brevier render rechnung.html --data rechnung.json -o rechnung.pdf

Außer Docker ist nichts zu installieren. Das Image führt brevier in dem Ordner aus, den Sie unter /work einbinden.

  1. brevier installieren
    docker pull brevier/brevier:latest
  2. Prüfen, ob es läuft
    docker run --rm brevier/brevier --version
  3. Das Beispiel oben auf dieser Seite erzeugen
    docker run --rm -v "$PWD:/work" brevier/brevier render rechnung.html --data rechnung.json -o rechnung.pdf