Pular para o conteúdo

Acessibilidade: primitivas de marcação e modelo de estrutura PDF/UA-2

NextPDF Core oferece primitivas para criação acessível: uma árvore de estrutura lógica, mapeamento de papéis padrão, marcação de conteúdo marcado e atributos de idioma Best Current Practice (BCP) 47 alinhados ao modelo de árvore de estrutura da ISO 14289-2 (PDF/UA-2) e da ISO 32000-2 §14.7. O arquivo gerado só está em conformidade quando o documento final, as escolhas de conteúdo do autor e um verificador externo sustentam esse resultado. A biblioteca não declara essa garantia por você.

Terminal window
composer require nextpdf/core

Um arquivo Portable Document Format (PDF) marcado inclui uma árvore de estrutura lógica cuja raiz contém um único elemento de estrutura Document. A tecnologia assistiva lê essa árvore para determinar uma ordem de leitura significativa que não dependa do layout visual (ISO 32000-2 §14.7.2; ISO 14289-2 §8.2.5.2). O NextPDF modela esse comportamento com três tipos que trabalham em conjunto no namespace NextPDF\Accessibility.

StructureTree é o proprietário da hierarquia. Ele aloca identificadores de conteúdo marcado para cada página, rastreia o aninhamento entre pais e filhos e serializa a raiz da árvore de estrutura, os elementos de estrutura, a árvore de pais, o mapa de papéis e o namespace de estrutura padrão do PDF 2.0 conforme a ISO 32000-2 §14.7. createRoot() inicializa o único elemento Document obrigatório com um atributo de idioma. addElement() anexa filhos tipados. hasRoot() e rootHasChildren() informam se a árvore existe e se ela tem descendentes.

StructureElement é o objeto de valor de um dicionário de elemento de estrutura. Ele armazena o tipo de estrutura padrão (nomes da Tabela 368, como H1 a H6, P, L, LI, Table, Figure, Link), entradas de identificador de conteúdo marcado e atributos de acessibilidade opcionais para texto alternativo, texto de substituição, título e idioma. Um único elemento pode abranger várias páginas. Ele acumula uma entrada de identificador por página para que o array de filhos referencie o conteúdo marcado através dos limites de página.

TaggedContentEmitter conecta o pipeline de Hypertext Markup Language (HTML) à árvore de estrutura. Quando Document::enableTaggedPdf() está ativo, o renderizador HTML acopla o emissor para que os elementos de nível de bloco criem operadores de conteúdo marcado pareados e nós de elemento de estrutura correspondentes. HtmlToStructureMap fornece o mapeamento baseado em tabela das tags HTML para os tipos de estrutura PDF (ISO 14289-2 §8). O emissor encaminha conteúdo corrente decorativo, como regiões de cabeçalho e rodapé do HTML, para um artefato e o mantém fora da ordem de leitura.

Bcp47Validator valida a marcação de idioma (Request for Comments (RFC) 5646). Ele fornece uma verificação sintática de boa formação e uma verificação de validade apoiada em registro. O modo estrito (ConformancePolicy::strictUa2()) rejeita tags malformadas no limite da application programming interface (API), em vez de descartá-las silenciosamente no momento da gravação. Isso corresponde ao requisito da ISO 14289-2 §8.4.4 de que a entrada de idioma do catálogo resolva para um idioma específico.

