PDF/A ir PDF/UA atsako į du visiškai skirtingus klausimus, todėl elgesys su jais kaip su vienu bendru prieinamumo ir archyvavimo varnelės langeliu yra priežastis, kodėl sugadinti failai patenka į archyvą su klaidinga atitikties etikete. PDF/A tikrina, ar failas po dvidešimties metų vis dar bus atvaizduojamas tiksliai taip pat. PDF/UA tikrina, ar pagalbinės technologijos gali jį perskaityti šiandien. Dokumentas gali visiškai sėkmingai praeiti vieną patikrą ir visiškai suklupti kitoje, todėl vienintelis sąžiningas verdiktas gaunamas vykdant abi patikras ir atliekant jas prieš įrašant failą, o ne po to, kai tolesnė sistema jau pasitiki jo metaduomenyse įrašytu atitikties identifikatoriumi. Šis identifikatorius yra tik paties failo deklaracija. Formate nėra nieko, kas reikalautų, kad jis būtų teisingas, o programa, kuri į XMP įrašo „PDF/A-1b“ neatlikusi patikros pagal standartą, sugeneruoja failą, kuris atrodo atitinkantis reikalavimus tik tiems vartotojams, kurie perskaito tik etiketę. „losLab PDF Library“ („PDFlibPas“) pašalina šią spragą „Delphi“ ir „C++Builder“ kūrėjams, integruodama abu validatorius tiesiai į biblioteką, todėl patikra vykdoma pačiame procese, nenaudojant jokių išorinių paslaugų
Du standartai, atmetantys failus dėl visiškai skirtingų priežasčių
ISO 19005 (PDF/A) yra atkūrimo sutartis. Reikalavimus atitinkantis failas po kelių dešimtmečių turi būti atvaizduojamas identiškai programinėje įrangoje, kuri niekada nematė jį sukūrusios sistemos, todėl taisyklės griežtai riboja išorines priklausomybes: kiekvienas šriftas turi būti įterptas, spalvos turi būti susietos su įterptu ICC OutputIntent arba išreikštos nuo įrenginio nepriklausomoje erdvėje, PDF/A-1 standarte draudžiamas šifravimas, nenaudojamas JavaScript, o XMP metaduomenys turi sutapti su dokumento informacijos žodynu. Tuo tarpu ISO 14289 (PDF/UA) yra semantikos sutartis. Pagalbinės technologijos turi gebėti judėti po dokumentą ir suprasti jo prasmę, kuri gyvena visiškai kitame sluoksnyje: pilnas struktūros medis, alternatyvusis tekstas ant paveikslėlių, dokumento pavadinimas, nustatytas rodymui, antraščių lygiai be praleidimų ir lentelių antraščių ryšiai, išliekantys net ir tada, kai puslapis nebėra ekrane
Kadangi abu standartai kontroliuoja skirtingus sluoksnius, problemų dažniausiai sukelia failai, esantys tarp jų. Puikiai suarchyvuotas dokumentas gali būti visiškai nebylus ekrano skaitytuvui. O gražiai sužymėtas dokumentas gali naudoti kompiuterio šriftą, kurio po dešimties metų nebeliks. Viešojo sektoriaus leidyba yra ta vieta, kur abu reikalavimai dažniausiai atsiranda vienu metu, ir ten esantis apdorojimo srautas negali jų sujungti į vieną patikros etapą. Rezultatai keliauja skirtingiems žmonėms: neįterpti šriftai yra PDF generuojančio kodo defektas, o trūkstamas alternatyvusis tekstas yra turinio šablonų autoriaus atsakomybė, todėl šias dvi problemas sumaišiusi ataskaita tiesiog bus persiųsta du kartus
Kurią PDF/A dalį pasirinksite kaip tikslą, yra taip pat svarbu, kaip ir tai, ar ją pasieksite. PDF/A-1 standartas yra apribotas ties PDF 1.4 versija ir atmeta skaidrumą bei JPEG2000, kuriuos šiuolaikinės ataskaitų generavimo sistemos naudoja negalvodamos. PDF/A-2 (ISO 19005-2, pagrįstas ISO 32000-1) priima abu šiuos elementus ir yra protingas numatytasis pasirinkimas naujam archyvui. PDF/A-3 žengia dar toliau ir leidžia įterpti bet kokio tipo failus, kuo remiasi reglamentuojami el. sąskaitų faktūrų formatai. Komanda, kuri 2026 metais vis dar naudoja PDF/A-1b kaip standartą, dažniausiai tiesiog vykdo reikalavimą, kurį kažkas parašė prieš penkiolika metų, o susitarimas dėl naujesnės standarto dalies taikymo dažnai yra pigesnis nei skaidrumo šalinimas iš kiekvienos sistemos generuojamos diagramos
Struktūrizuoti rezultatai gavimo metu
Pagrindinis plokščiojo API (flat-API) įėjimo taškas yra CheckFileCompliance su testo selektoriumi: 1 (PDF/A) ir 2 (PDF/UA). Jis grąžina eilučių sąrašo identifikatorių (handle), kurio elementai yra atskiri radiniai (po vieną eilutėje), o tai yra būtent tokia struktūra, kuria lengvai gali judėti automatiniai patikros vartai:
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;
Dvi detalės lemia, ar šis kodas gali veikti be priežiūros. Pirmoji, tai grąžinama reikšmė, kuri gali reikšti du priešingus dalykus. CheckFileCompliance grąžina 0, kai failas visiškai atitinka reikalavimus, taip pat kai failo apskritai nepavyko atidaryti, nes viduje tuščias rezultatų sąrašas abiem atvejais sutraukiamas iki 0. Vartai, kurie 0 skaito kaip sėkmingą patikrą, praleis sugadintus failus tiesiai į archyvą, todėl prieš pasitikėdami nuliu išsklaidykite abejones naudodami LastErrorCode, kaip tai daroma aukščiau pateiktame kode. Antroji detalė susijusi su tuo, kurioje gyvavimo ciklo vietoje yra failas. Tikrintuvas veikia naudodamas bibliotekos srautinį skaitytuvą, o ne pilną dokumento modelį: jis atidaro failą tiesiogiai su bendro skaitymo prieiga ir niekada neiškviečia LoadFromFile, todėl gali apdoroti kelių gigabaitų įvestį nesukurdamas objektų medžio. Tačiau toks srautinis atidarymas nepavyks, jei kitas procesas vis dar laiko failą atidarytą rašymui, o vykstantis įkėlimas yra būtent tokia būsena. Vykdykite patikrą tik pasibaigus failo perdavimui
Srautinis dizainas atsiperka esant didelėms apkrovoms. Kiekviena patikra atidaro savo įvestį tik skaitymui ir dalijasi ja su kitais skaitymo procesais, todėl dokumentų rinkinio auditas lengvai plečiamas per darbininkų gijas (worker threads) arba procesus su viena TPDFlib instancija kiekvienam darbininkui, išvengiant konfliktų tarp jų. Išteklius, reikalaujantis drausmės, yra pats identifikatorius (handle). Kiekvienas ne nulinis CheckFileCompliance rezultatas išlieka išskirtas atmintyje, kol neiškviečiate ReleaseStringList, o ilgai veikiantys vartai, pamiršę juos atlaisvinti, neužlūš, bet lėtai nuotėkio būdu praras atmintį, kol kas nors pradės ieškoti to priežasties
Ataskaitos žmonėms, skirtumai (diff) kūrimo vartams
Rezultatų sąrašas yra tinkama forma automatiniams vartams, bet visiškai netinkama laiškui šablonų komandai. Funkcija CreatePreflightReport pateikia tą pačią analizę kaip lengvai skaitomą tekstą, CreatePreflightReportEx prideda ataskaitos formato selektorių, o SavePreflightReport įrašo ją į diską, kad ataskaita galėtų keliauti kartu su pateiktu dokumentų paketu. Daugelyje archyvavimo sutarčių reikalaujama pateikti šią ataskaitą kaip atskirą rezultatą, o ne tik kaip vidinį sistemos elementą
Šios šeimos narys, kuris tyliai užsitarnauja savo vietą, yra ComparePreflightReports. Atitiktis yra regresijos sritis, kaip ir bet kuri kita elgsena. Šablono patobulinimas, naujai licencijuotas įmonės šriftas arba bibliotekos atnaujinimas gali sukelti naują radinį, kurio nebuvo ankstesnėje versijoje, ir nei vienas iš jų apie save nepraneša. Laikykite pavyzdines (golden) ataskaitas reprezentatyviems dokumentams versijų kontrolės sistemoje, sugeneruokite jas iš naujo po kiekvieno pakeitimo ir paleiskite ComparePreflightReports skirtumui apskaičiuoti. Tuščias skirtumas (diff) yra vertingas išleidimo rezultatas. Netikėtas radinys sustabdo projekto kūrimą (build), o tai yra daug pigesnė vieta jį atrasti nei audito metu
Išvesties generavimas, praeinantis patikrą iš pirmo karto
Išankstinė patikra (preflight) labiausiai atsiperka tikrinant failus, gautus iš kitų šaltinių. Dokumentams, kuriuos sukuria jūsų pačių kodas, pažeidimų paieška po sugeneravimo ir jų taisymas atgaline data yra lėtas kelias. „PDFlibPas“ palaiko kiekvieno standarto generavimo režimą, ir abu režimus galite įjungti tam pačiam dokumentui:
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;
Spąstai slepiasi įrašymo metu. Keletas atitikties pataisymų įvyksta dokumento serializavimo metu, o ne tada, kai įjungiate režimą: privalomas anotacijų spausdinimo vėliavėlės nustatymas, numatytojo AFRelationship įrašymas PDF/A-3 įterptiems failams, tabuliavimo tvarkos ir formos laukų aprašymų normalizavimas PDF/UA standartui. Atmintyje esantis dokumentas nėra baitiškai identiškas tam, kuris įrašomas į diską, todėl vienintelis prasmingas išankstinio patikrinimo verdiktas yra tas, kuris apskaičiuojamas pagal išsaugotą failą. Patikrinkite patį statement.pdf failą. Nedarykite prielaidos apie atitiktį pagal atmintyje esantį objektą, nes baitai, kuriuos vertintumėte, nėra tie baitai, kuriuos išsiuntėte
Sąskaitų-faktūrų scenarijai, kai kartu su vaizdiniu dokumentu pateikiamas mašininio skaitymo XML failas, atitinka ZUGFeRD ir Factur-X modelį, kuris yra pagrįstas PDF/A-3 standartu. Juose reikėtų aiškiai nustatyti prisegtuko ryšį naudojant SetPDFA3DefaultAFRelationship, kadangi ISO 19005-3 reikalauja, kad kiekvienas įterptas failas deklaruotų savo vaidmenį dokumento atžvilgiu. Jei paliksite jį nenustatytą, įterptas XML bus tik duomenų blokas be nurodytos paskirties, ką validatorius iškart pastebės
Nepriklausomi teisėjai: veraPDF ir Acrobat
Gamintojas neturėtų būti vienintelis savo produkcijos vertintojas. „PDFlibPas“ tikrintuvai pateikia greitus, struktūrizuotus rezultatus pačiame procese, o tai yra būtent tai, ko norite kritiniame vykdymo kelyje, tačiau archyvavimo partijos išleidimo vartai vis tiek turėtų patikrinti išvestį per validatorių, kurio niekas iš jūsų komandos neparašė. „veraPDF“ yra bendruomenės palaikoma PDF/A pavyzdinė realizacija ir įrankis, kurį dauguma archyvų nurodo savo priėmimo kriterijuose, todėl reikia orientuotis į jį. „Acrobat“ preflight profiliai yra naudingas teisėjas, kai „veraPDF“ ir vidinis patikrinimas nesutampa. Įrašykite validatoriaus pavadinimą ir jo versiją šalia kiekvienos išsaugotos ataskaitos. Teiginys, kad failas praėjo „veraPDF“ patikrą, sako labai mažai, jei nenurodytas kūrimo (build) numeris, su kuriuo patikra buvo atlikta, nes įrankis sugriežtina savo taisykles tarp skirtingų versijų išleidimų
Validatoriai nesutaria dėl standartų ribinių atvejų, ir kai taip nutinka, sprendimas nėra tiesiog pasirinkti patinkantį įrankį. Sumažinkite failą iki minimalaus pavyzdžio, kuris vis dar sukelia nesutarimą, ir palyginkite jį su standartiniu tekstu. Valanda tokio darbo paprastai atskleidžia vieną iš dviejų dalykų: tikrą įrankio klaidą, apie kurią verta pranešti kūrėjams, arba sąlygą, kurią jūsų komanda skaitė neteisingai ir turėtų užfiksuoti atitikties pastabose, kad kitam žmogui nereikėtų to ginčyti iš naujo
Šifruotai įvesčiai taikomas trumpesnis kelias. Abu tikrintuvai priima slaptažodžio argumentą, tačiau PDF/A-1 failas su šifravimo žodynu jau savaime neatitinka reikalavimų, nes ISO 19005-1 visiškai draudžia šifravimą, todėl šifruotas dokumentas gali būti atmestas dar prieš pradedant any gilesnę analizę. Išsiaiškinti, ką iš tikrųjų suteikia šifravimo žodynas, yra atskira užduotis, aprašyta straipsnyje PDF šifravimas ir teisių auditas
PDF/UA radiniai beveik visada yra susiję su tuo, kaip pirmiausia buvo sukurtas struktūros medis, o tam naudojami žymėjimo metodai yra aprašyti straipsnyje sužymėtų PDF struktūros medžių kūrimas „Delphi“ aplinkoje. Archyvai, kurie taip pat reikalauja skaitmeninių parašų, turėtų sujungti šiuos patikros vartus su darbo eiga, aprašyta straipsnyje PAdES pasirašymas ir patvirtinimas. Pilną preflight API nuorodą galima rasti „losLab PDF Library for Delphi“ produkto puslapyje