Zum Inhalt springen

Content: textuelles + strukturiertes Inhaltsmodell

Das Content-Modul erzeugt Textanzeige-Operatoren, Textzustands-Operatoren, Textschatten, Dokument-JavaScript und Eigenschafts-Dictionarys für markierte Inhalte. Es bildet die Schicht zwischen Layout und Content-Stream.

Terminal-Fenster
composer require nextpdf/core:^3

Content enthält die Primitive, mit denen aufgelöster Text in PDF-Operatoren überführt wird. TextRenderer ist die zentrale Komponente. Er erzeugt den Textanzeige-Operator für einen String und die vorangestellten Textzustands-Operatoren. Der Operator Tj zeichnet die Glyphen eines Strings mit der aktuellen Schrift und den übrigen textbezogenen Grafikparametern — ISO 32000-2 §9. TextRenderer wählt anhand des aktiven TypographyMode zwischen einem einzelnen Anzeige-Operator und einem positionierten TJ-Array. Er wendet Kerning-Anpassungen an, wenn der Modus TJ-Arrays verwendet.

Der Textzustand ist vollständig modelliert. setTextRenderingMode() nimmt ein TextRenderingMode-Enum entgegen. Seine acht Fälle entsprechen eins zu eins den Textrendering-Modi nach ISO 32000-2: Fill, Stroke, Fill-then-stroke, Invisible und die vier Clip-Varianten (Tabelle 104). Der Renderer steuert außerdem Strichbreite, Zeichen- und Wortabstand, horizontale Streckung, Textversatz nach oben, Rechts-nach-links-Richtung und einen optionalen Hyphenator. Ein Aufruf von buildTextStateOperators() gibt den akkumulierten Zustand als einzelnen Operatorblock aus.

TextShadow ist ein Value Object — es umfasst Farbe, X- und Y-Versatz in Benutzereinheiten sowie Deckkraft. Der Renderer nutzt es, um einen zweiten, versetzten Zeichendurchlauf auszugeben. Die Standardversätze liegen bei dezenten 0,5/−0,5 mit 0,5 Deckkraft und ergeben einen weichen Schatten im CSS-Stil.

JavaScriptManager verwaltet das Scripting auf Dokumentebene. includeJs() registriert ein Dokument-Skript. addJsObject() registriert ein benanntes Skript-Objekt. writeJavaScript() / writeOpenAction() serialisieren die Skripte in den Katalog und die OpenAction. Der Manager prüft jeden Skript-Körper und kodiert ihn vor der Ausgabe als PDF-String.

PropertiesRegistry ist der Eigenschaftsspeicher für markierte Inhalte. register() gibt für ein Eigenschafts-Dictionary einen stabilen Tag-Index zurück. registerOcg() / registerOcgs() binden optionale Inhaltsgruppen über die Objektnummer ein. writeProperties() serialisiert die Registry in das Ressourcen-Dictionary der Seite. Das sind die Daten, auf die das ContentStream-Modul verweist, wenn es eine markierte Sequenz mit einer Eigenschaftsliste öffnet.

Zwei Bild-Decoder liegen hier, weil es sich um PDF-native Pass-through-Formate handelt. JBig2Loader und JpxLoader parsen JBIG2- und JPEG-2000-Segmentstrukturen und geben ImageData zurück, ohne jemals Pixel zu rastern. Die kodierten Bytes werden unverändert an den Viewer weitergereicht. Enthält eine JBIG2-Quelle ein separates Globals-Segment, bettet JBig2Loader es über eine /JBIG2Globals-Stream-Referenz am Bild-XObject ein; die in-stream/in-line-Form bleibt beim Round-Trip unverändert. Das ist reine strukturelle Verdrahtung — die Globals-Bytes werden ohne Rasterung durchgereicht, nicht dekodiert.

KlasseWichtige MethodenRolle
TextRendererbuildTextShowOperator(), buildTextStateOperators(), setTextRenderingMode(), setTextStrokeWidth(), setTextShadow(), setFontSpacing(), setWordSpacing(), setFontStretching(), setTextRise(), setRTL(), setHyphenation()Builder für Textanzeige- und Textzustands-Operatoren
TextRenderingMode (Enum)Fill, Stroke, FillStroke, Invisible, FillClip, StrokeClip, FillStrokeClip, ClipISO 32000-2 Textrendering-Modi
TextShadow__construct(Color, offsetX, offsetY, opacity)Value Object für den versetzten Zeichendurchlauf
JavaScriptManagerincludeJs(), addJsObject(), hasJavaScript(), writeJavaScript(), writeOpenAction()Verdrahtung von Dokument-JavaScript in den Katalog
PropertiesRegistryregister(), getTagIndex(), registerOcg(), registerOcgs(), getAll(), writeProperties()Eigenschaftsspeicher für markierte Inhalte und OCG
JBig2Loaderload(), loadFromString(), parseSegments()JBIG2-Pass-through-Decoder
JpxLoaderload(), loadFromString(), parseBoxes()JPEG-2000-Pass-through-Decoder

Führen Sie composer docs:generate-api-php -- --module=Content aus, um die vollständige PHPDoc-Tabelle zu erzeugen.

