Dokumentation
PDFs erstellen
PDFs in Vue
PDFs in Nuxt
PDFs in React
PDFs in Angular
Daten und Assets
Ihre Daten
Ein Dokument ist eine Komponente, Ihre Daten kommen also als Props. map, Bedingungen, Ihre eigenen
Komponenten, Context - alles, was einen Baum erzeugt, wird zu einem PDF.
import { Divider, Document, Page, Row, Text } from "@jasy/react";
type Line = { id: number; name: string; price: number };
export function Statement({ lines }: { lines: Line[] }) {
const total = lines.reduce((sum, l) => sum + l.price, 0);
return (
<Document size={11}>
<Page size="A4" margin={48} gap={8}>
{lines.map((line) => (
<Row key={line.id} justify="between">
<Text>{line.name}</Text>
<Text>{line.price} EUR</Text>
</Row>
))}
<Divider />
<Row justify="between">
<Text bold>Total</Text>
<Text bold>{total} EUR</Text>
</Row>
</Page>
</Document>
);
}
Ein PDF wird einmal gerendert und nicht wie eine Seite am Leben gehalten: Laden Sie Ihre Daten vorrenderToPdf und übergeben Sie sie. Ein Effect, der nach dem ersten Render State setzt (useEffect, der
Daten holt), kommt zu spät - das Dokument ist dann schon gelesen.
Eigene Fonts
Die Standard-PDF-Fonts (Helvetica, Times, Courier) brauchen nichts. Für einen eigenen registrieren Sie den
Font unter einem Namen an <Document fonts> und verwenden diesen Namen dann als font. Im Browser holen
Sie zuerst die Bytes:
const inter = new Uint8Array(await (await fetch("/fonts/Inter.woff2")).arrayBuffer());
const bytes = await renderToPdf(<Report font={inter} />);
function Report({ font }: { font: Uint8Array }) {
return (
<Document fonts={{ Inter: font }} font="Inter">
<Page size="A4" margin={48}>
<Text size={24} bold>
Set in Inter
</Text>
</Page>
</Document>
);
}
Das Format spielt keine Rolle: .ttf, .woff und .woff2 sind hier dasselbe - jasy entpackt den
Wrapper selbst. Der Font wird auf dem Weg ins PDF gesubsettet, die Datei bleibt also klein. Für mehrere
Schriftstärken registrieren Sie eine Datei pro Stil: fonts={{ Inter: { normal, bold, italic } }}.
Auf einem Server funktioniert auch ein einfacher Pfad - fonts={{ Inter: "./fonts/Inter.woff2" }} ist
schon alles. Im Browser gibt es kein Dateisystem, auf das man zeigen könnte, also sind es Bytes.
Bilder
<Image src> nimmt die Bild-Bytes als Uint8Array, eine URL oder - auf einem Server - einen Pfad. JPEG und
PNG funktionieren beide, und die Transparenz eines PNG liegt über dem, was dahinter ist, nicht in einem
weißen Kasten.
const logo = new Uint8Array(await (await fetch("/logo.png")).arrayBuffer());
<Image src={logo} width={120} height={40} fit="contain" />;
Eine URL wird geladen, während das Dokument vorbereitet wird, noch vor dem Layout, ihre Größe ist also bekannt, wenn die Seite angeordnet wird.
Render-Optionen
renderToPdf (und renderToPdfString) nehmen die Render-Optionen der Engine als zweites Argument:
const bytes = await renderToPdf(<Invoice {...data} />, {
onOverflow: "warn",
accessible: true,
encrypt: { userPassword: "secret" },
onDiagnostic: (d) => console.log(d.code, d.message),
});
onOverflow- was passiert, wenn ein einzelnes unteilbares Element höher als die Seite ist:"error"(Standard) wirft,"warn"platziert es abgeschnitten und protokolliert,"ignore"platziert es abgeschnitten.accessible- ein getaggtes PDF mit Structure Tree für Screenreader, siehe Barrierefreiheit.encrypt- Passwortschutz mit AES-256, siehe Verschlüsselung.onDiagnostic- alles, was die Engine über das Dokument zu sagen hat, ein Aufruf pro Befund, siehe Ausgabeoptionen.
Ein Descriptor für einen Server
toDocumentDescriptor(element) hält vor dem PDF an und gibt den Descriptor der Engine zurück: einen
einfachen Baum { type, props, children }. Um ihn als JSON zu senden, kodieren Sie Font- und Bild-Bytes
selbst - JSON kennt kein Uint8Array - und dekodieren sie auf der anderen Seite. Funktionen überleben JSON
gar nicht, ein Dokument mit Canvas, Flow oder PageBuilder geht also über renderToPdf.