PDFlibPas validerar PDF/UA-2-filer (ISO 14289-2) i Delphi via TPDFlib.CheckFilePDFUACompliance med måldel 2, vilket kör en separat PDF/UA-2-profil: rollerna i strukturträdet löses genom PDF 2.0-namnrymder och /RoleMapNS, trunkerad eller oläsbar indata rapporteras som ett fel, och resultatet är en täckningsrapport som aldrig påstår full certifiering
Den sista delen betyder mer än det låter. Tillgänglighetsvalidering är ett område där en grön bock kopieras in i en upphandlingskalkyl och aldrig ifrågasätts igen. En validator som i tysthet hoppar över halva standarden och ändå skriver ut "pass" är värre än ingen validator, eftersom den förvandlar ett okänt utfall till en falsk upplysning. PDFlibPas tar den motsatta ståndpunkten: kontrollera det som går att kontrollera maskinellt, säg högt vad som inte kontrollerades, och behandla varje "kunde inte slutföras" som ett fynd snarare än en framgång
Varför går det inte att validera PDF/UA-2 med PDF/UA-1-regler?
PDF/UA-2 är inte PDF/UA-1 med ett nummer i spetsen. PDF/UA-1 vilar på PDF 1.7 och en enda platt rollmap; PDF/UA-2 vilar på PDF 2.0 (ISO 32000-2), där varje strukturelement kan tillhöra en namnrymd och varje namnrymd har sin egen rollmap. En UA-1-kontroll riktad mot en UA-2-fil missar både verkliga problem och hittar på falska
De falska är den pinsamma delen. PDF/UA-1-validatorer brukar kräva att Note-element bär ett ID och reglerar hur den onumrerade rubriken H får användas. Ingen av reglerna bär över. I PDF 2.0:s strukturnamnrymd uttrycks fotnoter med FENote, och rubriker är H1 till Hn utan något tak på sex nivåer. PDF/UA-2 går längre och förbjuder den onumrerade rollen H helt och hållet. Riktas UA-1-rubriklogik mot det trädet klagar du antingen på saker standarden tillåter eller släpper igenom det enda den förbjuder
Därför är PDFlibPas PDF/UA-2-profil en egen kodväg, inte en flagga på den gamla. Den vägrar också återanvända UA-1:s klausulnummer. Diagnostik som delas med UA-1-kontrollen binds om till ISO 14289-2 i UA-2-rapporter, och där ett klausulnummer inte har verifierats mot standardtexten lämnar rapporten klausulfältet tomt i stället för att gissa. En tom klausul är mindre tillfredsställande än ett självsäkert klausulnummer, men det är enda försvarbara utdata när ingen har bekräftat mappningen
Så här löser PDFlibPas roller genom RoleMapNS
PDFlibPas löser varje strukturroll till en standardroll i en känd namnrymd, följer /RoleMapNS-kedjor över namnrymder och rapporterar varje kedja som slutar på en egen roll, loopar eller bryter mot mappningsreglerna. Det är kärnan i PDF/UA-2-strukturvalidering, eftersom hjälpmedelsteknik bara förstår standardroller; en egen /InvoiceLine betyder ingenting förrän den landar på något som P eller TR
Lösaren utgår från elementets /S-namn och dess /NS-namnrymd. Utan namnrymd ligger elementet implicit i PDF 1.7:s standardnamnrymd och den äldre /RoleMap i strukturträdets rot gäller. Med en namnrymd gäller namnrymdordlistans egen /RoleMapNS, och en mappning kan peka på en roll i en annan namnrymd via en array med två element. Kontrollerna som kommer ut av detta är konkreta:
- En namnrymd som refereras från ett strukturelement måste vara en indirekt ordlista med en giltig
/NS-URI och måste finnas i strukturträdets rot-array/Namespaces(diagnostik 10054) - En egen roll måste till slut lösa till en standardroll i PDF 1.7-namnrymden, PDF 2.0-namnrymden (
http://iso.org/pdf2/ssn) eller MathML-namnrymden; cirkulära kedjor och återvändsgränder rapporteras som 10055 - En standardroll får inte mappas om till en egen roll, och en roll får inte mappas om inom sin egen explicita namnrymd
- Strukturroten måste innehålla exakt ett
Document-element i PDF 2.0-namnrymden (10057), och varje elements/Pmåste peka på sin faktiska förälder (10058) - En onumrerad
H, eller en äldre PDF 1.7-Notesom inte mappats till en PDF 2.0-roll, rapporteras som 10056
En detalj värd att kopiera in i din egen verktygslåda: PDFlibPas validerar varje deklarerad mappning, inte bara de som är nåbara från trädet. En trasig post i en rollmap som inget element just nu använder är fortfarande en latent defekt, eftersom nästa innehållsuppdatering börjar använda den. MathML hanteras ärligt också. MathML-namnrymden känns igen som ett giltigt lösningsmål, men MathML-vokabulären i sig valideras inte, och täckningsrapporten säger det
Köra en PDF/UA-2-kontroll från Delphi
TPDFlib.CheckFilePDFUACompliance är ingångspunkten med ett anrop: skicka in fil, lösenord, måldel och alternativ, och du får tillbaka ett handtag till en stränglista med kodade problem. Handtag noll med LastErrorCode lika med noll betyder att de implementerade kontrollerna inte hittade något; ett LastErrorCode skilt från noll betyder att anropet i sig misslyckades
var
Lib: TPDFlib;
Issues, I: Integer;
begin
Lib := TPDFlib.Create;
try
// TargetPart: 0 = detektera från XMP pdfuaid:part, 1 = PDF/UA-1, 2 = PDF/UA-2
// Options: 1 = stanna vid första felet, 0 = samla alla problem
Issues := Lib.CheckFilePDFUACompliance('report.pdf', '', 2, 0);
if Issues = 0 then
begin
if Lib.LastErrorCode <> 0 then
Writeln('Validation did not run, error ', Lib.LastErrorCode)
else
Writeln('No issues from the implemented PDF/UA-2 checks');
end
else
try
for I := 1 to Lib.GetStringListCount(Issues) do // posterna är 1-baserade
Writeln(Lib.GetStringListItem(Issues, I));
finally
Lib.ReleaseStringList(Issues);
end;
finally
Lib.Free;
end;
end;
Välj måldel medvetet. Mål 0 läser pdfuaid:part ur XMP-metadata och väljer profil utifrån den, vilket är rätt för en generisk inkorgsvalidator. För din egen utdatapipeline, skicka 2 explicit. Har din generator glömt skriva identifieringen faller autodetekteringen tillbaka på UA-1-reglerna och du validerar fel standard; en explicit 2 ger i stället diagnostik 10050 för den saknade delen, plus 10051 om pdfuaid:rev inte är 2024 och 10052 om den effektiva PDF-versionen inte är 2.0. På författarsidan skriver TPDFlib.SetPDFUA2Mode den identifieringen, höjer versionen till 2.0 och väljer PDF 2.0:s strukturnamnrymd som standard; själva namnrymdmodellen förklaras i genomgången av PDF 2.0-, PDF/A-4- och PDF/UA-2-namnrymder
Vad händer när validatoren tar slut på budget?
PDFlibPas failar stängt (fail closed): när PDF/UA-2-kontrollen stöter på en traverseringsgräns, en cykel, en parsergräns eller ett dokument den inte kan öppna, avger den en diagnostikpost, och ett resultat utan diagnostik främjas aldrig till godkänt. Diagnostik 10059 är reserverad för just fallet "läsaren kunde inte bli klar"
Budgeterna är explicita och publicerade i coverage-JSON:en: strukturdjup 256, 100 000 strukturobjekt och 256 hopp längs valfri rollmap-kedja. De siffrorna finns för att strukturträd kommer från opålitlig indata. En fientlig eller bara trasig fil kan nästla element tusentals nivåer djupt, peka ett barn tillbaka mot en förfader, eller bygga en rollmap som kedjar genom hundratals namnrymder. En validator utan budgetar kraschar eller hänger sig, och en validator med budgetar men utan diagnostik gör något finurligare och värre: den stannar tidigt, hittar inget fel i den del den läste och rapporterar framgång
Samma princip gäller en nivå upp. Returnerar den underliggande läsaren en poäng under 100 men inga problemrader, vilket kan hända när parsningen avbryts innan någon regel hunnit köra, infogar PDFlibPas en 10059-rad så att den tomma listan inte kan tas för ett rent resultat. Ett undantag under kontrollen blir också en 10059-rad. Det är en liten mängd kod, och den stänger den vanligaste vägen som valideringspipelines ljuger för sina ägare
Dela en parsning med PDF/A och bygga en rapport
För batcharbete parsar valideringspipeline-API:et en fil en gång och kör flera kontroller mot den gemensamma parsningen. RunPDFUAValidationPipelineTask är PDF/UA-medlemmen i den familjen och tar samma måldelsvärden som funktionen med ett anrop, vilket gör att en preflight med PDF/A plus PDF/UA-2 slipper betala för två fullständiga läsningar av ett stort dokument
var
Pipe, PDFAIssues, UAIssues: Integer;
Json: WideString;
begin
Pipe := Lib.BeginValidationPipeline('archive.pdf', '');
if Pipe = 0 then
Exit;
try
PDFAIssues := Lib.RunValidationPipelineTask(Pipe, 1, 0); // 1 = PDF/A
UAIssues := Lib.RunPDFUAValidationPipelineTask(Pipe, 2, 0); // PDF/UA-2
// ... inspektera och frisläpp båda handtagen som i föregående exempel ...
Writeln('Parses: ', Lib.GetValidationPipelineParseCount(Pipe));
// ComplianceTests: 1 = PDF/A, 2 = PDF/UA, 0 = båda; ReportFormat 1 = JSON
Json := Lib.CreateValidationPipelineReport(Pipe, 0, 0, 1);
finally
Lib.ReleaseValidationPipeline(Pipe);
end;
end;
Den strukturerade rapporten märker tillgänglighetsavsnittet PDF/UA-2 och ISO 14289-2 när filen identifierar sig som del 2, och varje PDF/UA-avsnitt bär "fullCertification": false tillsammans med det inbäddade täckningsobjektet. Text-preflightrapporten lägger till en rad som säger att bara implementerade kontroller kördes och att full tillgänglighetscertifiering kräver ytterligare validering och mänsklig granskning. De bredare rapportformaten, regel-ID:na och CI-gating-mönstren beskrivs i guiden för PDF/A- och PDF/UA-preflight
Vad garanterar täckningsrapporten egentligen?
TPDFlib.GetPDFUAReadValidationCoverageJSON garanterar en sak: en exakt lista över vad PDF/UA-2-kontrollen granskade och vad den inte gjorde. För del 2 returnerar den fullCertification låst till false, en checked-array, en unverified-array och traverseringsgränserna. Den garanterar inte att en fil är tillgänglig, och den är designad så att ingen kodväg kan få den att säga annat
var
Coverage: WideString;
begin
Coverage := Lib.GetPDFUAReadValidationCoverageJSON(2);
// Spara den bredvid valideringsresultatet, inte i stället för det
TFile.WriteAllText('report.coverage.json', Coverage, TEncoding.UTF8);
if Pos('"fullCertification":false', Coverage) > 0 then
Writeln('Machine checks only; schedule a human accessibility review');
end;
Den kontrollerade listan täcker identifiering (del, revision, prefix), effektiv PDF-version, titelmetadata, /MarkInfo, DisplayDocTitle, namnrymdsreferenser, rollmap-lösning, dokumentroten, strukturföräldrar, trädcykler samt reglerna för H och Note. Den overifierade listan är lika specifik: innehållstaggning och läsordning, strukturomslutning, typsnitt och Unicode-mappning, anteckningar och formulär, naturligt språk, alternativa beskrivningar, MathML-vokabulären och mänsklig tillgänglighetsgranskning. Flera av dessa går inte ens att avgöra maskinellt. Ingen parser kan säga dig om en alt-text faktiskt beskriver diagrammet, eller om läsordningen ger mening för någon som lyssnar på den
Behandla coverage-JSON:en som en del av resultatet. Arkivera den med varje valideringskörning, och när en revisor frågar vad "godkänt" betydde ett visst datum kan du överlämna exakt omfattning i stället för att rekonstruera den ur minnet och ett versionsnummer
Korskontroll mot veraPDF
PDF/UA-2-kärnan korskontrollerades mot veraPDF 1.30.3:s kommandoradsvalidator med dess ua2-profil, och resultaten stämmer där täckningen överlappar. Ett oberoende genererat giltigt kärnprov klarade båda verktygen; ett prov som deklarerar pdfuaid:rev 2023 och ett prov som använder den onumrerade H-rollen misslyckades i båda verktygen
Ett fjärde prov är det värt att prata om. Det innehöll grafikinnehåll som inte var taggat alls, och veraPDF flaggade det medan PDFlibPas kärnkontroller inte gjorde det, eftersom innehållstaggning ligger utanför aktuell täckning. Det gapet är precis därför content-tagging-and-reading-order står först i unverified-listan. Att köra en andra validator är billig försäkring, och en oenighet mellan två verktyg är ofta det snabbaste sättet att hitta kanten på vad var och en kontrollerar. För författarsidan av samma problem, att bygga träd som klarar från början, se guiden för strukturträd i taggad PDF
FAQ
Certifierar PDFlibPas en fil som PDF/UA-2-kompatibel?
Nej. PDFlibPas kör de implementerade maskinkontrollerna för PDF/UA-2 och returnerar en täckningsrapport med fullCertification alltid false, som listar varje område som fortfarande behöver andra verktyg eller mänsklig granskning
Vilket TargetPart-värde ska jag skicka till CheckFilePDFUACompliance?
Skicka 2 när du vet att filen måste vara PDF/UA-2, så att saknad identifiering rapporteras. Skicka 0 för att autodetektera delen ur XMP pdfuaid:part, och 1 för att tvinga fram PDF/UA-1-reglerna
Vad betyder diagnostik 10059 i en PDF/UA-2-rapport?
Diagnostik 10059 betyder att validatoren inte kunde slutföra: filen kunde inte parsas eller öppnas, en traverseringsgräns överskreds, en cykel hittades, eller ett undantag inträffade. Den räknas alltid som ett fel, aldrig som godkänt
PDF/UA-2-validering, den gemensamma valideringspipelinen och PDF 2.0-författar-API:erna finns i losLab PDF Library for Delphi, tillsammans med PDF/A-preflight och strukturerade valideringsrapporter