Pular para o conteúdo

Content: modelo de conteúdo textual + estruturado

O módulo Content compõe operadores de exibição de texto, operadores de estado de texto, sombras de texto, JavaScript em nível de documento e dicionários de propriedades de marked-content. Ele atua entre o layout e o content stream.

Terminal window
composer require nextpdf/core:^3

O Content fornece as primitivas que convertem texto resolvido em operadores do Portable Document Format (PDF). TextRenderer é o componente central. Ele monta o operador de exibição de texto para uma string e os operadores de estado de texto que o precedem. De acordo com a International Organization for Standardization (ISO) 32000-2 §9, o operador Tj pinta os glifos de uma string com a fonte atual e os parâmetros gráficos relacionados ao texto. TextRenderer escolhe entre um único operador de exibição ou um array TJ com posicionamento, com base no TypographyMode ativo. Ele aplica ajustes de kerning quando o modo usa arrays TJ.

O estado de texto é modelado como um conjunto completo. setTextRenderingMode() recebe um enum TextRenderingMode. Seus oito casos correspondem um a um aos modos de renderização de texto da ISO 32000-2: fill, stroke, fill-then-stroke, invisible e as quatro variantes de clip (Tabela 104). O renderizador também controla a largura do traço, o espaçamento entre caracteres, o espaçamento entre palavras, o esticamento horizontal, a elevação do texto, a direção da direita para a esquerda e um Hyphenator opcional. Chamar buildTextStateOperators() emite o estado acumulado como um único bloco de operadores.

TextShadow é um value object composto por cor, deslocamentos X e Y em unidades de usuário e opacidade. O renderizador o usa para emitir uma segunda passagem de desenho no deslocamento. Os deslocamentos padrão formam um par sutil 0.5/−0.5 com 0.5 de opacidade, semelhante a uma sombra suave em Cascading Style Sheets (CSS).

JavaScriptManager é responsável por scripts em nível de documento. includeJs() registra um script de documento. addJsObject() registra um objeto de script nomeado. writeJavaScript() / writeOpenAction() serializam scripts no catálogo e na OpenAction. O manager valida e codifica cada corpo de script como PDF string antes da emissão.

PropertiesRegistry é o repositório de propriedades de marked-content. register() retorna um índice de tag estável para um dicionário de propriedades. registerOcg() / registerOcgs() vinculam grupos de conteúdo opcional (OCGs) por número de objeto. writeProperties() serializa o registro no dicionário de recursos da página. O módulo ContentStream lê esses dados quando abre uma sequência marcada com uma lista de propriedades.

Dois decodificadores de imagem ficam neste módulo porque lidam com formatos pass-through nativos do PDF. JBig2Loader e JpxLoader analisam as estruturas de segmentos JBIG2 e JPEG 2000 e retornam ImageData sem rasterizar pixels. Os bytes codificados passam para o visualizador sem alteração. Quando uma fonte JBIG2 contém um segmento de globals separado, JBig2Loader o incorpora por meio de uma referência de stream /JBIG2Globals no XObject de imagem; a forma in-stream/in-line continua preservando o round-trip como antes. Isso é apenas ligação estrutural: os bytes de globals passam sem rasterização e sem decodificação.

ClasseMétodos principaisFunção
TextRendererbuildTextShowOperator(), buildTextStateOperators(), setTextRenderingMode(), setTextStrokeWidth(), setTextShadow(), setFontSpacing(), setWordSpacing(), setFontStretching(), setTextRise(), setRTL(), setHyphenation()Construtor de operadores de exibição de texto + estado de texto
TextRenderingMode (enum)Fill, Stroke, FillStroke, Invisible, FillClip, StrokeClip, FillStrokeClip, ClipModos de renderização de texto da ISO 32000-2
TextShadow__construct(Color, offsetX, offsetY, opacity)Value object de passagem de desenho com deslocamento
JavaScriptManagerincludeJs(), addJsObject(), hasJavaScript(), writeJavaScript(), writeOpenAction()Ligação do catálogo de JavaScript em nível de documento
PropertiesRegistryregister(), getTagIndex(), registerOcg(), registerOcgs(), getAll(), writeProperties()Repositório de propriedades de marked-content + OCG
JBig2Loaderload(), loadFromString(), parseSegments()Decodificador pass-through de JBIG2
JpxLoaderload(), loadFromString(), parseBoxes()Decodificador pass-through de JPEG 2000

