Technisch artikel

PDF 2.0-, PDF/A-4- en PDF/UA-2-uitvoer met HotPDF in Delphi

HotPDF schrijft native PDF 2.0-documenten vanuit Delphi en C++Builder, inclusief de drie PDF/A-4-archiefprofielen en PDF/UA-2-toegankelijke uitvoer met namepaced structuurelementen. Ze selecteren is een kwestie van twee eigenschappen, maar de standaarden achter die eigenschappen veranderden meer dan het versienummer suggereert: PDF/A-4 liet de conformance-letters vallen die iedereen bij PDF/A-2 leerde, en PDF/UA-2 introduceerde structuurnaamruimten die een deel-1-document nooit had

Dit artikel behandelt wat er werkelijk verandert in het gegenereerde bestand, en welke fouten HotPDF bij EndDoc in een exception verandert in plaats van in een document dat bij de klant faalt bij validatie

Hoe PDF/A-4-identificatie verschilt van deel 2 en 3

PDF/A-4 identificeert zich met deelnummer en revisiejaar, zonder conformance-letter voor het basisdeel. Zet PDFACompliance op '4' en HotPDF emitteert pdfaid:part=4 met pdfaid:rev=2020 en helemaal geen pdfaid:conformance-entry. De letter is niet verloren gegaan — deel 4 heeft geen A/B/U-niveaus, omdat de vereisten die ze vroeger scheidden in het basisdeel zijn gevouwen

Twee extensies behouden een letter. '4E' selecteert PDF/A-4e voor technische documenten en emitteert conformance E, dat de 3D- en RichMedia-annotatiepaden toestaat die de andere profielen verbieden. '4F' selecteert PDF/A-4f en emitteert conformance F, dat een ingesloten bestand van elk formaat toestaat. Alle drie forceren een PDF 2.0-header, vereisen de gebruikelijke PDF/A-output-intent en metagegevenscontroles, en verbieden versleuteling — een versleuteld archiefbestand is een tegenspraak die de standaard niet onderhoudt

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archive.pdf';
    Pdf.PDFACompliance := '4F';   // PDF/A-4f: associated files of any format
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 760, 0, 'Invoice 2026-0731');
    Pdf.AddPDFAssociatedFile('invoice.xml', 'text/xml',
      'Structured invoice data', 'Data', LoadInvoiceBytes);
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

AddPDFAssociatedFile sluit het bestand in, bouwt zijn FileSpec met een /AFRelationship, en registreert het in zowel de Catalog-/AF-array als de EmbeddedFiles-naamruimteboom. Beide registraties zijn vereist; een bestand dat slechts in een van beide staat, is de meest voorkomende reden waarom een hybride factuur een snelle visuele controle doorstaat en een echte validator faalt. De relatie-tekenreeks accepteert Source, Data, Alternative, Supplement of Unspecified, en het actieve profiel moet PDF/A-3, PDF/A-4e of PDF/A-4f zijn — het basis-profiel van deel 4 admisseert geen associated files. De oudere naam AddPDFA3AssociatedFile werkt nog voor bestaande code

Wat PDF/UA-2 vraagt dat PDF/UA-1 niet vroeg

PDF/UA-2 forceert PDF 2.0 en emitteert pdfuaid:part=2 met pdfuaid:rev=2024, en het introduceert naamruimten in de structuurboom. Een deel-1-document had één vlakke woordenschat van standaardrollen. Een deel-2-document kan custom rollen meedragen zolang elk bij een gedeclareerde naamruimte hoort, wat domeinspecifieke tagging leesbaar maakt voor hulptechnologie in plaats van giswerk

Twee methoden implementeren dit. RegisterStructureNamespace maakt een indirect /Type /Namespace-dictionary aan of hergebruikt het, en legt het vast in StructTreeRoot /Namespaces, waarbij het dictionary wordt teruggegeven zodat je het kunt hergebruiken. AddStructureElementNS maakt een structuurelement waarvan de /NS-entry naar dat dictionary wijst, wat is wat een rolnaam buiten de standaardverzameling licentieert. Herhaalde aanroepen met dezelfde URI hergebruiken één dictionary in plaats van duplicates op te stapelen

var
  Root: THPDFDictionaryObject;
