Technical Article

Preverjanje PDF/A in PDF/UA v Delphiju s PDFlibPas

PDF/A in PDF/UA odgovarjata na dve vprašanji, ki nista med seboj povezani, in njuno obravnavanje kot enotno potrditveno polje za dostopnost in arhiviranje je razlog, da poškodovane datoteke dosežejo arhiv z oznako o skladnosti. PDF/A sprašuje, ali bo datoteka čez dvajset let še vedno zanesljivo upodobljena. PDF/UA sprašuje, ali jo lahko danes bere podporna tehnologija. Dokument lahko enega prestane z odliko, na drugem pa spodleti, zato edina poštena razsodba izhaja iz izvajanja obeh preverjanj, in to preden se datoteka zapiše, ne pa potem, ko sistem prejema zaupa identifikatorju skladnosti, zapečenemu v metapodatkih. Ta identifikator je le samo-deklaracija. Nič v formatu ne zahteva njegove resničnosti, aplikacija, ki zapiše "PDF/A-1b" v XMP brez preverjanja standarda, pa ustvari datoteko, ki je videti skladna vsakemu porabniku, ki bere le nalepko. Knjižnica losLab PDF Library (PDFlibPas) zapira to vrzel za Delphi in C++Builder z izgradnjo obeh potrjevalcev neposredno v knjižnico, tako da preverjanje poteka znotraj procesa brez potrebe po postavljanju zunanje storitve.

Dva standarda, ki zavračata datoteke iz nasprotnih razlogov

Standard ISO 19005 (PDF/A) je pogodba o reprodukciji. Skladna datoteka se mora čez desetletja upodobiti enako na programski opremi, ki nikoli ni videla sistema, ki jo je ustvaril, zato pravila napadajo zunanje odvisnosti: vsaka pisava mora biti vgrajena, barva usidrana v vgrajenem profilu ICC OutputIntent or expressed in a device-independent space, brez šifriranja v PDF/A-1, brez JavaScripta, metapodatki XMP pa se morajo ujemati s slovarjem informacij o dokumentu. ISO 14289 (PDF/UA) je namesto tega pogodba o semantiki. Podporna tehnologija mora prehoditi dokument in iz njega razbrati pomen, ki živi v povsem drugi plasti: celotno drevo strukture, nadomestno besedilo (alt text) na slikah, naslov dokumenta, nastavljen za prikaz, ravni naslovov, ki ne preskakujejo, ter odnosi glav tabel, ki preživijo, ko stran ni več na zaslonu.

Ker oba standarda nadzorujeta različne plasti, so datoteke, ki povzročajo težave, tiste med njima. Dokument, ki je popoln za arhiv, je lahko nem za bralnik zaslona. Čudovito označen dokument pa se lahko sklicuje na namizno pisavo, ki čez deset let ne bo obstajala. Založništvo v javnem sektorju je običajno mesto, kjer se obe zahtevi pojavita hkrati, cevovod pa ju ne more združiti v en sam prehod. Ugotovitve gredo različnim ljudem. Nevgrajene pisave so napaka v kodi, ki ustvarja PDF, medtem ko manjkajoče nadomestno besedilo pripada lastniku vsebinskih predlog, poročilo, ki meša oboje, pa se preprosto posreduje naprej dvakrat.

Kateri del standarda PDF/A izberete, je enako pomembno kot to, ali ga dosežete. PDF/A-1 je zamrznjen na PDF 1.4 in zavrača prosojnost ter JPEG2000, po katerih sodobni izhodi poročil posegajo brez razmišljanja. PDF/A-2 (ISO 19005-2, zgrajen na ISO 32000-1) sprejema oboje in je razumna privzeta možnost za nov arhiv. PDF/A-3 gre še dlje in dovoljuje vgrajene datoteke katere koli vrste, na kar se opirajo regulirani formati e-računov. Ekipa, ki leta 2026 še vedno standardizira na PDF/A-1b, običajno nosi zahtevo, ki jo je nekdo napisal pred petnajstimi leti, ponovno pogajanje o ciljnem delu pa je pogosto cenejše od odstranjevanja prosojnosti iz vsakega grafikona, ki ga sistem odda.

Strukturirane ugotovitve ob prevzemu

Vstopna točka ravnega API-ja je CheckFileCompliance z izbirnikom testa 1 za PDF/A in 2 za PDF/UA. Vrne ročaj seznama nizov, katerega elementi so posamezne ugotovitve, vsaka v svoji vrstici, kar je natanko oblika, ki jo avtomatiziran prehod želi prehoditi:

