Contracts / Typografie
Auf einen Blick
Abschnitt betitelt „Auf einen Blick“Die Typografie-Domäne umfasst den Vertrag der Schriftarten-Registry sowie die Verträge für die Textvorverarbeitung: FontRegistryInterface, TextPreprocessorInterface und die unveränderlichen Wertobjekte TextPreprocessResult und TextSegment. Alle sind stable.
Installation
Abschnitt betitelt „Installation“composer require nextpdf/core:^3Konzeptioneller Überblick
Abschnitt betitelt „Konzeptioneller Überblick“FontRegistryInterface definiert den prozessweiten Speicher für Schriftarten. Die Registry registriert eine TrueType-, OpenType-, TTC- oder PFB-Schriftart und gibt geparste FontInfo-Metadaten zurück. Sie überdauert einzelne Dokumente, sodass ein Worker jede Schriftart nur einmal parsen muss. Beim Boot kann sie eine Gruppe von Schriftarten vorwärmen und danach gesperrt werden, damit Produktions-Traffic sie nicht mehr verändern kann. Eine gesperrte Registry wirft eine LogicException, sobald register(), addFontDirectory() oder warmup() aufgerufen wird, während Lookups weiterhin verfügbar bleiben. Die Registry nimmt eine Schriftart auch aus reinen Binärdaten über registerFromBinary() entgegen. Die @font-face-Brücke nutzt diese Methode, um eine aus einer entfernten Quelle oder einer Daten-URI geladene Schriftart zu registrieren. Die Registry hält nur reine PHP-Daten — keine Ressourcen-Handles —, deshalb können Sie sie gefahrlos über einen Worker-Pool hinweg teilen.
Die Engine bettet jede verwendete Schriftart ein und erstellt davon ein Subset. Ein eingebettetes Schriftartprogramm wird im PDF mitgeführt, sodass das Dokument in jedem Viewer gleich rendert, unabhängig von installierten Systemschriftarten — ISO 32000-2 §9. Ein Schriftart-Subset enthält nur die Glyphen, die das Dokument tatsächlich referenziert; das ist für CJK-Inhalte oder Unicode-reiche Inhalte entscheidend — ISO 32000-2 §9. Der Vertrag der Registry stellt die geparsten Metadaten bereit, die die Subset- und Einbettungsstufen verwenden.
TextPreprocessorInterface verarbeitet Text, bevor er in Glyphen-Layout, Schriftart-Subsetting, die ToUnicode-CMap und den Strukturbaum gelangt. Genau aus dieser Platzierung ergibt sich die Sicherheitseigenschaft: Ein Präprozessor, der Inhalte schwärzt, entfernt sie, bevor sie den Content-Stream, das Schriftart-Subset oder die Metadaten erreichen können. Der Vertrag legt zwei Invarianten fest. Ein Präprozessor darf keine layoutbeeinflussenden Zeichen einführen und muss die logische Lesereihenfolge bewahren; seine Aufgabe ist Inhaltsersetzung, nicht Layout. Das Ergebnis ist ein unveränderliches TextPreprocessResult, das eine geordnete Liste von TextSegment-Werten enthält. Ein Segment wird entweder unverändert durchgereicht oder geschwärzt. Bei einem geschwärzten Segment hängt der Anzeigetext vom Maskierungsmodus ab: leer für ein Black-Box-Rechteck, Sternchen entsprechend der ursprünglichen Länge oder ein festes Label. Der originalCharCount eines Segments ist ein nicht umkehrbarer Messhinweis, der nur zur Dimensionierung eines Schwärzungsrechtecks dient. Er darf niemals dazu verwendet werden, den ursprünglichen Inhalt zu rekonstruieren.
API-Oberfläche
Abschnitt betitelt „API-Oberfläche“| Typ | Art | Wichtige Member | Stabilität | Seit |
|---|---|---|---|---|
FontRegistryInterface | interface | register(), get(), has(), all(), addFontDirectory(), warmup(), lock(), isLocked(), registerBase14(), registerFromBinary(), memoryUsage() | stable | 1.7.0 |
TextPreprocessorInterface | interface | process(string): TextPreprocessResult | stable | 1.9.0 |
TextPreprocessResult | final readonly class | $segments, hasRedactions(), getDisplayText() | stable | 1.9.0 |
TextSegment | final readonly class | $displayText, $isRedacted, $originalCharCount, $fillColor | stable | 1.9.0 |
Die Konstruktorsignaturen und öffentlichen Eigenschaften von TextPreprocessResult und TextSegment sind eingefroren; neue Methoden dürfen hinzukommen, Eigenschaften dürfen sich nicht ändern.
Codebeispiel — Schnellstart
Abschnitt betitelt „Codebeispiel — Schnellstart“<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->addPage();$doc->setFont('helvetica', 'B', 18);$doc->cell(0, 12, 'Bold heading', newLine: true);$doc->setFont('helvetica', '', 11);$doc->multiCell(0, 7, 'Body text rendered with a registered font.');$doc->save(__DIR__ . '/output/04-text-and-fonts.pdf');setFont() löst die Familie über FontRegistryInterface auf. Das eigenständige Dokument nutzt eine private Registry. Worker teilen sich eine gemeinsame Registry (siehe die Dokument-Seite).
Codebeispiel — Produktion
Abschnitt betitelt „Codebeispiel — Produktion“<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\FontRegistryInterface;use NextPDF\Contracts\TextPreprocessorInterface;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final readonly class FontWarmupService{ public function __construct( private FontRegistryInterface $fonts, private TextPreprocessorInterface $preprocessor, private LoggerInterface $logger, ) {}
/** * Warm a font set at boot, then lock the registry. * * @param list<string> $fontFiles Absolute paths to font files. */ public function boot(array $fontFiles): void { try { $this->fonts->warmup($fontFiles); $this->fonts->lock(); } catch (NextPdfException $e) { $this->logger->error('Font warmup failed', ['error' => $e->getMessage()]);
throw $e; } }
public function redact(string $text): string { $result = $this->preprocessor->process($text);
return $result->hasRedactions() ? $result->getDisplayText() : $text; }}Die Sequenz aus warmup() und anschließend lock() ist die Boot-Sequenz des Workers. Nach lock() wirft jeder Mutationsaufruf eine Exception. Lookups bedienen weiterhin den Traffic.
Randfälle & Stolperfallen
Abschnitt betitelt „Randfälle & Stolperfallen“- Eine gesperrte Registry weist jede Mutationsmethode zurück. Wärmen Sie beim Boot vor und sperren Sie danach; rufen Sie
register()niemals während der Request-Verarbeitung auf. registerFromBinary()schreibt die Schriftart-Bytes zum Parsen in eine temporäre Datei. Nicht vertrauenswürdige Schriftartdaten sind beim Parsen eine Angriffsfläche — leiten Sie sie durch einExternalResourcePolicyInterface(siehe die Seite zur Sicherheitsrichtlinie).- Ein
TextPreprocessordarf keine Zeilenumbrüche, Wagenrückläufe oder Tabs hinzufügen. Das verändert das Layout und bricht die erste Invariante des Vertrags. TextSegment::$originalCharCountist nur ein Breitenhinweis. Wird er genutzt, um auf den ursprünglichen Inhalt zu schließen, hebelt das die Schwärzung aus und verletzt die dritte Invariante des Vertrags.TextPreprocessResult::getDisplayText()gibt für Black-Box-Segmente bewusst eine leere Zeichenkette zurück. Behandeln Sie ein leeres Segment nicht als Vorverarbeitungsfehler.
Performance
Abschnitt betitelt „Performance“Das Parsen der Schriftart dominiert die erstmalige Nutzung; die Registry amortisiert diesen Aufwand auf einmaliges Parsen pro Prozess. Nach dem Warmup sind get() und has() O(1)-Map-Lookups. memoryUsage() gibt einen MemoryReport zurück, damit ein Worker den Schriftart-Cache im Verhältnis zu seinem Budget überwachen kann. Die Textvorverarbeitung ist linear zur Eingabelänge. Die Segmentliste fügt einen begrenzten Overhead hinzu, proportional zur Anzahl der Schwärzungstreffer. Das performance_budget von 1500 ms Wall-Time und 64 MB Spitzenverbrauch deckt ein Warmup eines typischen Schriftartensatzes plus das Rendern des Dokuments ab. Die Subsetting-Kosten skalieren mit der Anzahl der tatsächlich verwendeten Glyphen, nicht mit der vollständigen Glyphentabelle der Schriftart. Subsetting reduziert daher die Ausgabegröße und die Renderkosten für CJK-Inhalte.
Sicherheitshinweise
Abschnitt betitelt „Sicherheitshinweise“Die Typografie-Domäne hat zwei sicherheitsrelevante Oberflächen. Die erste ist die Schriftarteingabe: registerFromBinary() parst beliebige Bytes. Nicht vertrauenswürdige Schriftartdaten müssen ein ExternalResourcePolicyInterface passieren, das Dateigröße und Glyphenanzahl begrenzt, bevor sie den Parser erreichen. Die zweite ist die Schwärzung: TextPreprocessorInterface ist vor Glyphen-Layout, Schriftart-Subsetting, der ToUnicode-CMap und dem Strukturbaum positioniert, und zwar genau deshalb, damit geschwärzter Inhalt niemals in das gerenderte Artefakt gelangt. Eine als Overlay zur Zeichenzeit umgesetzte Schwärzung gibt den ursprünglichen Text im Content-Stream und im Subset preis. Die Platzierung des Vertrags verhindert diese Fehlerklasse. Der Messhinweis eines Segments ist bewusst nicht umkehrbar. Behandeln Sie jede extern bereitgestellte Schriftart und jeden extern bereitgestellten Text als nicht vertrauenswürdig.
Konformität
Abschnitt betitelt „Konformität“| Aussage | Standard | Abschnitt | Nachweis |
|---|---|---|---|
| Jede vom Dokument verwendete Schriftart ist eingebettet, sodass das Dokument gerendert wird, ohne auf Systemschriftarten angewiesen zu sein. | ISO 32000-2 | §9 | |
| Die eingebettete Schriftart wird auf die Glyphen reduziert, die das Dokument referenziert. | ISO 32000-2 | §9 |
Beide Klauseln sind paraphrasiert. NextPDF gibt keinen normativen Text wieder. PDF/A-4 schreibt die Einbettung für jede Schriftart vor. Diese Konformität ist auf den Seiten zu Extraktion und Barrierefreiheit dokumentiert.
Siehe auch
Abschnitt betitelt „Siehe auch“- Contracts: 41 öffentliche Interfaces (SPI) — der SPI-Überblick und die Stabilitätsstufen.
- Contracts / Document — die Rolle der Registry im Lebenszyklus des Dokuments.
- Contracts / Security Policy —
ExternalResourcePolicyInterfacebegrenzt nicht vertrauenswürdige Schriftart-Bytes. - Typografie — das Modul für Text-Shaping und Layout.
- Font — Parsen, Subsetting und Einbetten von Schriftarten.
- Text — Textausgabe, die Präprozessor-Ergebnisse verbraucht.