Een PDF is een container: ingebedde bestanden en bijbehorende gegevens
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
In een oogopslag
Sectie met titel “In een oogopslag”De meeste mensen stellen zich een PDF voor als een stapel pagina’s. Dat is het deel dat je ziet. Maar een PDF is ook een container, en hij kan hele andere bestanden in zich dragen — een spreadsheet, een XML-payload, het oorspronkelijke brondocument — gebundeld in hetzelfde enkele bestand dat je aan iemand anders overhandigt.
Deze pagina legt uit hoe dat werkt: de embedded-file stream die de bytes opslaat, de name tree die ze opsomt, en de ene sleutel die bepaalt of een bijlage daar alleen maar staat of werkelijk iets betekent.
Waarom dit belangrijk is
Sectie met titel “Waarom dit belangrijk is”Een ongetypeerde bijlage en een getypeerde zien er voor een mens identiek uit. Beide zijn een bestand dat binnen in een PDF meereist en — in deze engine — zijn beide met het document geassocieerd. Het verschil is dat een van beide een machine vertelt waarvoor het dient, en de andere de relatie blanco laat zodat de machine moet gokken.
Dat verschil is bij een hybride e-factuur de hele inzet. Een belastingplatform leest jouw factuurpagina niet; het leest de XML die je hebt ingebed. Als die XML is bijgevoegd als een ongedifferentieerde blob in plaats van als de factuurgegevens voor het zichtbare document, heeft een conforme reader geen betrouwbare manier om te weten dat het de te verwerken payload is. De pagina ziet er perfect uit. De factuur wordt afgewezen. Het falen komt dagen later, met een geblokkeerde betaling erachter.
De relatie goed krijgen, in de laag die het bestand produceert, is veel goedkoper dan het ontdekken per afgewezen factuur.
De korte versie
Sectie met titel “De korte versie”- Een PDF kan de bytes van elk bestand inbedden als een embedded file stream (Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4). De stream draagt de gegevens plus een kleine parameters dictionary: oorspronkelijke grootte, data en een checksum.
- Ingebedde bestanden worden gecatalogiseerd in de
EmbeddedFilesname tree, zodat een reader ze op naam kan opsommen zonder het hele document te scannen. - Een bijbehorend bestand gaat een stap verder: het declareert een
AFRelationship(Spec: ISO 32000-2, §7.11.3ISO 32000-2 §7.11.3) — een van acht standaardwaarden (Source,Data,Alternative,Supplement,EncryptedPayload,FormData,Schema,Unspecified), of een aangepaste waarde — die zegt hoe het bestand zich verhoudt tot de inhoud waaraan het is bijgevoegd. - Die getypeerde relatie is het mechanisme achter hybride e-facturen (ZUGFeRD / Factur-X) en PDF/A-3-bijlagen (Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3).
- NextPDF ondersteunt de ruwe container-primitieven in core:
embedFile()enembedFileFromString()met een expliciete relatie. Advanced edities voegen de speciale EN 16931 / ZUGFeRD / Factur-X e-factuur-embedder bovenop deze primitieven toe.
Hoe NextPDF dit aanpakt
Sectie met titel “Hoe NextPDF dit aanpakt”Zie het als twee lagen op elkaar gestapeld.
De onderste laag is opslag. Een embedded file stream
(Spec: ISO 32000-2, §7.11.4ISO 32000-2 §7.11.4) is de bytes van het
oorspronkelijke bestand verpakt in een PDF stream-object, met een parameters
dictionary die de oorspronkelijke grootte, wijzigingsdatum en een checksum van de
niet-gecomprimeerde gegevens vastlegt. De stream wordt bereikt via een file
specification dictionary waarvan de /EF-dictionary naar de embedded file stream
wijst — de stream zelf draagt geen /EF. Een reader kan het bestand er byte voor
byte weer uithalen. Om deze bestanden vindbaar te maken houdt de document catalog
een EmbeddedFiles name tree bij — een gesorteerde afbeelding van een naam naar
elke file specification — zodat een viewer “hier zijn de 3 bestanden in deze PDF”
kan opsommen zonder elke pagina te doorlopen.
De bovenste laag is betekenis. Op zichzelf is een ingebed bestand slechts
aanwezig. Het associated-files-mechanisme
(Spec: ISO 32000-2, §14.13ISO 32000-2 §14.13) bindt een bestand aan iets —
het hele document, een pagina, een grafisch object — en bestempelt het met een
AFRelationship. ISO 32000-2 definieert een kleine woordenschat van acht
standaardwaarden (Spec: ISO 32000-2, §7.11.3ISO 32000-2 §7.11.3), en staat ook
aangepaste waarden toe; elke standaardwaarde beantwoordt een precieze vraag:
AFRelationship | Wat het beweert over het bestand |
|---|---|
Source | Dit is het bronmateriaal waarvan de zichtbare inhoud is gegenereerd (bijvoorbeeld het oorspronkelijke tekstverwerkerdocument). |
Data | Dit zijn gestructureerde gegevens die aan de zichtbare inhoud zijn gekoppeld — het canonieke geval is de factuur-XML achter een gerenderde factuurpagina. |
Alternative | Dit is een alternatieve weergave van dezelfde inhoud (bijvoorbeeld een audio- of videoversie). |
Supplement | Dit is aanvullend materiaal dat de inhoud uitbreidt maar er geen deel van uitmaakt. |
EncryptedPayload | Het ingebedde bestand is een versleutelde payload die de PDF als een ondoorzichtige blob omhult. |
FormData | Het bestand is formuliergegevens (FDF, XFDF of een XML-formulierpayload). |
Schema | Het bestand is een schema dat de structuur van een Data-bestand beschrijft (bijvoorbeeld een XSD voor XML-gegevens of een JSON Schema). |
Unspecified | De relatie is met opzet niet vermeld. Eerlijk, maar het vertelt een machine niets. |
Naast deze acht staat de standaard ook applicatiespecifieke aangepaste relatiewaarden toe, zodat de woordenschat uitbreidbaar is in plaats van vast.
Een bijbehorend bestand wordt bepaald door twee dingen die samenwerken, niet door
één sleutel alleen. De /AF-associatie bindt de file specification aan een deel
van het document; de AFRelationship-sleutel in de file specification vermeldt
vervolgens de semantische relatie. De /AF-vermelding op het associatiepunt (de
document catalog, een pagina of een object) is een array — die array bevat een
of meer file specification dictionaries, meestal als indirecte referenties; /AF
is geen enkele referentie. Een bijbehorend bestand op documentniveau is de file
specification die wordt vermeld in de /AF-array van de document catalog, met zijn
AFRelationship. Markeer dat spreadsheet als Unspecified en je hebt het met het
document geassocieerd maar een machine niets verteld over waarom. Markeer
hetzelfde spreadsheet als Data en je hebt elke conforme reader verteld wat het
is en waarvoor het dient. De bytes zijn hetzelfde. De semantiek niet.
Dit is waarom het e-factuurgeval niet “voeg een XML-bestand bij” is. Het is “bed
deze XML in als het Data-bijbehorende bestand voor dit document, binnen een
conforme PDF/A-3-drager” — waarbij factuurgeldigheid en juridische acceptatie
afzonderlijke controles blijven die de drager niet uitvoert. De flow heeft vier
fasen, en de volgorde is wat hem correct houdt.
- Store the bytesThe file is wrapped in an embedded file stream with its size, dates, and a checksum (ISO 32000-2 §7.11.4).
- Register it by nameThe file specification is added to the EmbeddedFiles name tree so a reader can enumerate attachments without scanning the document.
- Declare the relationshipAn AFRelationship value (one of the eight standard values such as Source or Data) marks how the file relates to the content, associated at the document level (ISO 32000-2 §14.13.3).
- Make it archivalA PDF/A-3 carrier permits the embedded payload to ride inside one conforming archival PDF/A document; invoice validity and legal acceptance remain separate checks (ISO 19005-3).
Die vierde fase is waarom PDF/A-3 als een apart profiel bestaat. Eerdere
archiveringsprofielen beperkten wat ingebed mocht worden; PDF/A-3
(Spec: ISO 19005-3, PDF/A-3ISO 19005-3 PDF/A-3) is het deel dat bestanden van
elk formaat toestaat om binnen een conform archiveringsdocument mee te reizen.
Het staat de ingebedde payload toe — het valideert die payload niet en verleent
geen juridische status. Zonder het zou de hybride factuur — één bestand dat zowel
de pagina is die een persoon leest als de gegevens die een belastingsysteem
parseert — helemaal geen conform archief-PDF/A-document kunnen zijn; of de factuur
geldig en juridisch geaccepteerd is, blijft een afzonderlijke vraag. De
speciale e-factuur-embedder die Advanced edities toevoegen is de
gemaksnaad over precies dit: hij bedt de payload in, zet de relatie op Data en
registreert die correct, zodat je het container-leidingwerk niet met de hand in
elkaar zet. De diepere factuur- en archiveringsmechaniek staat op de twee
naburige pagina’s die hieronder worden gelinkt; deze pagina gaat over de container
waarop ze beide staan.
Praktisch voorbeeld
Sectie met titel “Praktisch voorbeeld”Een klein, compleet programma. De twee aanroepen die ertoe doen zijn het verschil
tussen een ongetypeerd bijbehorend bestand en een getypeerd — en de relatie is
een expliciet argument dat je hoort te zetten. In deze engine produceren beide
aanroepen een bijbehorend bestand: embedFile() en embedFileFromString()
registreren de file specification altijd in de /AF-array van de document catalog,
zodat het enige wat de relatie verandert is wat de associatie betekent. Hij valt
standaard terug op Unspecified, wat het bestand associeert maar een machine niets
vertelt over waarom; voor een e-factuur-payload zet je hem op Data zodat een
reader hem kan vinden.
<?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();De '/Data'-relatie is onmiskenbaar. De eerste bijlage — gelaten op
Unspecified — is evengoed geassocieerd, alleen zonder een vermelde betekenis.
Voor beide aanroepen schrijft de engine de embedded file stream, voegt het bestand
toe aan de EmbeddedFiles name tree, vermeldt zijn file specification in de
/AF-array van de document catalog en legt de relatie vast die je hebt opgegeven —
hij kiest er geen voor je. Deze engine heeft geen modus met alleen-name-tree: elk
bestand dat je op deze manier inbedt is een document-geassocieerd bestand, dus de
relatie is de enige hendel die je beheert.
Veelvoorkomend misverstand
Sectie met titel “Veelvoorkomend misverstand”De veelgehoorde aanname is dat “embedded” en “associated” twee woorden voor
hetzelfde zijn. Dat zijn ze niet. Embedded gaat over opslag — de bytes zitten in
de PDF. Associated gaat over binding — de file specification staat in een
/AF-array op een deel van het document, en draagt een AFRelationship. In het
abstracte PDF-model kan een bestand in de name tree worden ingebed zonder ooit
geassocieerd te zijn; het embedFile()-pad van NextPDF laat het daar niet bij —
het schrijft altijd de /AF-associatie — dus voor deze engine is de open vraag
nooit of een bestand geassocieerd is maar wat de relatie zegt.
Een tweede valkuil: aannemen dat een viewer “wel uitvogelt” welke bijlage de
factuur is. Een conforme reader hoort niet te gokken. Hij zoekt naar het bestand
waarvan de relatie Data zegt. Laat de relatie Unspecified en je hebt de
payload geassocieerd terwijl je de machine niets nuttigs over zijn rol hebt
verteld.
Grenzen en beperkingen
Sectie met titel “Grenzen en beperkingen”Het containermechanisme is krachtig op een manier die het waard is om eerlijk over
te zijn: embedFile() leest welk pad het PHP-proces ook maar kan lezen. Dat is de
functie — en het is ook de grens. De engine voegt de bytes toe die hem worden
gegeven; hij beslist niet, en kan niet beslissen, voor jou of een pad er een is dat
je bedoelde bloot te leggen.
| Edition | Availability |
|---|---|
| Core |
|
| Pro | Not in this edition |
| Enterprise | Not in this edition |
Nog twee grenzen die het waard zijn om duidelijk te benoemen:
- Inbedden is niet valideren. De engine draagt de bytes die je hem geeft. Of de ingebedde XML een conforme factuur-payload is, is een afzonderlijke vraag, beantwoord door een validator — zie de factuurpagina.
- Een getypeerde bijlage is op zichzelf geen conform archiveringsbestand. Het hybride bestand een wettelijk PDF/A-3-document maken vereist de archiveringsmodus en een onafhankelijke conformiteitscontrole — zie de archiveringspagina.
Verwante documentatie
Sectie met titel “Verwante documentatie”- Facturen en e-facturatie — de use
case die dit mechanisme mogelijk maakt: een hybride PDF die een
machineleesbare factuur draagt als zijn
Data-bijbehorende bestand. - Archivering en PDF/A — waarom de drager een PDF/A-3-bestand is en wat conformiteit wel en niet belooft.
- De anatomie van een PDF-bestand — waar de name tree en de document catalog in de bestandsstructuur zitten.
- Streams en filters — hoe de bytes van een ingebed bestand worden opgeslagen en gecomprimeerd binnen een stream-object.
Woordenlijst
Sectie met titel “Woordenlijst”- Embedded file stream — een PDF stream-object dat de bytes van een extern bestand bevat, met een parameters dictionary die zijn oorspronkelijke grootte, data en een checksum vastlegt (ISO 32000-2 §7.11.4).
- EmbeddedFiles name tree — de gesorteerde afbeelding in de document catalog die ingebedde bestanden op naam opsomt, zodat een reader bijlagen kan opsommen zonder het hele document te scannen.
- Bijbehorend bestand — een ingebed bestand dat aan een deel van het document
is gebonden door een
/AF-associatie (op de document catalog, een pagina of een object) en dat eenAFRelationshipdraagt die vermeldt hoe het zich verhoudt tot die inhoud; het geval op documentniveau — de file specification in de/AF-array van de catalog — is degene waar deze pagina om draait (ISO 32000-2 §14.13.3). - AFRelationship — de file-specification-sleutel waarvan de waarde de relatie
benoemt (ISO 32000-2 §7.11.3). Hij neemt een van acht standaardwaarden aan
(
Source,Data,Alternative,Supplement,EncryptedPayload,FormData,Schema,Unspecified) of een aangepaste waarde;Datais de waarde die een hybride e-factuur-payload gebruikt. - PDF/A-3 — het ISO 19005-3-archiveringsprofiel dat toestaat dat bestanden van elk formaat worden ingebed, waardoor een conform hybride document mogelijk wordt.
- Hybride factuur — één PDF-bestand dat zowel een menselijk leesbare pagina is als een machineleesbare ingebedde factuur-payload.