Execute composer docs:generate-api-php -- --module=Content para obter a tabela completa de PHPDoc.

Fonte: 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();

Isso adiciona uma sombra suave e um hyphenator e, em seguida, monta o operador de exibição com uma função de escape fornecida pelo chamador, a fronteira canônica PdfStringEscaper do architecture decision record 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() retorna uma string vazia para entrada vazia. Não emita um Tj vazio; proteja a montante se o layout puder produzir trechos em branco.
  • O callback de escape é obrigatório e é responsável pela segurança da string. Passe o PdfStringEscaper::escapeLiteral() canônico do ADR-015. Um escaper parcial produz uma literal string sintaticamente inválida.
  • Em uma origem no canto superior esquerdo, TextShadow::offsetY é negativo para baixo. Um Y positivo empurra a sombra para cima, o que raramente é intencional.
  • JavaScriptManager valida a entrada de script. Corpos de script inválidos são rejeitados no registro, não descartados silenciosamente no momento da escrita.
  • JBig2Loader e JpxLoader nunca rasterizam. Eles validam e repassam os bytes codificados. Um segmento corrompido aparece como um erro de análise, não como uma imagem em branco.
  • PropertiesRegistry::register() é idempotente por dicionário; dicionários de propriedades idênticos reutilizam o mesmo índice de tag.

A construção dos operadores é O(n) no comprimento da string, mais uma passagem de kerning O(n) quando o modo de tipografia usa arrays TJ. Não há custo de layout ou shaping aqui; esse trabalho fica nos módulos Typography e Layout. A serialização de JavaScript e de propriedades é O(entries). Os carregadores de imagem pass-through usam análise O(bytes) com custo zero de decodificação. Essa é a principal vantagem deles para cargas de trabalho de documentos digitalizados. O performance_budget para a carga de trabalho de referência é de 1500 ms de tempo decorrido e 64 MB de pico.

JavaScriptManager aceita corpos de script que podem vir de templates não confiáveis. Ele valida e codifica cada corpo como PDF string, mas o JavaScript de documento continua sendo uma superfície de conteúdo ativo. Desative-o para saídas não confiáveis, ou remova-o com o caminho de sanitização descrito em /modules/core/security/. JBig2Loader e JpxLoader analisam estruturas de segmentos não confiáveis: limite o tamanho da entrada e o tempo de análise, e execute a extração em um worker restrito quando você aceitar a fonte de entrada externa. A fronteira de escape de texto é o callback fornecido pelo chamador. Sempre passe o escaper canônico para que bytes de controle não consigam escapar de uma literal string.

O módulo emite operadores de exibição de texto e de estado de texto que são consistentes com o modelo de texto da ISO 32000-2 §9. Isso inclui a semântica do operador Tj e os modos de renderização da Tabela 104 espelhados pelo enum TextRenderingMode. Esses são fatos de implementação: src/Content/TextRenderer.php e o enum TextRenderingMode produzem as formas dos operadores, e tests/Unit/Content/TextRenderer*, JavaScriptManagerIsoTest e PropertiesRegistryTest os exercitam. Eles não afirmam conformidade end-to-end com o PDF 2.0. O contrato de escape de string segue o ADR-015 e a ISO 32000-2 §7.3.4.2. Os caminhos pass-through de JBIG2 e JPEG 2000 preservam os streams codificados sem alteração. Um segmento de globals JBIG2 separado é incorporado como uma referência de stream /JBIG2Globals no XObject de imagem; isso é verificado como ligação estrutural, não como uma afirmação de fidelidade de decodificação. A conformidade em nível de documento é validada pelas suítes de oracle e golden em /modules/core/conformance/.