Incorpore uma fonte TrueType e gere seu subconjunto
Visão geral
Seção intitulada “Visão geral”Registre uma fonte TrueType, renderize texto com ela e deixe o writer incorporar apenas o subconjunto necessário. Esta receita segue o mesmo fluxo de conteúdo de examples/04-text-and-fonts.php, acrescentando uma fonte TrueType (.ttf) registrada.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3Essa restrição instala o pacote nextpdf/core. O exemplo é executado no PHP 8.4, e a fixture de teste LiberationSans-Regular.ttf incluída mantém a receita autossuficiente.
Visão conceitual
Seção intitulada “Visão conceitual”Registre uma face com FontRegistry::register($path, $alias). O registry analisa o arquivo e retorna um FontInfo, usando TrueTypeParser para arquivos .ttf e .otf. Para usar a face, selecione o alias dela com setFont($alias, ...). Essa chamada também registra os codepoints utilizados.
A geração do subconjunto é executada automaticamente em save(). O writer de fontes PDF coleta os codepoints utilizados e chama FontSubsetter::subset(), ou CffSubsetter para faces Compact Font Format (CFF) ou OpenType. Quando o subconjunto é menor que o programa completo, o writer incorpora o subconjunto. Ele também reescreve BaseFont e FontName com uma tag de subconjunto de seis letras maiúsculas unidas por sinal de mais. Esse é o formato ABCDEF+FontName que a ISO 32000-2 exige para um subconjunto de fonte. O writer armazena o programa TrueType incorporado como FontFile2 no descritor de fonte (ISO 32000-2).
O prefixo do subconjunto é gerado de forma determinística a partir do nome PostScript, de modo que um build determinístico produz uma tag estável. É por isso que o perfil de reprodutibilidade desta receita é structural. Esse perfil normaliza o prefixo do subconjunto e o /ID do trailer em vez de verificá-los byte a byte.
Superfície da API
Seção intitulada “Superfície da API”FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo—NextPDF\Typography\FontRegistry.setFont(string $family, string $style = '', float $size = 12.0): static—NextPDF\Core\Concerns\HasTypography; passe o alias registrado como$family.- A geração do subconjunto é interna ao writer (
NextPDF\Writer\PdfFontWriter->NextPDF\Typography\FontSubsetter). Não há uma opção pública para ativar ou desativar: o writer sempre gera o subconjunto quando os codepoints são conhecidos e o subconjunto é menor.
A tabela completa de PHPDoc é gerada a partir do código-fonte.
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;use NextPDF\Typography\FontRegistry;
$registry = new FontRegistry();$registry->register(__DIR__ . '/MyFont-Regular.ttf', alias: 'MyFont');
$doc = Document::createStandalone();$doc->addPage();$doc->setFont('MyFont', '', 14);$doc->cell(0, 10, 'Rendered with an embedded, subset TrueType face.', newLine: true);
$doc->save(__DIR__ . '/out.pdf');Document::createStandalone() constrói o próprio registry. Para usar um registry que você mesmo preencheu, crie o documento por meio de DocumentFactory, como mostrado no exemplo de produção. A factory faz com que o writer leia a face que você registrou.
Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”Este exemplo é autossuficiente e executável pelo harness. Ele registra a LiberationSans-Regular.ttf incluída e renderiza por meio de DocumentFactory, garantindo que o registry preenchido seja o que está em uso. O exemplo depende da geração automática do subconjunto no momento de salvar.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
// A bundled TrueType test fixture keeps this recipe self-contained.// Replace with a font you have the right to embed.$fontPath = __DIR__ . '/../../fonts/test-fixtures/LiberationSans/LiberationSans-Regular.ttf';if (!is_file($fontPath)) { // Fall back to the repository-relative fixture location. $fontPath = dirname(__DIR__, 2) . '/fonts/test-fixtures/LiberationSans/LiberationSans-Regular.ttf';}
$fontRegistry = new FontRegistry();$fontRegistry->register($fontPath, alias: 'LiberationSans');
$imageRegistry = new ImageRegistry(maxCacheBytes: 0);$documentFactory = new DocumentFactory($fontRegistry, $imageRegistry);
$doc = $documentFactory->create();$doc->setTitle('Embedded Subset Font');$doc->addPage();
$doc->setFont('LiberationSans', '', 20);$doc->cell(0, 14, 'Embedded TrueType face', newLine: true);
$doc->setFont('LiberationSans', '', 12);$doc->multiCell(0, 7, 'Only the glyphs used by this document are embedded. ' . 'The writer subsets the font program and rewrites the BaseFont with a ' . 'deterministic six-letter subset prefix, for example ABCDEF+LiberationSans.');
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/embed-and-subset-fonts.pdf');
echo "Wrote embed-and-subset-fonts.pdf\n";STDOUT esperado:
Wrote embed-and-subset-fonts.pdfPara verificar o subconjunto, abra a saída e inspecione o dicionário de fontes. O BaseFont exibe <TAG>+LiberationSans, e o descritor carrega um FontFile2. Executar qpdf --check não relata erros estruturais.
Casos extremos e pegadinhas
Seção intitulada “Casos extremos e pegadinhas”- Propriedade do registry.
Document::createStandalone()constrói o próprio registry. Uma fonte que você registrou em umFontRegistryseparado não fica visível para esse documento. UseDocumentFactorypara passar o registry, como faz o exemplo de produção. - Direitos de incorporação. A geração do subconjunto não altera o licenciamento. Incorpore apenas fontes para as quais você tem licença de incorporação. Algumas fontes definem bits de restrição de incorporação; o parser lê esses bits, mas você continua responsável pela conformidade.
- Caminho CFF/OpenType. Para faces
.otfe CFF,CffSubsettergera o subconjunto, nãoFontSubsetter. O comportamento e a reescrita da tag de subconjunto são equivalentes. Apenas o caminho de código difere. - Sem ganho de tamanho. Às vezes o subconjunto não é menor que o original. Isso pode acontecer com fontes muito pequenas ou quando todos os glyphs são usados. Nesse caso, o writer incorpora o programa original sem uma tag de subconjunto. Esse comportamento está correto, não é uma falha.
- Fontes CJK. Faces grandes de chinês, japonês e coreano (CJK) usam uma estratégia de geração de subconjunto em camadas, conforme a ADR-008, com um subprocesso isolado e um fallback nativo em PHP. Consulte Componha texto CJK com codificação ciente de cmap para detalhes sobre CJK e o status atual do pipeline.
Desempenho
Seção intitulada “Desempenho”A análise percorre as tabelas da fonte uma única vez, e o custo da geração do subconjunto cresce com o número de glyphs. Faces latinas não CJK geram o subconjunto no próprio processo dentro do orçamento wall_ms: 1500, peak_mb: 96. Faces CJK grandes são roteadas para um subprocesso isolado com um timeout de dois segundos de tempo decorrido e um fallback nativo em PHP (ADR-008). Esse roteamento significa que uma geração de subconjunto lenta ou que trave não pode bloquear quem fez a chamada.
Notas de segurança
Seção intitulada “Notas de segurança”Um arquivo de fonte é uma entrada binária não confiável. O parser rejeita caminhos de stream-wrapper e bytes nulos. O subprocesso de geração de subconjunto CJK roda sem conexões de banco de dados, handles de arquivo nem estado de framework herdado. Ele recorre ao fallback de forma segura em caso de travamento ou timeout (ADR-008). Valide a procedência das fontes que você aceita de usuários finais.
Conformidade
Seção intitulada “Conformidade”| Afirmação | Especificação | Cláusula | reference_id |
|---|---|---|---|
| O BaseFont/FontName de um subconjunto de fonte carrega um prefixo de subconjunto de seis letras maiúsculas unidas por sinal de mais. | ISO 32000-2 | iso32000_2_sec9#x1.x66.p2 | |
| Um programa de fonte TrueType incorporado é armazenado como FontFile2 no descritor de fonte. | ISO 32000-2 | iso32000_2_sec9#x1.x65.p15 |
Esta receita mostra como o NextPDF incorpora e gera o subconjunto de uma face TrueType e emite um prefixo de subconjunto em conformidade. Ela não atesta a conformidade com a licença da fonte. Os direitos de incorporação são responsabilidade do integrador.
Contexto comercial
Seção intitulada “Contexto comercial”Não se aplica.