Technisch artikel

PDF/A-, PDF/X- en PDF/UA-output in Delphi: HotPDF-gids

PDF/A, PDF/X en PDF/UA zijn drie verschillende standaarden die drie verschillende problemen oplossen: langetermijnarchivering, printuitwisseling en toegankelijkheid. Het zijn geen drie selectievakjes op één compliance-formulier, en de meest voorkomende fout is ze zo te behandelen. Een bestand kan foutloze PDF/A zijn en nutteloos voor een drukkerij; een perfecte printmaster kan onleesbaar zijn voor een schermlezer. Erger nog, alle drie zijn ze beperkingen op de interne structuur van het bestand, niet op hoe het eruitziet. Een document dat in elke viewer die u bezit probleemloos opent, kan bij de eerste validatiepoging toch falen, en meestal doet het dat ook

HotPDF, de native VCL PDF-bibliotheek van losLab, behandelt conformiteit als iets dat u declareert voordat de eerste pagina bestaat. U stelt een compliance-eigenschap in, koppelt de structuren die de standaard vereist, en de bibliotheek weigert configuraties die met het profiel in tegenspraak zijn bij het opslaan. Dat is een beter model dan een bestand genereren en hopen dat een postprocessor het achteraf kan aanpassen, want het meeste van wat deze standaarden vereist kan niet achteraf worden toegevoegd

Drie ISO-standaarden, drie verschillende beloften

PDF/A (ISO 19005) gaat over tijd. Het belooft dat een bestand tientallen jaren later nog identiek rendert, dus het eist volledige zelfcontainment: elk lettertype ingebed, elke kleur apparaatonafhankelijk betekend via een OutputIntent, volledige XMP-metadata, en een verbod op alles waarvan het gedrag van de omgeving afhangt. Versleuteling en JavaScript vallen af, want niemand kan garanderen dat de ontsleutelaar of de scriptengine in 2050 nog bestaat

PDF/X (ISO 15930) gaat over kleur op papier. Het bestaat zodat een ontwerper een bestand aan een drukkerij kan overhandigen dat geen van beiden hoeft te bespreken, wat gekarakteriseerde drukomstandigheden betekent, een verplichte /Trapped-key, gedefinieerde snij- en bleed-geometrie, en, in de X-1a-variant, geen live transparantie waar de RIP naar moet raden. PDF/UA (ISO 14289) gaat over wie het resultaat kan lezen. Hulptechnologie heeft een volledige tag-structuur nodig, een logische leesvolgorde, een gedeclareerde documenttaal, en tekstalternatieven voor alles wat geen tekst is

Omdat de drie in verschillende richtingen trekken, kiest u de leidende standaard per outputkanaal in plaats van één bestand na te jagen dat ze alle drie bevredigt. Een CMYK-only printmaster is precies het verkeerde om een schermlezer-gebruiker te overhandigen die nooit kleur ziet, en de lockdown van het archiefprofiel op dynamisch gedrag botst met alles wat interactief is. Genereer per kanaal vanuit dezelfde brongegevens en u omzeilt het hele conflict

HotPDF genereert PDF/A-, PDF/X- en PDF/UA-bestanden per uitvoerkanaal vanuit één brondocument in Delphi, waarbij elke ISO-standaard een andere structurele belofte inhoudt
PDF/A, PDF/X en PDF/UA trekken in verschillende richtingen, dus HotPDF genereert één bestand per uitvoerkanaal vanuit dezelfde bron

PDF/A: de OutputIntent is het deel dat iedereen vergeet

Als een PDF/A-bestand validatie faalt, is de OutputIntent het eerste om te controleren. Het is de structuur die generatoren het vaakst overslaan, juist omdat niets zichtbaars ervan afhangt. ISO 19005 vereist er een: een ingebed ICC-profiel dat vastpint wat de apparaatkleuren van het document werkelijk betekenen. HotPDF maakt dat profiel een expliciete input in plaats van een bijgedachte:

