Contracts / Typography
Visão geral
Seção intitulada “Visão geral”O domínio de tipografia define os contracts para registro de fontes e pré-processamento de texto: FontRegistryInterface, TextPreprocessorInterface e os value objects imutáveis TextPreprocessResult e TextSegment. Todos são stable.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Visão conceitual
Seção intitulada “Visão conceitual”FontRegistryInterface é o armazenamento de fontes com tempo de vida do processo. Ele registra uma fonte TrueType, OpenType, TrueType Collection (TTC) ou Printer Font Binary (PFB) e retorna os metadados FontInfo já analisados. Como o registro permanece além dos documentos individuais, um worker analisa cada fonte apenas uma vez. Você pode pré-aquecer um lote de fontes no boot e depois travar o registro para que o tráfego de produção não possa alterá-lo. Um registro travado lança LogicException em register(), addFontDirectory() ou warmup(); as consultas continuam disponíveis. O registro também aceita bytes brutos de fonte por meio de registerFromBinary(). A ponte @font-face usa esse método para registrar uma fonte obtida de uma origem remota ou de um data URI (uniform resource identifier). O registro armazena apenas dados PHP puros, sem handles de recursos, de modo que pode ser compartilhado em um pool de workers.
O engine incorpora e cria subconjuntos para toda fonte que utiliza. Um programa de fonte incorporado fica incluído no arquivo Portable Document Format (PDF), de modo que o documento é renderizado da mesma forma em qualquer visualizador, independentemente das fontes do sistema instaladas — ISO 32000-2 §9. Um subconjunto de fonte contém apenas os glifos que o documento de fato referencia. Isso é especialmente importante para conteúdo em chinês, japonês e coreano (CJK) ou outro conteúdo com amplo uso de Unicode — ISO 32000-2 §9. O contract do registro expõe os metadados analisados usados pelas etapas de criação de subconjunto e incorporação.
TextPreprocessorInterface intercepta o texto antes que ele entre no layout de glifos, na criação de subconjunto de fontes, no mapa de caracteres ToUnicode (CMap) e na árvore de estrutura. Esse posicionamento é a propriedade de segurança: um pré-processador que redige conteúdo o remove antes que ele possa chegar ao content stream, ao subconjunto de fonte ou aos metadados. O contract carrega dois invariantes. Um pré-processador não deve introduzir caracteres que afetem o layout e deve preservar a ordem lógica de leitura; sua responsabilidade é substituir conteúdo, não definir layout. O resultado é um TextPreprocessResult imutável com uma lista ordenada de valores TextSegment. Um segmento é de passagem direta ou redigido. Para um segmento redigido, o texto exibido depende do modo de mascaramento: vazio para um retângulo de caixa-preta, asteriscos correspondentes ao comprimento original ou um rótulo fixo. O originalCharCount em um segmento é uma dica de medição não reversível, usada apenas para dimensionar um retângulo de redação. Ele nunca deve ser usado para reconstruir o conteúdo original.
Superfície da API
Seção intitulada “Superfície da API”| Tipo | Espécie | Membros principais | Estabilidade | Desde |
|---|---|---|---|---|
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 |
TextPreprocessResult e TextSegment mantêm congeladas suas assinaturas de construtor e propriedades públicas; novos métodos podem ser adicionados, mas as propriedades não podem mudar.
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?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() resolve a família por meio de FontRegistryInterface. Um documento standalone usa um registro privado. Em um worker, compartilhe um único registro; consulte a página do documento.
Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”<?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; }}warmup() seguido de lock() é a sequência de boot do worker. Após lock(), qualquer mutação lança uma exceção. As consultas continuam atendendo ao tráfego.
Casos extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- Um registro travado rejeita todos os métodos de mutação. Pré-aqueça e trave o registro no boot; nunca chame
register()durante o tratamento de requisições. registerFromBinary()grava os bytes da fonte em um arquivo temporário antes de analisar. Dados de fonte não confiáveis são uma superfície de ataque para o parser — proteja-os por meio deExternalResourcePolicyInterface(consulte a página de política de segurança).- Um
TextPreprocessornão deve adicionar quebras de linha, retornos de carro ou tabulações. Esses caracteres alteram o layout e quebram o primeiro invariante do contract. TextSegment::$originalCharCounté apenas uma dica de largura. Usá-lo para inferir o conteúdo original anula a redação e viola o terceiro invariante do contract.TextPreprocessResult::getDisplayText()retorna uma string vazia para segmentos de caixa-preta, por design. Não trate um segmento vazio como uma falha de pré-processamento.
Desempenho
Seção intitulada “Desempenho”A análise de fontes é o principal custo do primeiro uso; o registro amortiza esse custo, limitando-o a uma vez por processo. Após o warmup, get() e has() são consultas de mapa O(1). memoryUsage() retorna um MemoryReport para que um worker possa acompanhar o cache de fontes em relação ao seu orçamento. O pré-processamento de texto é linear em relação ao comprimento da entrada. A lista de segmentos adiciona uma sobrecarga limitada, proporcional ao número de correspondências de redação. O performance_budget de 1500 ms de tempo total e 64 MB de pico cobre o warmup de um conjunto típico de fontes mais a renderização do documento. O custo da criação de subconjunto escala com a quantidade de glifos efetivamente usados, não com a tabela completa de glifos da fonte. A criação de subconjunto, portanto, reduz o tamanho da saída e o custo de renderização para conteúdo CJK.
Notas de segurança
Seção intitulada “Notas de segurança”O domínio de tipografia tem duas superfícies relevantes para a segurança. A primeira é a entrada de fontes: registerFromBinary() analisa bytes arbitrários. Dados de fonte não confiáveis devem passar por um ExternalResourcePolicyInterface que limita o tamanho do arquivo e a quantidade de glifos antes que cheguem ao parser. A segunda é a redação: TextPreprocessorInterface é executado antes do layout de glifos, da criação de subconjunto de fontes, do CMap ToUnicode e da árvore de estrutura, de modo que o conteúdo redigido nunca entra no artefato renderizado. Uma redação por sobreposição na etapa de pintura vaza o texto original no content stream e no subconjunto. O posicionamento do contract evita essa classe de defeito. A dica de medição em um segmento é deliberadamente não reversível. Trate qualquer fonte ou texto fornecido externamente como não confiável.
Conformidade
Seção intitulada “Conformidade”| Afirmação | Norma | Cláusula | Evidência |
|---|---|---|---|
| Toda fonte usada pelo documento é incorporada para que o documento seja renderizado sem depender das fontes do sistema. | ISO 32000-2 | §9 | |
| A fonte incorporada é reduzida a um subconjunto contendo os glifos que o documento referencia. | ISO 32000-2 | §9 |
Ambas as cláusulas estão parafraseadas. O NextPDF não reproduz texto normativo. O PDF/A-4 exige a incorporação de toda fonte. Essa conformidade está documentada nas páginas de extração e de acessibilidade.
Veja também
Seção intitulada “Veja também”- Contracts: 41 interfaces públicas (SPI) — visão geral da service provider interface e dos níveis de estabilidade.
- Contracts / Document — o papel do registro no ciclo de vida do documento.
- Contracts / Security Policy —
ExternalResourcePolicyInterfacecontrolando bytes de fonte não confiáveis. - Typography — o módulo de modelagem de texto e layout.
- Font — análise, criação de subconjunto e incorporação de fontes.
- Text — saída de texto que consome resultados do pré-processador.