Quelle: examples/28-text-rendering.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Content\TextRenderer;
use NextPDF\Content\TextRenderingMode;
$renderer = new TextRenderer();
$renderer
->setTextRenderingMode(TextRenderingMode::FillStroke)
->setTextStrokeWidth(0.3)
->setWordSpacing(0.5);
$stateOps = $renderer->buildTextStateOperators();

Das Beispiel ergänzt einen weichen Schatten und einen Hyphenator und erstellt anschließend den Anzeige-Operator mit einer vom Aufrufer bereitgestellten Escape-Funktion (dem kanonischen PdfStringEscaper-Seam aus ADR-015).

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Content\TextRenderer;
use NextPDF\Content\TextShadow;
use NextPDF\Graphics\Color;
use NextPDF\Support\PdfStringEscaper;
$renderer = new TextRenderer();
$renderer
->setTextShadow(new TextShadow(Color::rgb(0, 0, 0), 0.4, -0.4, 0.45))
->setRTL(false);
$showOp = $renderer->buildTextShowOperator(
text: 'Quarterly report',
fontKey: 'F1',
metrics: $fontMetrics,
escapeSegment: static fn (string $s): string => PdfStringEscaper::escapeLiteral($s),
);
$pageContent = $renderer->buildTextStateOperators() . $showOp;
  • buildTextShowOperator() gibt bei leerer Eingabe einen leeren String zurück. Geben Sie keinen leeren Tj aus — sichern Sie das vorgelagert ab, falls Ihr Layout leere Läufe erzeugen kann.
  • Der Escape-Callback ist verpflichtend und für die String-Sicherheit verantwortlich. Übergeben Sie den kanonischen PdfStringEscaper::escapeLiteral() (ADR-015). Ein unvollständiger Escaper erzeugt einen syntaktisch defekten Literal-String.
  • TextShadow::offsetY ist bei einem Ursprung oben links nach unten negativ. Ein positiver Y-Wert verschiebt den Schatten nach oben, was selten beabsichtigt ist.
  • JavaScriptManager prüft die Skript-Eingabe. Ein ungültiger Skript-Körper wird bereits bei der Registrierung abgelehnt und nicht erst zum Schreibzeitpunkt stillschweigend verworfen.
  • JBig2Loader und JpxLoader rastern niemals. Sie validieren die kodierten Bytes und reichen sie durch. Ein beschädigtes Segment wird als Parse-Fehler sichtbar, nicht als leeres Bild.
  • PropertiesRegistry::register() ist pro Dictionary idempotent — identische Eigenschafts-Dictionarys teilen sich einen Tag-Index.

Die Operatorkonstruktion ist O(n) in der String-Länge, zuzüglich eines O(n)-Kerning-Durchlaufs, wenn der Typografie-Modus TJ-Arrays verwendet. Dabei entstehen keine Layout- oder Shaping-Kosten — diese verbleiben in den Modulen Typography und Layout. Die Serialisierung von JavaScript und Eigenschaften ist O(Einträge). Die Pass-through-Bildlader parsen in O(Bytes) ohne Dekodierkosten. Das ist ihr wesentlicher Vorteil bei Arbeitslasten mit gescannten Dokumenten. Das performance_budget für die Referenz-Arbeitslast beträgt 1500 ms Wandzeit und 64 MB Spitzenverbrauch.

JavaScriptManager akzeptiert Skript-Körper, die aus nicht vertrauenswürdigen Templates stammen können. Er prüft jeden Körper und kodiert ihn als PDF-String, aber Dokument-JavaScript bleibt eine Angriffsfläche für aktive Inhalte. Deaktivieren Sie es für nicht vertrauenswürdige Ausgaben, oder entfernen Sie es über den Bereinigungspfad, der unter /modules/core/security/ beschrieben ist. JBig2Loader und JpxLoader parsen nicht vertrauenswürdige Segmentstrukturen: Begrenzen Sie Eingabegröße und Parse-Zeit, und führen Sie die Extraktion in einem eingeschränkten Worker aus, wenn die Quelle vom Benutzer stammt. Die Escape-Grenze für Text ist der vom Aufrufer bereitgestellte Callback. Übergeben Sie stets den kanonischen Escaper, damit Steuerbytes nicht aus einem Literal-String ausbrechen können.

Das Modul gibt Textanzeige- und Textzustands-Operatoren aus, die mit dem Textmodell aus ISO 32000-2 §9 übereinstimmen. Dazu gehören die Semantik des Operators Tj und die Rendering-Modi aus Tabelle 104, die das TextRenderingMode-Enum spiegelt. Dies sind Implementierungsfakten: Die Operatorformen werden von src/Content/TextRenderer.php und dem TextRenderingMode-Enum erzeugt und von tests/Unit/Content/TextRenderer*, JavaScriptManagerIsoTest und PropertiesRegistryTest geprüft. Sie sichern keine Ende-zu-Ende-Konformität mit PDF 2.0 zu. Der String-Escape-Vertrag folgt ADR-015 und ISO 32000-2 §7.3.4.2. Die Pass-through-Pfade für JBIG2 und JPEG 2000 erhalten die kodierten Streams unverändert. Ein separates JBIG2-Globals-Segment wird als /JBIG2Globals-Stream-Referenz am Bild-XObject eingebettet — verifiziert als strukturelle Verdrahtung, nicht als Aussage zur Dekodiertreue. Die Validierung der Konformität auf Dokumentebene erfolgt durch die Oracle- und Golden-Suiten in /modules/core/conformance/.