var
  Pdf: THotPDF;
  ICC: TFileStream;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archival.pdf';
    Pdf.PDFACompliance := 'B';            // level B: visual fidelity
    Pdf.Lang := 'en-US';
    Pdf.StandardFontEmulation := False;   // embed echte fonts, geen Base-14-emulatie
    ICC := TFileStream.Create('sRGB.icc', fmOpenRead);
    try
      Pdf.AddPDFAOutputIntent('sRGB IEC61966-2.1', '', ICC, 3, 'DeviceRGB');
    finally
      ICC.Free;
    end;
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 760, 0, 'Archival invoice body');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Een paar details bepalen hier slagen of falen. StandardFontEmulation moet uit: geëmuleerde Base-14-lettertypen worden niet ingebed, en inbedding is niet onderhandelbaar onder ISO 19005. Versleuteling moet uitgeschakeld blijven, dus combineer PDFACompliance nooit met ActivateProtection; een versleuteld archiefbestand is een tegenspraak die de validator onmiddellijk vangt. Het componentaantal in AddPDFAOutputIntent moet overeenkomen met het profiel, wat 3 is voor een RGB-profiel zoals sRGB IEC61966-2.1 en 4 voor CMYK. HotPDF volgt DeviceRGB- en DeviceCMYK-gebruik tegen de gedeclareerde intentie tijdens het schrijven, dus een verdwaalde CMYK-vulling in een RGB-intent-document wordt een gerapporteerd probleem in plaats van een stil probleem

Eén ding dat de moeite waard is om over het ICC-profiel te zeggen: behandel het als een geversioneerd deployment-artefact, niet als een bestand dat iemand ooit op de buildserver heeft gedropt. Zijn bytes worden in elk document dat u genereert ingebed, dus een afgekapt of corrupt profiel vergiftigt stilletjes een hele batch, en u merkt het pas bij validatie. Lever het met uw installer mee, registreer zijn checksum in het run-log, en laad het via het TFileStream-patroon hierboven zodat een ontbrekend bestand luidruchtig faalt tijdens generatie in plaats van stilletjes bij de archiefpoort

PDF/X voor druk: Trapped, CMYK en het persprofiel

Printmasters keren het kleurverhaal om. De pers wil gekarakteriseerde CMYK, en de standaard laat u verklaren of trapping is toegepast, ook wanneer het eerlijke antwoord is dat u het niet weet. De /Trapped-key is hoe dan ook verplicht:

Pdf.PDFXCompliance := 'X-1a';
Pdf.Trapped := 'Unknown';        // verplichte key onder ISO 15930
ICC := TFileStream.Create('FOGRA39.icc', fmOpenRead);
try
  Pdf.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)', '', ICC, 4, 'DeviceCMYK');
finally
  ICC.Free;
end;
Pdf.BeginDoc;
// teken met CMYK-veilige kleuren, geen transparantie, geen encryptie
Pdf.EndDoc;

Het componentaantal is nu 4 voor het CMYK-persprofiel. X-1a verbiedt ook live transparantie, dus audit elke tekeningcode die doorschijnende elementen laagt; wat een viewer op het scherm samenstelt is precies wat een RIP zal weigeren te interpreteren. Wanneer uw winkel een andere karakterisering meestuurt, wissel dan de profielbytes en de identifier-string maar laat de omringende structuur met rust

PDF/UA: structuur wordt gegenereerd, nooit achteraf toegevoegd

Toegankelijkheid is de standaard die teams het vaakst aan het einde proberen vast te spijkeren, en hij bestraft die aanpak harder dan de andere twee. De tag-structuur moet de volgorde spiegelen waarin de inhoud logisch is gecreëerd, en dat is informatie die u eenvoudig niet meer hebt zodra het bestand is geschreven. PDFUACompliance instellen zet gelabelde output aan, en de structuur-API bindt elke tekenaanroep aan zijn semantische rol terwijl u gaat:

HotPDF bouwt de PDF/UA-tagboom live terwijl elke Delphi-tekenaanroep wordt uitgevoerd, en tekst uitgezonden buiten BeginTaggedContent en EndTaggedContent blijft onzichtbaar voor screenreaders
De tag-boom wordt geschreven terwijl je tekent, en tekst buiten een getagd paar rendert prima maar blijft onzichtbaar voor screenreaders
Pdf.PDFUACompliance := True;     // zet tagged PDF automatisch aan
Pdf.Lang := 'en-US';             // expliciet gezet; leeg valt terug op 'en'
Pdf.BeginDoc;