function GateArchiveUpload(Pdf: TPDFlib; const FileName: string): Boolean;
var
  ListId, I: Integer;
begin
  ListId := Pdf.CheckFileCompliance(FileName, '', 1, 0);  // 1 = PDF/A
  if ListId = 0 then
  begin
    // 0 means "no findings" OR "file unreadable" -- disambiguate before passing
    Result := Pdf.LastErrorCode = 0;
    Exit;
  end;
  for I := 0 to Pdf.GetStringListCount(ListId) - 1 do
    LogFinding(FileName, Pdf.GetStringListItem(ListId, I));
  Pdf.ReleaseStringList(ListId);
  Result := False;
end;

Dve podrobnosti določata, ali to lahko teče brez nadzora. Prva je povratna vrednost, ki pomeni dve nasprotni stvari. CheckFileCompliance vrne 0, ko je datoteka popolnoma skladna, in tudi takrat, ko datoteke sploh ni bilo mogoče odpreti, saj se interno prazen seznam rezultatov v obeh primerih zruši v 0. Prehod, ki bere 0 kot uspeh, bo poškodovane prenose spustil neposredno v arhiv, zato pred zaupanjem ničli preverite z LastErrorCode, kot to počne zgornji prehod. Druga podrobnost se nanaša na to, kje v življenjskem ciklu se datoteka nahaja. Preverjalnik deluje na pretočnem bralniku knjižnice in ne na celotnem modelu dokumenta, pri čemer datoteko odpre neposredno z deljenjem branja in nikoli ne pokliče LoadFromFile, zato lahko pregleda večgigabajtni vhod brez gradnje objektnega drevesa. To isto pretočno odpiranje spodleti, ko drug proces še vedno drži datoteko za pisanje, prenos v teku pa je natanko takšno stanje. Prehod izvedite po končanem prenosu.

Pretočna oblika se obrestuje tudi pod obremenitvijo. Vsako preverjanje odpre svoj vhod samo za branje in ga deli za branje, zato se revizija korpusa razširi na delovne niti ali procese z eno instanco TPDFlib na delavca in brez sporov med njimi. Vir, ki potrebuje disciplino, je sam ročaj. Vsak nenegativni rezultat iz CheckFileCompliance ostane dodeljen, dokler ne pokličete ReleaseStringList, dolgotrajni prehod, ki jih pozabi sprostiti, pa se ne sesuje, temveč le počasi izgublja pomnilnik, dokler nekdo ne razišče vzroka.

Poročila za ljudi, primerjave za gradbene prehode

Seznam ugotovitev je prava oblika za prehod in napačna za e-pošto ekipi za predloge. CreatePreflightReport predstavi enako analizo kot berljivo besedilo, CreatePreflightReportEx doda izbirnik formata poročila, SavePreflightReport pa ga zapiše na disk, tako da lahko poročilo potuje znotraj dostavljenega paketa dokumentov. Precej arhivskih pogodb zahteva to poročilo kot samostojen izdelek in ne le kot notranji izdelek.

Član te družine, ki si tiho prisluži svoje mesto, je ComparePreflightReports. Skladnost je regresijska površina kot kateri koli drug del vedenja. Sprememba predloge, na novo licencirana pisava ali nadgradnja knjižnice lahko vnesejo ugotovitev, ki je v prejšnji izdaji ni bilo, nobena od njih pa se ne napove sama. Hranite zlata poročila (golden reports) za nabor reprezentativnih dokumentov pod nadzorom različic, jih poustvarite po vsaki spremembi in zaženite ComparePreflightReports za izračun delte. Prazen diff je izdajni izdelek, ki ga je vredno obdržati. Presenetljiva ugotovitev pa pomeni neuspeh gradnje, kar je veliko cenejše mesto za odkritje kot revizija.

Ustvarjanje izhoda, ki uspe v prvem poskusu

Preverjanje opravi svoje delo na datotekah, ki prispejo od drugod. Za dokumente, ki jih ustvari vaša lastna koda, je iskanje kršitev po ustvarjanju in njihovo naknadno popravljanje zamudna pot. PDFlibPas prinaša način generiranja za vsak standard, oba pa lahko vklopite za isti dokument:

var
  Pdf: TPDFlib;
  Diag: WideString;
