Um PDF é um contêiner: arquivos embutidos e dados associados
Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4Spec: ISO 32000-2, §14.13ISO 32000-2 §14.13Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3
Visão geral
Seção intitulada “Visão geral”A maioria das pessoas imagina um PDF como uma pilha de páginas. Essa é a parte que você vê. Mas um PDF também é um contêiner, e pode carregar outros arquivos inteiros dentro de si — uma planilha, um payload XML, o documento de origem original — empacotados no mesmo arquivo único que você entrega a outra pessoa.
Esta página explica como isso funciona: o stream de arquivo embutido que armazena os bytes, a name tree que os lista, e a única chave que decide se um anexo está apenas ali parado ou de fato significa algo.
Por que isso importa
Seção intitulada “Por que isso importa”Um anexo sem tipo e um com tipo parecem idênticos para um humano. Ambos são um arquivo viajando dentro de um PDF e — neste motor — ambos estão associados ao documento. A diferença é que um deles diz a uma máquina para que serve, e o outro deixa a relação em branco para a máquina adivinhar.
Essa diferença é tudo o que importa para uma e-fatura híbrida. Uma plataforma fiscal não lê a página da sua fatura; ela lê o XML que você embutiu. Se esse XML estiver anexado como um blob indiferenciado em vez de como os dados da fatura para o documento visível, um leitor conforme não tem como saber de forma confiável que ele é o payload a processar. A página parece perfeita. A fatura é rejeitada. A falha chega dias depois, com um pagamento retido por trás.
Acertar a relação, na camada que produz o arquivo, é muito mais barato do que descobri-la uma fatura rejeitada por vez.
A versão resumida
Seção intitulada “A versão resumida”- Um PDF pode embutir os bytes de qualquer arquivo como um stream de arquivo embutido (Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4). O stream carrega os dados mais um pequeno dicionário de parâmetros: tamanho original, datas e um checksum.
- Os arquivos embutidos são catalogados na name tree
EmbeddedFiles, de modo que um leitor pode enumerá-los por nome sem varrer o documento inteiro. - Um arquivo associado vai um passo além: ele declara uma
AFRelationship(Spec: ISO 32000-2, §7.11.3ISO 32000-2 §7.11.3) — um de oito valores padrão (Source,Data,Alternative,Supplement,EncryptedPayload,FormData,Schema,Unspecified), ou um valor customizado — dizendo como o arquivo se relaciona com o conteúdo ao qual está anexado. - Essa relação tipada é o mecanismo por trás de e-faturas híbridas (ZUGFeRD / Factur-X) e de anexos PDF/A-3 (Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3).
- O NextPDF suporta as primitivas brutas do contêiner no core:
embedFile()eembedFileFromString()com uma relação explícita. As edições Advanced adicionam o embedder dedicado de e-fatura EN 16931 / ZUGFeRD / Factur-X em cima dessas primitivas.
Como o NextPDF aborda isso
Seção intitulada “Como o NextPDF aborda isso”Pense nisso como duas camadas empilhadas uma sobre a outra.
A camada inferior é o armazenamento. Um stream de arquivo embutido
(Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4) são os bytes do arquivo
original embrulhados em um objeto stream do PDF, com um dicionário de parâmetros
registrando o tamanho original, a data de modificação e um checksum dos dados
descomprimidos. O stream é alcançado por meio de um dicionário de especificação
de arquivo cujo dicionário /EF aponta para o stream de arquivo embutido — o
stream em si não carrega /EF. Um leitor pode extrair o arquivo de volta byte a
byte. Para tornar esses arquivos localizáveis, o catálogo do documento mantém uma
name tree EmbeddedFiles — um mapa ordenado de um nome até cada especificação de
arquivo — de modo que um visualizador pode listar “aqui estão os 3 arquivos
dentro deste PDF” sem percorrer cada página.
A camada superior é o significado. Por si só, um arquivo embutido está apenas
presente. O mecanismo de arquivos associados (Spec: ISO 32000-2, §14.13ISO 32000-2 §14.13)
anexa um arquivo a algo — o documento inteiro, uma página, um objeto gráfico — e o
carimba com uma AFRelationship. A ISO 32000-2 define um pequeno vocabulário de
oito valores padrão (Spec: ISO 32000-2, §7.11.3ISO 32000-2 §7.11.3), e também
permite valores customizados; cada valor padrão responde a uma pergunta precisa:
AFRelationship | O que ele afirma sobre o arquivo |
|---|---|
Source | Este é o material de origem a partir do qual o conteúdo visível foi gerado (por exemplo, o documento original do processador de texto). |
Data | Estes são dados estruturados ligados ao conteúdo visível — o caso canônico é o XML da fatura por trás de uma página de fatura renderizada. |
Alternative | Esta é uma representação alternativa do mesmo conteúdo (por exemplo, uma versão em áudio ou vídeo). |
Supplement | Este é material suplementar que estende o conteúdo, mas não faz parte dele. |
EncryptedPayload | O arquivo embutido é um payload criptografado que o PDF embrulha como um blob opaco. |
FormData | O arquivo é dados de formulário (FDF, XFDF, ou um payload de formulário XML). |
Schema | O arquivo é um schema descrevendo a estrutura de um arquivo Data (por exemplo, um XSD para dados XML ou um JSON Schema). |
Unspecified | A relação deliberadamente não é declarada. Honesto, mas não diz nada a uma máquina. |
Além desses oito, a norma também permite valores de relação customizados específicos da aplicação, de modo que o vocabulário é extensível em vez de fixo.
Um arquivo associado é definido por duas coisas trabalhando juntas, não por uma
chave isolada. A associação /AF vincula a especificação de arquivo a uma parte
do documento; a chave AFRelationship na especificação de arquivo então declara
a relação semântica. A entrada /AF no ponto de associação (o catálogo do
documento, uma página ou um objeto) é um array — esse array contém uma ou mais
especificações de arquivo, geralmente como referências indiretas; /AF não é uma
referência única. Um arquivo associado em nível de documento é a especificação de
arquivo listada no array /AF do catálogo do documento, carregando sua
AFRelationship. Marque aquela planilha como Unspecified e você a terá
associado ao documento, mas terá dito a uma máquina nada sobre o porquê. Marque
a mesma planilha como Data e você terá dito a todo leitor conforme o que ela é e
para que serve. Os bytes são os mesmos. A semântica não.
É por isso que o caso da e-fatura não é “anexar um arquivo XML”. É “embutir este
XML como o arquivo associado Data deste documento, dentro de um portador PDF/A-3
conforme” — com a validade da fatura e a aceitação legal permanecendo
verificações separadas que o portador não realiza. O fluxo tem quatro estágios, e
a ordem é o que o mantém correto.
- Armazenar os bytesO arquivo é embrulhado em um stream de arquivo embutido com seu tamanho, datas e um checksum (ISO 32000-2 §7.11.4).
- Registrar por nomeA especificação de arquivo é adicionada à name tree EmbeddedFiles para que um leitor possa enumerar anexos sem varrer o documento.
- Declarar a relaçãoUm valor AFRelationship (um dos oito valores padrão, como Source ou Data) marca como o arquivo se relaciona com o conteúdo, associado em nível de documento (ISO 32000-2 §14.13.3).
- Torná-lo de arquivamentoUm portador PDF/A-3 permite que o payload embutido viaje dentro de um único documento de arquivamento PDF/A conforme; a validade da fatura e a aceitação legal permanecem verificações separadas (ISO 19005-3).
Esse quarto estágio é o motivo de o PDF/A-3 existir como um perfil distinto. Os
perfis de arquivamento anteriores restringiam o que podia ser embutido; o PDF/A-3
(Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3) é a parte que permite arquivos
de qualquer formato viajarem dentro de um documento de arquivamento conforme.
Ele permite o payload embutido — não valida esse payload nem confere status legal.
Sem ele, a fatura híbrida — um arquivo que é tanto a página que uma pessoa lê
quanto os dados que um sistema fiscal faz parsing — não poderia ser um documento
de arquivamento PDF/A conforme de jeito nenhum; se a fatura é válida e
legalmente aceita continua sendo uma questão separada. O embedder dedicado de
e-fatura que as edições Advanced adicionam é a costura de conveniência sobre
exatamente isto: ele embute o payload, define a relação como Data e o registra
corretamente, de modo que você não monta o encanamento do contêiner à mão. A
mecânica mais profunda de faturamento e arquivamento vive nas duas páginas
vizinhas linkadas abaixo; esta página é sobre o contêiner sobre o qual ambas se
apoiam.
Exemplo prático
Seção intitulada “Exemplo prático”Um programa pequeno e completo. As duas chamadas que importam são a diferença
entre um arquivo associado sem tipo e um com tipo — e a relação é um argumento
explícito que você deveria definir. Neste motor, ambas as chamadas produzem um
arquivo associado: embedFile() e embedFileFromString() sempre registram a
especificação de arquivo no array /AF do catálogo do documento, de modo que a
única coisa que a relação muda é o que a associação significa. Ela tem como
padrão Unspecified, que associa o arquivo, mas não diz nada a uma máquina sobre
o porquê; para um payload de e-fatura você a define como Data para que um leitor
possa encontrá-lo.
<?php
declare(strict_types=1);
use NextPDF\Core\Document;use NextPDF\Navigation\AFRelationship;
$document = Document::createStandalone();$document->addPage();$document->setFont('helvetica', 'B', 16);$document->cell(0, 12, 'Invoice INV-2026-0042', newLine: true);
// An UNTYPED associated file: the bytes are embedded AND the file spec is// added to the document catalog's /AF array, but the relationship says// nothing about why. A reader can open it; a machine cannot tell its role.// The relationship is left Unspecified (its default); the second argument is// the human-readable description. embedFile accepts the AFRelationship enum.$document->embedFile( '/srv/invoices/INV-2026-0042-source.docx', 'Original source document', AFRelationship::Unspecified,);
// A TYPED associated file: the invoice XML is declared as the DATA behind// the visible page. This is the relationship a hybrid e-invoice reader// looks for — the same intent the dedicated e-invoice embedder sets.// embedFileFromString takes the data, a filename, a description, and a// relationship as a PDF-name string ('/Data').$invoiceXml = $generateCiiXml(); // your ERP authors this; the engine never does$document->embedFileFromString( $invoiceXml, 'factur-x.xml', 'Factur-X invoice data', '/Data',);
$bytes = $document->getPdfData();A relação '/Data' é inconfundível. O primeiro anexo — deixado Unspecified —
está associado da mesma forma, só que sem um significado declarado. Para ambas as
chamadas, o motor escreve o stream de arquivo embutido, adiciona o arquivo à name
tree EmbeddedFiles, lista sua especificação de arquivo no array /AF do
catálogo do documento, e registra a relação que você declarou — ele não escolhe
uma por você. Este motor não tem um modo somente-name-tree: todo arquivo que você
embute desta forma é um arquivo associado ao documento, de modo que a relação é a
única alavanca que você controla.
Equívoco comum
Seção intitulada “Equívoco comum”A suposição frequente é que “embutido” e “associado” são duas palavras para a
mesma coisa. Não são. Embutido é sobre armazenamento — os bytes estão dentro do
PDF. Associado é sobre vinculação — a especificação de arquivo está listada em
um array /AF em uma parte do documento, e ela carrega uma AFRelationship. No
modelo PDF abstrato, um arquivo pode ser embutido na name tree sem nunca ser
associado; o caminho embedFile() do NextPDF não o deixa assim — ele sempre
escreve a associação /AF — então, para este motor, a questão em aberto nunca é
se um arquivo está associado, mas o que a relação diz.
Uma segunda armadilha: presumir que um visualizador “vai descobrir” qual anexo é a
fatura. Um leitor conforme não deve adivinhar. Ele procura o arquivo cuja relação
diz Data. Deixe a relação como Unspecified e você terá associado o payload sem
dizer à máquina nada de útil sobre seu papel.
Limites e fronteiras
Seção intitulada “Limites e fronteiras”O mecanismo do contêiner é poderoso de um jeito que vale ser honesto a respeito:
embedFile() lê qualquer caminho que o processo PHP possa ler. Esse é o recurso —
e também é a fronteira. O motor anexa os bytes que recebe; ele não decide, e não
pode decidir, por você se um caminho é um que você pretendia expor.
| Edition | Availability |
|---|---|
| Core |
|
| Pro | Not in this edition |
| Enterprise | Not in this edition |
Dois outros limites valem ser declarados de forma direta:
- Embutir não é validar. O motor carrega os bytes que você lhe dá. Se o XML embutido é um payload de fatura conforme é uma questão separada, respondida por um validador — veja a página de faturamento.
- Um anexo tipado não é, por si só, um arquivo de arquivamento conforme. Tornar o arquivo híbrido um documento PDF/A-3 legal exige o modo de arquivamento e uma verificação de conformidade independente — veja a página de arquivamento.
Documentos relacionados
Seção intitulada “Documentos relacionados”- Faturas e faturamento eletrônico — o
caso de uso que este mecanismo torna possível: um PDF híbrido que carrega uma
fatura legível por máquina como seu arquivo associado
Data. - Arquivamento e PDF/A — por que o portador é um arquivo PDF/A-3 e o que a conformidade promete e não promete.
- A anatomia de um arquivo PDF — onde a name tree e o catálogo do documento ficam na estrutura do arquivo.
- Streams e filtros — como os bytes de um arquivo embutido são armazenados e comprimidos dentro de um objeto stream.
Glossário
Seção intitulada “Glossário”- Stream de arquivo embutido — um objeto stream do PDF que contém os bytes de um arquivo externo, com um dicionário de parâmetros registrando seu tamanho original, datas e um checksum (ISO 32000-2 §7.11.4).
- Name tree EmbeddedFiles — o mapa ordenado no catálogo do documento que lista os arquivos embutidos por nome, de modo que um leitor pode enumerar anexos sem varrer o documento inteiro.
- Arquivo associado — um arquivo embutido vinculado a uma parte do documento
por uma associação
/AF(no catálogo do documento, em uma página ou em um objeto) e carregando umaAFRelationshipque declara como ele se relaciona com esse conteúdo; o caso em nível de documento — a especificação de arquivo no array/AFdo catálogo — é o que esta página centraliza (ISO 32000-2 §14.13.3). - AFRelationship — a chave da especificação de arquivo cujo valor nomeia a
relação (ISO 32000-2 §7.11.3). Ela assume um de oito valores padrão (
Source,Data,Alternative,Supplement,EncryptedPayload,FormData,Schema,Unspecified) ou um valor customizado;Dataé o valor que um payload de e-fatura híbrida usa. - PDF/A-3 — o perfil de arquivamento ISO 19005-3 que permite embutir arquivos de qualquer formato, viabilizando um documento híbrido conforme.
- Fatura híbrida — um único arquivo PDF que é tanto uma página legível por humano quanto um payload de fatura embutido legível por máquina.