Fontes personalizadas: contrato de extensão FontRegistry
Em resumo
Seção intitulada “Em resumo”FontRegistryInterface define o contrato com ciclo de vida do processo para registrar e localizar fontes. Registre fontes a partir de um caminho de arquivo, de um diretório ou de dados binários brutos e, em seguida, bloqueie o registro para que os workers de produção não possam alterá-lo.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Visão conceitual
Seção intitulada “Visão conceitual”O registro de fontes é um singleton que persiste além de cada instância de Document. Ele armazena apenas dados PHP puros, sem handles de recursos nem objetos de extensão, então você pode compartilhá-lo entre requisições em um worker de longa duração.
Use uma das três formas de registro:
- A partir de um arquivo. O
register()analisa um arquivo.ttf,.otf,.ttcou.pfbe retorna os metadados. Para uma TrueType Collection, passe o índice da subfonte. - A partir de um diretório. O
addFontDirectory()adiciona um caminho de busca que o engine percorre ao resolver uma família pelo nome. - A partir de dados binários. O
registerFromBinary()analisa bytes TrueType ou OpenType brutos. Use essa opção para a ponte@font-facequando as fontes vêm de um Uniform Resource Identifier (URI)data:ou de uma origem remota.
Para reduzir a latência da primeira requisição, chame warmup() no boot do worker para pré-analisar um lote de fontes. Em seguida, chame lock(). Após lock(), qualquer método de mutação lança LogicException: register(), addFontDirectory(), warmup(), registerBase14() e registerFromBinary(). Os métodos de consulta continuam disponíveis: get(), has(), all() e getSearchDirectories(). Esse bloqueio protege os workers de produção ao garantir que nenhuma requisição possa alterar o conjunto de fontes compartilhado.
Na maioria dos casos, você não implementa FontRegistryInterface. O engine fornece a implementação, e você a chama. Implemente-a apenas quando precisar de uma estratégia personalizada de resolução de fontes, como uma baseada em armazenamento endereçável por conteúdo. Em ambos os casos, o contrato continua sendo a fronteira.
Superfície da API
Seção intitulada “Superfície da API”NextPDF\Contracts\FontRegistryInterface (estável, desde 1.7.0):
| Método | Retorna | Finalidade |
|---|---|---|
register(string $fontFile, string $alias, int $fontIndex) | FontInfo | Analisa e registra um arquivo de fonte. Lança exceção quando o registro está bloqueado ou quando o arquivo não pode ser analisado. |
registerFromBinary(string $fontData, string $alias) | FontInfo | Registra uma fonte a partir de bytes TrueType ou OpenType brutos. |
registerBase14(string $key, FontInfo $font) | void | Registra uma fonte padrão Base 14 pré-construída. |
addFontDirectory(string $directory) | void | Adiciona um diretório de busca de fontes. |
warmup(array $fontFiles) | void | Pré-analisa um lote de fontes no boot do worker. |
lock() | void | Congela o registro para impedir mutações posteriores. |
isLocked() | bool | Indica se o registro está bloqueado. |
get(string $family, string $style) | FontInfo | null | Busca uma fonte por família e estilo. |
has(string $key) | bool | Verifica se uma chave de registro existe. |
all() | array<string, FontInfo> | Retorna todas as fontes registradas. |
getSearchDirectories() | list<string> | Retorna os diretórios de busca em ordem. |
memoryUsage() | MemoryReport | Informa o uso atual de memória do registro. |
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?php
declare(strict_types=1);
use NextPDF\Contracts\FontRegistryInterface;
/** @var FontRegistryInterface $fonts */$info = $fonts->register('/srv/fonts/Inter-Regular.ttf', 'Inter');
if (!$fonts->has('inter')) { throw new RuntimeException('Inter failed to register');}Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”No boot do worker, aqueça o conjunto de fontes, bloqueie o registro e observe cada carregamento para rastreabilidade de licenças. Este exemplo usa apenas tipos públicos.
<?php
declare(strict_types=1);
use NextPDF\Contracts\FontRegistryInterface;use NextPDF\Event\Content\FontLoadedEvent;use NextPDF\Event\EventDispatcher;use NextPDF\Event\ListenerProvider;use Psr\Log\LoggerInterface;
final class FontWarmup{ /** @param list<string> $fontFiles */ public function __construct( private readonly FontRegistryInterface $fonts, private readonly LoggerInterface $logger, private readonly array $fontFiles, ) {}
public function boot(): EventDispatcher { $listeners = new ListenerProvider(); $listeners->addListener( FontLoadedEvent::class, function (FontLoadedEvent $event): void { $this->logger->info('font.loaded', [ 'family' => $event->family, 'style' => $event->style, 'type' => $event->fontType->name, ]); }, );
if (!$this->fonts->isLocked()) { $this->fonts->warmup($this->fontFiles); $this->fonts->lock(); }
return new EventDispatcher($listeners); }}Casos extremos e armadilhas
Seção intitulada “Casos extremos e armadilhas”- Registro bloqueado. Após
lock(), qualquer mutação lançaLogicException. VerifiqueisLocked()antes de um warmup condicional em um worker reciclado. - O registro binário não fica em cache por chave. O
registerFromBinary()grava os dados em um arquivo temporário e os analisa. Use oFontInforetornado como handle. - Índice de TrueType Collection (TTC). Para uma TrueType Collection, o terceiro argumento de
register()seleciona a subfonte. O valor padrão0seleciona a primeira face. - Resolução de família. O
get()retornanullpara um par de família e estilo desconhecido. Nunca presuma um resultado não nulo.
Desempenho
Seção intitulada “Desempenho”warmup() transfere o custo de análise da primeira requisição para o boot do worker. Os métodos do registro usam dados PHP puros, e as consultas são leituras de mapa em tempo constante. Chame memoryUsage() para dimensionar o conjunto de fontes residente no worker em relação ao seu orçamento de memória.
Notas de segurança
Seção intitulada “Notas de segurança”Uma fonte registrada pode ser incorporada em conteúdo Portable Document Format (PDF). Valide a procedência da fonte antes do registro. Não registre dados binários controlados por um atacante sem verificações de tamanho e formato. Use o hook FontLoadedEvent para impor a conformidade com o licenciamento de fontes e registrar quais faces um documento incorpora.
Conformidade
Seção intitulada “Conformidade”Nenhuma afirmação normativa de assinatura ou de arquivamento se aplica. A incorporação e o subsetting de fontes estão em conformidade com o modelo de fontes do PDF 2.0. O subsetter interno detém essa conformidade; este contrato não.
Contexto comercial
Seção intitulada “Contexto comercial”NextPDF Enterprise adiciona atestação de licenças de fontes e uma política de subsetting auditada sobre o mesmo FontRegistryInterface. Seu código de registro funciona da mesma forma em todas as edições porque o contrato é a fronteira.
Veja também
Seção intitulada “Veja também”- Visão geral da criação de extensões
- Gatilhos de ação e listeners de eventos
- Layout personalizado e interceptação de texto
- Regras de estabilidade da SPI
Contratos e módulos relacionados
Seção intitulada “Contratos e módulos relacionados”- Referência do módulo de fontes — a implementação do registro, a análise e os detalhes internos de subsetting.
- Referência dos contratos de tipografia — a entrada no catálogo para
FontRegistryInterface. - Gatilhos de ação e listeners de eventos —
FontLoadedEvente o dispatcher. - Layout personalizado e interceptação de texto — o contrato irmão de estratégia em tempo de renderização.
- Regras de estabilidade da SPI — a garantia de interface por trás de
FontRegistryInterface.
O glossário define registro de fontes, registro de imagens e listener de eventos; consulte o glossário publicado para as definições canônicas.