Root := Pdf.AddStructureElement(sstDocument, nil);
H1 := Pdf.EmitTaggedHeading(1, Root, 50, 700, 'Quarterly Report');
Para := Pdf.BeginTaggedContent('P', Root);
Pdf.CurrentPage.TextOut(50, 650, 0, 'Revenue grew in all regions.');
Pdf.EndTaggedContent;

Pdf.EndDoc;

De fout om op te letten is tekst die buiten elk BeginTaggedContent/EndTaggedContent-paar wordt getekend. Het rendert perfect en blijft onzichtbaar voor een schermlezer, dus geen ziende tester vangt het ooit; de bug wordt verscheept en komt pas bovendrijven wanneer een werkelijke hulptechnologie-gebruiker de kloof raakt. Wanneer uw sjablonen aangepaste structuur-rol-namen dragen, map ze op de standaardset met AddStructRoleMap('MyHead', 'H1') zodat conforme readers weten wat ze betekenen. ISO 14289 vereist ook een gedeclareerde taal. HotPDF valt terug op 'en' wanneer Lang leeg is, maar dat is een vangnet, geen reden om de werkelijke documenttaal oningesteld te laten

Verificatie: vertrouw de validator, niet de viewer

Een viewer die uw bestand opent bewijst niets over conformiteit, dus verificatie hoort in het release-pad met tools die structuur controleren in plaats van rendering. Voor PDF/A en PDF/UA is veraPDF de referentie-gegrade open validator; hij rapporteert fouten per ISO-clausule, wat rechtstreeks terugmapt op de configuratie hierboven. Voor PDF/X zijn Adobe Acrobats Preflight-profielen nog steeds de praktische controle, want persconformiteit gaat net zo zeer over kleurintentie als over syntaxis

De generator doet zijn eigen deel hiervan. Bij het opslaan rekent HotPDF de feature-vlaggen uit tegen de geconfigureerde PDF-versie, en downgradet stilzwijgend wat de versie niet kan uitdrukken, zoals AES-256 dat naar AES-128 zakt onder PDF 1.7. De compliance-gates in EndDoc gaan verder en raisen ronduit bij harde tegenspraken, zoals PDFACompliance vragen samen met versleuteling. Geen van beide vervangt de externe validator. Ze voorkomen slechts dat onmogelijke configuraties hem ooit bereiken

HotPDF-compliancepoorten in EndDoc vangen onmogelijke configuraties af voordat veraPDF PDF/A en PDF/UA valideert en Acrobat Preflight PDF/X valideert in een Delphi-releasepad
HotPDF weigert tegenstrijdige configuraties bij EndDoc, en onafhankelijke validators beslissen over echte conformiteit

Eén gewoonte betaalt zich herhaaldelijk uit: versioneer de hele compliance-setup als één eenheid. De HotPDF-release, de sjabloonrevisie, de ICC-profielchecksum, de validator-build die aftekende. Conformiteit drijft weg zodra één van hen onder de andere verandert, en de lelijkste audits zijn die waarbij niemand meer kan reconstrueren welke combinatie een vijf jaar oud archiefbestand produceerde. Eén configuratierecord per batch regelt dat voorgoed

Tot slot, draai de validator op echte productieoutput, nooit op een net handgebouwd voorbeeld. De fouten die bijten komen van data die niemand anticiperen kon: een klantenlogo dat als CMYK binnenkomt terwijl de intentie RGB zegt, een sjabloon-aanpassing die een niet-ingebed lettertype binnensluipt, een nieuw codepad dat tekst buiten de tag-structuur tekent. Houd per incident uit het verleden één bekend-slecht bestand aan als regressie-input en de compliance-poort blijft in de loop der tijd eerlijk. Voor de rendering-kant van deze pipelines, zie ons artikel over rapportoutput, lettertypen en afbeeldingen met HotPDF; voor het inbedden van validators in een build is er een begeleidend stuk over het automatiseren van PDF-preflight-controles

De compliance-eigenschappen, output-intents en tagging-API die in deze voorbeelden gebruikt worden, worden geleverd met de HotPDF Delphi Component voor Delphi en C++Builder; de productpagina linkt de volledige referentie voor elke aanroep die hier getoond wordt