begin
  Pdf := TPDFlib.Create;
  try
    Pdf.NewDocument;
    Pdf.SetPDFAMode(1);
    Pdf.LoadOutputIntentProfile('sRGB-IEC61966-2.1.icc', 'RGB');
    Pdf.SetPDFUAMode('en-US');
    Pdf.SetInformation(1, 'Quarterly Statement');  // /Title: required for PDF/UA
    // ... draw tagged content here ...
    Diag := Pdf.GetPDFUADiagnostics;
    if Diag <> '' then
      Writeln('fix before shipping: ', Diag);
    Pdf.SaveToFile('statement.pdf');
    // the preflight that counts runs on the saved file:
    Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
  finally
    Pdf.Free;
  end;
end;

Past se skriva ob shranjevanju. Več popravkov skladnosti se izvede med serijsko pripravo dokumenta in ne ob vklopu načina: prisilna nastavitev tiskalne zastavice na komentarjih, zapisovanje privzete AFRelationship za vgrajene datoteke PDF/A-3, normalizacija tabulatorskega vrstnega reda in opisov polj obrazcev za PDF/UA. Dokument v pomnilniku ni bajtno enak tistemu na disku, zato je edina razsodba preverjanja tista, izračunana iz shranjene datoteke. Preverite sam statement.pdf. Ne sklepajte o skladnosti na podlagi objekta v pomnilniku, saj bajti, ki bi jih ocenjevali, niso tisti, ki ste jih poslali.

Scenariji računov, ki prenašajo strojno berljiv XML poleg vizualnega dokumenta, sledijo vzorcu ZUGFeRD in Factur-X, ki temelji na PDF/A-3. Ti bi morali eksplicitno nastaviti odnos priloge s SetPDFA3DefaultAFRelationship, saj ISO 19005-3 zahteva, da vsaka vgrajena datoteka izrazi svojo vlogo glede na dokument. Če jo pustite nenastavljeno, je vgrajeni XML le vsebina brez navedenega namena, kar preverjalnik opazi.

Neodvisni razsodniki: veraPDF in Acrobat

Proizvajalec ne bi smel biti edini sodnik svojega izhoda. Preverjalniki PDFlibPas vam ponujajo hitre in strukturirane razsodbe znotraj procesa, kar je tisto, kar želite na vroči poti, vendar bi moral končni prehod za arhivski paket kljub temu poslati izhod skozi potrjevalnik, ki ga ni napisal nihče iz vaše ekipe. veraPDF je referenčna implementacija za PDF/A, ki jo vzdržuje skupnost, in orodje, ki ga večina arhivov navaja v svojih sprejemnih merilih, zato je to tisto, ki ga morate uskladiti. Acrobatovi profili preverjanja so uporaben razsodnik, ko se veraPDF in preverjanje v procesu ne strinjata. Zabeležite ime potrjevalca in njegovo različico poleg vsakega shranjenega poročila. Trditev, da je datoteka prestala veraPDF, pove zelo malo brez številke gradnje, saj orodje med izdajami zaostruje svoja pravila.

Potrjevalci se ne strinjajo na robovih standardov, in ko pride do tega, rešitev ni izbira orodja, ki vam je všeč. Skrčite datoteko na minimalen vzorec, ki še vedno sproži nesoglasje, in jo preberite ob besedilu standarda. Ura takšnega dela običajno razkrije eno od dveh stvari: resnično napako orodja, ki jo je vredno prijaviti avtorjem, ali pa člen, ki ga je vaša ekipa napačno razumela in bi ga morala zapisati v opombe o skladnosti, da naslednji osebi ne bo treba ponovno razpravljati o njem.

Šifrirani vhod dobi bližnjico. Oba preverjalnika sprejmeta geslo, vendar je datoteka PDF/A-1 s šifrirnim slovarjem že neskladna, saj ISO 19005-1 šifriranje popolnoma prepoveduje, zato lahko šifrirano oddajo zavrnete, še preden se zažene globlja analiza. Ugotavljanje, kaj šifrirni slovar dejansko omogoča, je lastno opravilo, ki ga pokriva članek Revizija šifriranja in dovoljenj PDF. Ugotovitve PDF/UA se skoraj vedno vrnejo k temu, kako je bilo drevo strukture sploh ustvarjeno, tehnike označevanja za to pa živijo v članku Gradnja dreves strukture označenih PDF v Delphiju. Arhivi, ki zahtevajo tudi digitalne podpise, bi morali ta prehod povezati z delovnim tokom v priročniku Podpisovanje in potrjevanje PAdES. Celotna referenca API za preverjanje se nahaja na produktni strani losLab PDF Library for Delphi.