begin
  Pdf.PDFUACompliance := True;
  Pdf.PDFUAPart := 2;             // part 2 forces PDF 2.0
  Pdf.Lang := 'en-US';
  Pdf.BeginDoc;
  Root := Pdf.AddStructureElement('Document', nil);
  Pdf.AddStructureElementNS('WidgetGroup',
    'https://example.com/ns/widgets', Root);
  Pdf.EndDoc;
end;

Lang is hier geen decoratie. Een getagd document zonder gedeclareerde natuurlijke taal laat een screenreader gissen naar uitspraak, en PDF/UA behandelt de weglating als een defect in plaats van een voorkeur

Welke structuurfouten vangt EndDoc?

Vier, en elk komt overeen met een document dat anders gebroken bij een validator zou aankomen. De structuurwortel moet precies één top-level Document-element bevatten. Elk naamruimte-dictionary moet indirect zijn, getypeerd als Namespace, en een unieke niet-lege URI meedragen. Elke /NS-referentie van een structuurelement moet resolven naar een dictionary dat daadwerkelijk in de array /Namespaces van de wortel staat. En een rol zonder naamruimte moet een PDF 2.0-standaardrol zijn of resolven via de RoleMap

Deze vuren bij EndDoc omdat dat het laatste moment is waarop de hele boom in geheugen bestaat en het eerste moment waarop hij compleet is. Ze eerder vangen zou betekenen geldige tussenstadia af te wijzen; ze later vangen zou betekenen ze helemaal niet te vangen. Het praktische gevolg voor je code is dat een structuurbug aan het einde van de generatie naar boven komt met een boodschap die het probleem benoemt, in plaats van weken later naar boven te komen als een veraPDF-rapport dat iemand doorstuurt van een klant

De PDF 2.0-rollen die de moeite waard zijn om te kennen

De getypeerde rol-enum wint DocumentFragment, Aside, Title, FENote, Sub, Em, Strong en Artifact. Drie daarvan veranderen hoe je gewone bedrijfsdocumenten tagt. Aside geeft zijbalken en pull-quotes eindelijk een thuis dat geen verkeerd gebruikte Sect is. FENote markeert voet- en eindnoten als wat ze zijn, zodat een reader ze kan aanbieden in plaats van ze met de body-tekst te interleaven. Em en Strong vervangen het semantische giswerk dat voortkwam uit nadruk taggen als span-level opmaak

De tekenreeks-overload accepteert bovendien de open Hn-vorm, inclusief H7 en verder. PDF 1.7 stopte bij H6, wat diepe technische documenten dwong hun outline plat te slaan of niveaus te hergebruiken. Als je standaarddocumenten, wetteksten of onderdelen-catalogi genereert, kan dit alleen al de reden zijn om uitvoer naar PDF 2.0 te verplaatsen

Wat te controleren vóór het omschakelen van productie-uitvoer

PDF 2.0 is een headerwijziging met een lange staart. Oudere archief-inbouwhulpmiddelen, sommige druk-RIPs en een verrassend aantal line-of-business-viewers accepteren slechts tot PDF 1.7, en ze falen op de header in plaats van op iets wat je verkeerd deed. Controleer vóór het omschakelen de verbruikende systemen, en onthoud dat het selecteren van een PDF/A-4-profiel PDF 2.0 selecteert of je erom vroeg of niet

Een veilige volgorde is PDF/A-3 behouden voor documenten die naar onbekende lezers gaan, PDF/A-4f gebruiken voor interne archieven waar jij de inbouw beheert, en PDF/UA-2 alleen aannemen waar het toegankelijkheidsbeleid het noemt. Als je eerst de archiefkant uitwerkt, dekken de gidsen voor PDF/A-, PDF/X- en PDF/UA-validatie en voor ZUGFeRD- en Factur-X-hybride facturen op PDF/A-3 de profielkeuzes die meer voor het versienummer uitmaken, en de notities over geautomatiseerde preflight-rapportage laten zien hoe je het verdict onderdeel van je build maakt in plaats van een handmatige stap

HotPDF levert het hele PDF 2.0-ontwerpopvlak als native VCL-code voor Delphi en C++Builder, zodat PDF/A-4- en PDF/UA-2-uitvoer geen externe engine of herdistributable nodig hebben — de HotPDF-componentpagina somt de ondersteunde profielen en RAD Studio-versies op