SímboloTipoResumo
Document::enableTaggedPdf(string $lang = 'en', ?ConformancePolicy $policy = null): staticmétodoAtiva a árvore de estrutura e a ponte HTML; define as entradas de mark-info e de idioma do catálogo.
Document::setLanguage(string $lang): staticmétodoDefine o idioma natural no nível do documento (BCP-47).
Document::isTaggedPdfEnabled(): boolmétodoInforma se o modo de conformidade ativo exige marcação estrutural.
StructureTree::createRoot(string $lang = 'en'): intmétodoCria o único elemento raiz Document obrigatório.
StructureTree::addElement(int $parentIndex, string $type, int $pageIndex, ...): intmétodoAnexa um elemento de estrutura filho tipado.
StructureTree::hasRoot(): bool and rootHasChildren(): boolmétodoInforma se a árvore existe e se tem descendentes.
StructureElementclasse finalObjeto de valor para um elemento de estrutura (texto alternativo, texto de substituição, título, idioma, identificadores).
RoleMap::standard(): array<string,string>estáticoRetorna o vocabulário de tipos de estrutura padrão (ISO 32000-2 Tabela 368 mais tipos do PDF 2.0).
Bcp47Validator::isWellFormed/isValid/validate/normalisemétodoValida tags de idioma RFC 5646 com verificações sintáticas e apoiadas em registro.
AccessibilityAutoFixerRegistryclasse finalRegistro opcional no estilo PHP Standards Recommendation (PSR)-11 para corretores heurísticos de estrutura.
<?php
declare(strict_types=1);
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// The BCP 47 tag drives the catalog language entry and the
// structure-tree root language attribute.
$doc->enableTaggedPdf(lang: 'en');
$doc->setTitle('Tagged accessibility demo');
$doc->addPage();
// Semantic HTML maps to structure elements: h1 to /H1, p to /P,
// ul and li to /L plus /LI. Text runs are wrapped in
// marked-content operators with stable identifiers.
$doc->writeHtml('<h1>Document title</h1><p>Body paragraph.</p>');
$doc->save(__DIR__ . '/output/tagged.pdf');
<?php
declare(strict_types=1);
use NextPDF\Conformance\ConformancePolicy;
use NextPDF\Core\Document;
use NextPDF\Exception\InvalidConfigException;
use Psr\Log\LoggerInterface;
final class AccessibleReportWriter
{
public function __construct(private readonly LoggerInterface $logger)
{
}
public function render(string $html, string $bcp47Lang, string $outPath): void
{
$doc = Document::createStandalone();
try {
// strictUa2() rejects malformed BCP 47 tags at the API
// boundary (ISO 14289-2 §8.4.4) instead of dropping silently.
$doc->enableTaggedPdf($bcp47Lang, ConformancePolicy::strictUa2());
} catch (InvalidConfigException $e) {
$this->logger->error('Rejected language tag for tagged PDF', [
'lang' => $bcp47Lang,
'reason' => $e->getMessage(),
]);
throw $e;
}
$doc->setTitle('Quarterly accessibility report')
->setLanguage($bcp47Lang)
->addPage();
$doc->writeHtml($html);
// The engine emits a Degraded / ComplianceRisk advisory directing
// the caller to validate externally; surface it to operators
// rather than treating tagged output as certified.
foreach ($doc->getWarnings() as $warning) {
$this->logger->warning('Tagged-PDF advisory', [
'code' => $warning->code->value,
'message' => $warning->message,
]);
}
$doc->save($outPath);
}
}
  • Ordem das chamadas. Chame enableTaggedPdf() antes de writeHtml(). O pipeline HTML verifica o modo de conformidade quando o parser é construído e não conecta retroativamente o emissor a conteúdo que já foi renderizado.
  • Árvore de estrutura vazia. Um documento com enableTaggedPdf(), mas sem descendentes de estrutura anexados, não anuncia PDF/UA-2 em seus metadados. O portão de publicação é rootHasChildren(), e não hasRoot(), porque os validadores rejeitam um arquivo que reivindica PDF/UA-2 com uma árvore de estrutura vazia (ISO 14289-2 §5; verificado por EmptyTaggedPdfDoesNotAdvertisePdfUa2Test).
  • Colapso do modo de conformidade. Quando você chama enablePdfA() e enableTaggedPdf() no mesmo documento, o discriminador de conformidade de valor único colapsa e o último prevalece. Os efeitos colaterais (árvore de estrutura, mark-info) permanecem aditivos, e o NextPDF emite um aviso CONFORMANCE_MODE_CLOBBERED para que o colapso seja observável.
  • Os corretores automáticos não são automáticos. Os corretores integrados (EmptyTagStripper, LegacyLangNormaliser, RootLangFallback) são fornecidos sob NextPDF\Accessibility\AutoFixer\*, mas nunca são registrados automaticamente. Você deve registrá-los explicitamente em AccessibilityAutoFixerRegistry.

O NextPDF emite uma estrutura consistente com o modelo de árvore de estrutura do PDF/UA-2, mas não cria semântica que não consiga inferir. Você deve fornecer a marcação ou os atributos para os seguintes itens; o NextPDF não os gera por você:

  • texto alternativo para imagens e outros conteúdos não textuais;
  • escopo de cabeçalho de tabela e associações entre cabeçalho e célula além do que a marcação HTML expressa;
  • texto de finalidade do link quando o texto visível do link não for autodescritivo;
  • semântica de lista para conteúdo visualmente disposto como lista, mas sem marcação de lista;
  • ordem de leitura corrigida quando a ordem de origem difere da ordem de leitura pretendida;
  • classificação entre decorativo e significativo para conteúdo ambíguo.

O NextPDF não realiza verificação PDF/UA-2 de ponta a ponta. Em tempo de execução, ele emite um aviso Degraded / ComplianceRisk (PDFUA2_FOUNDATIONAL) que orienta o chamador a validar a saída com um verificador externo antes da aprovação para produção. Valide com um verificador PDF/UA (por exemplo, veraPDF). O NextPDF não declara conformidade em seu nome. A conformidade do documento final depende das escolhas de autoria e de um validador, não da chamada da API.

A construção da árvore de estrutura é linear em relação ao número de elementos de estrutura. A alocação de identificadores tem tempo constante amortizado por sequência de conteúdo marcado. A serialização faz uma única passagem linear pelo conjunto de elementos. Para marcação orientada por HTML, o custo dominante é o próprio pipeline HTML, não a emissão de tags. O limite por receita declarado em performance_budget (1500 ms de tempo de parede, 64 MB de pico) aplica-se a um documento semântico típico de várias páginas. Documentos grandes escalam linearmente com a contagem de elementos, e não com a contagem de páginas.

Tags de idioma e atributos de acessibilidade fluem para objetos PDF de nome e de string. O NextPDF os escapa por meio de PdfStringEscaper, de modo que valores malformados ou hostis de idioma, texto alternativo, texto de substituição e título não consigam sair de seu contexto de objeto PDF. O modo estrito também rejeita tags BCP-47 não registradas no limite da API, estreitando a superfície de entrada antes que ela chegue ao gravador. Os atributos de acessibilidade podem conter texto livre fornecido pelo autor. Trate-os como saída não confiável e revise-os como você revisa outros conteúdos do documento. Consulte o módulo Conformance para o comportamento do verificador de perfil.

Esta página mapeia o comportamento da biblioteca para identificadores de cláusula. Ela não afirma que a sua saída está em conformidade. As cláusulas citadas são parafraseadas, nunca citadas literalmente. Consulte o mapeamento da especificação PDF/UA-2 para ver a tabela em nível de provisão e a não cobertura explícita. Os hashes dos blocos de citação são registrados em docs/public/modules/core/_normative-evidence-a11y.md.