PDF/A i PDF/UA daju odgovore na dva pitanja koja nemaju nikakve veze jedno sa drugim, a njihovo tretiranje kao jedinstvenog polja za potvrdu pristupačnosti i arhiviranja je način na koji oštećene datoteke stižu u arhivu sa oznakom usaglašenosti. PDF/A se pita da li će se datoteka i dalje verno renderovati za dvadeset godina. PDF/UA se pita da li tehnologija asistencije (assistive technology) može da je pročita danas. Dokument može u potpunosti proći jedan test, a pasti na drugom, tako da jedina iskrena presuda dolazi od pokretanja oba, i to pre nego što se datoteka upiše na disk, a ne nakon što nizvodni sistem ukaže poverenje identifikatoru usaglašenosti ugrađenom u njegove metapodatke. Taj identifikator je samoizjava. Ništa u formatu ne zahteva da on bude tačan, a aplikacija koja upisuje „PDF/A-1b” u XMP bez validacije u odnosu na standard proizvodi datoteku koja izgleda usaglašeno svakom potrošaču koji čita samo oznaku. losLab PDF biblioteka (PDFlibPas) zatvara taj jaz za Delphi i C++Builder ugrađivanjem oba validatora u samu biblioteku, tako da se provera izvršava unutar samog procesa bez potrebe za podizanjem eksternog servisa.
Dva standarda koja odbijaju datoteke iz suprotnih razloga
ISO 19005 (PDF/A) je ugovor o reprodukciji. Usaglašena datoteka mora da se renderuje identično decenijama od danas na softveru koji nikada nije video sistem koji ju je proizveo, pa pravila napadaju spoljne zavisnosti: svaki font mora biti ugrađen, boja mora biti vezana za ugrađeni ICC OutputIntent ili izražena u prostoru nezavisnom od uređaja, bez šifrovanja u PDF/A-1, bez JavaScript-a, a XMP metapodaci moraju biti usklađeni sa rečnikom informacija o dokumentu. Nasuprot tome, ISO 14289 (PDF/UA) je ugovor o semantici. Tehnologija asistencije mora da prođe kroz dokument i izvuče značenje, koje živi u potpuno drugom sloju: kompletno stablo strukture, alternativni tekst na slikama (alternate text), naslov dokumenta podešen za prikaz, nivoi naslova koji ne preskaču korake, i odnosi zaglavlja tabela koji opstaju i kada se stranica skloni sa ekrana.
Pošto ova dva standarda kontrolišu različite slojeve, problemi nastaju upravo sa datotekama koje se nalaze između njih. Savršeno arhiviran dokument može biti potpuno nem za čitač ekrana. Prelepo tagovan dokument može referencirati sistemski font sa računara koji neće postojati za deset godina. Izdavaštvo u javnom sektoru je uobičajeno mesto gde oba zahteva stižu istovremeno, a proces obrade ih ne može stopiti u jednu kapiju. Nalazi se šalju različitim ljudima. Neugrađeni fontovi su propust u kodu koji generiše PDF, dok nedostajući alternativni tekst pripada onome ko poseduje šablone sadržaja, a izveštaj koji meša ove dve stvari se samo prosleđuje na dve različite adrese.
Koji deo PDF/A standarda ciljate podjednako je važno kao i to da li ga ispunjavate. PDF/A-1 je fiksiran na PDF 1.4 i odbacuje providnost (transparency) i JPEG2000, za kojima savremeni izveštaji posežu bez razmišljanja. PDF/A-2 (ISO 19005-2, izgrađen na ISO 32000-1) prihvata oba i predstavlja razumljiv podrazumevani izbor za novu arhivu. PDF/A-3 ide korak dalje i dozvoljava ugrađene datoteke bilo kog tipa, na šta se oslanjaju regulisani formati elektronskih faktura. Tim koji i u 2026. godini vrši standardizaciju na PDF/A-1b obično prenosi zahtev koji je neko napisao pre petnaest godina, a ponovno pregovaranje o ciljnom standardu je često jeftinije od uklanjanja providnosti iz svakog grafikona koji sistem generiše.
Strukturisani nalazi u vreme prihvatanja
Ulazna tačka za ravan API je CheckFileCompliance, sa selektorom testa 1 za PDF/A i 2 za PDF/UA. Ona vraća opisnik liste stringova čije stavke predstavljaju pojedinačne nalaze, po jedan u svakom redu, što je upravo oblik kroz koji automatizovana kapija želi da prođe:
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;
Dva detalja odlučuju o tome da li ovaj proces može da se izvršava bez nadzora. Prvi je povratna vrednost koja označava dve suprotne stvari. Funkcija CheckFileCompliance vraća 0 kada je datoteka potpuno usaglašena, ali i kada se datoteka uopšte ne može otvoriti, jer se interno prazna lista rezultata u oba slučaja svodi na 0. Kapija koja čita 0 kao prolaz propustiće neispravne otpremljene datoteke direktno u arhivu, pa razrešite ovu dvosmislenost pomoću LastErrorCode pre nego što poverujete nuli, kao što to radi gorenavedeni primer. Drugi detalj se odnosi na to gde se datoteka nalazi u svom životnom ciklusu. Validator se pokreće na strimujućem čitaču biblioteke umesto na celom modelu dokumenta, otvarajući datoteku direktno sa deljenjem za čitanje (read sharing) i nikada ne pozivajući LoadFromFile, zbog čega može da obradi ulaze od više gigabajta bez izgradnje stabla objekata. To isto strimujuće otvaranje otkazuje dok drugi proces još uvek drži datoteku radi upisa, a otpremanje u toku je upravo takvo stanje. Postavite kapiju tek nakon što se prenos završi.
Strimujući dizajn se ponovo isplaćuje pod opterećenjem. Svaka provera otvara svoj ulaz samo za čitanje i deli ga za čitanje, tako da se revizija skupa dokumenata (corpus) skalira kroz radne niti (worker threads) ili procese sa jednom instancom TPDFlib po radniku i bez ikakvih konflikata među njima. Resurs koji zahteva disciplinu je sam opisnik. Svaki ne-nulti rezultat iz CheckFileCompliance ostaje alociran sve dok ne pozovete ReleaseStringList, a dugotrajni proces koji zaboravi da ih oslobodi neće se srušiti, već će polako gubiti memoriju dok neko ne krene da istražuje uzrok.
Izveštaji za ljude, razlike za kapije builds procesa
Lista nalaza je ispravan oblik za kapiju, a pogrešan za slanje e-pošte timu za šablone. CreatePreflightReport prevodi istu analizu u čitljiv tekst, CreatePreflightReportEx dodaje selektor formata izveštaja, dok SavePreflightReport upisuje izveštaj na disk kako bi mogao da putuje unutar isporučenog paketa dokumenata. Mnogi ugovori o arhiviranju čine ovaj izveštaj obaveznim delom isporuke samim po sebi, a ne samo internim dokumentom.
Član ove porodice koji tiho zarađuje svoje mesto je ComparePreflightReports. Usaglašenost je podložna regresiji kao i bilo koji drugi deo ponašanja sistema. Izmena šablona, novo licencirani korporativni font ili nadogradnja biblioteke, sve to može uneti nalaz koji nije postojao u prošlom izdanju, a nijedan od njih se ne najavljuje sam. Čuvajte referentne („zlatne”) izveštaje za skup reprezentativnih dokumenata pod kontrolom verzija, generišite ih ponovo nakon svake izmene i pokrenite ComparePreflightReports da biste izračunali razliku. Prazan diff je izlazni artefakt vredan čuvanja. Neočekivani nalaz obara build proces, što je znatno jeftinije mesto za njegovo otkrivanje nego što je to revizija.
Generisanje izlaza koji prolazi pri prvom pokušaju
Preflight dokazuje svoju vrednost na datotekama koje stižu sa drugih mesta. Za dokumente koje proizvodi vaš sopstveni kod, pronalaženje prekršaja nakon generisanja i njihovo naknadno ispravljanje je sporiji zaobilazni put. PDFlibPas nosi režim rada na strani generisanja za svaki standard, i možete uključiti oba 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;
Zamka se krije u trenutku čuvanja. Nekoliko popravki usaglašnosti dešava se tokom serijalizacije dokumenta, a ne kada omogućite režim: nametanje flega za štampanje na napomenama, upisivanje podrazumevanog AFRelationship-a za PDF/A-3 ugrađene datoteke, normalizacija redosleda tabulatora i opisa polja obrazaca za PDF/UA. Dokument koji se nalazi u memoriji nije bajt-identičan onom koji završava na disku, tako da je jedina merodavna presuda preflight provere ona koja je izračunata nad sačuvanom datotekom. Validaciju izvršite nad samom datotekom statement.pdf. Nemojte pretpostavljati usaglašenost na osnovu objekta koji je još uvek u memoriji, jer bajtovi koje biste procenjivali nisu oni koje ste isporučili.
Scenariji fakturisanja koji nose mašinski čitljiv XML uz vizuelni dokument prate ZUGFeRD i Factur-X šablon, koji je izgrađen na PDF/A-3 standardu. Ti procesi bi trebalo eksplicitno da postave odnos priloga pomoću SetPDFA3DefaultAFRelationship, pošto ISO 19005-3 zahteva da svaka ugrađena datoteka deklarise svoju ulogu u odnosu na dokument. Ako je ostavite nepostavljenu, ugrađeni XML je samo binarni podatak bez navedene svrhe, što validator primećuje.
Nezavisni arbitri: veraPDF i Acrobat
Proizvođač ne bi trebalo da bude jedini sudija sopstvenog izlaza. PDFlibPas validator vam daje brze, strukturisane presude unutar samog procesa, što je ono što želite na glavnom putu obrade, ali kapija za izdavanje arhivske grupe dokumenata bi ipak trebalo da propusti izlaz kroz validator koji niko iz vašeg tima nije napisao. veraPDF je referentna implementacija za PDF/A koju održava zajednica i alat koji većina arhiva navodi u svojim kriterijumima prihvatanja, pa je to standard koji treba zadovoljiti. Acrobat preflight profili služe kao korisno rešenje za prelamanje kada se veraPDF i interna provera ne slažu. Zabeležite ime validatora i njegovu verziju pored svakog sačuvanog izveštaja. Tvrdnja da je datoteka prošla veraPDF test ne znači mnogo bez broja verzije (build number) koji ju je odobrio, s obzirom na to da ovaj alat pooštrava svoja pravila između izdanja.
Validatori se zaista ne slažu na granicama standarda, a kada se to dogodi, rešenje nije da izaberete alat koji vam se više dopada. Smanjite datoteku na minimalni primer koji i dalje izaziva neslaganje i pročitajte ga u odnosu na tekst standarda. Sat vremena takvog rada obično otkriva jednu od dve stvari: stvarni bag u alatu koji vredi prijaviti programerima, ili klauzulu koju je vaš tim pogrešno tumačio i koju bi trebalo zapisati u beleške o usaglašenosti kako sledeća osoba ne bi ponovo raspravljala o tome.
Šifrovani ulaz dobija prečicu. Oba validatora primaju lozinku kao argument, ali PDF/A-1 datoteka sa rečnikom šifrovanja je već neusaglašena jer ISO 19005-1 u potpunosti zabranjuje šifrovanje, pa se šifrovani dokument može odbiti pre nego što se pokrene bilo kakva dublja analiza. Utvrđivanje šta tačno rečnik šifrovanja dozvoljava je zaseban zadatak, pokriven u reviziji šifrovanja i dozvola PDF-a.
PDF/UA nalazi skoro uvek vode poreklo od načina na koji je stablo strukture prvobitno kreirano, a tehnike tagovanja koje stoje iza toga opisane su u članku o izgradnji tagovanih stabala PDF strukture u Delphi-ju. Arhive koje takođe zahtevaju digitalne potpise trebalo bi da upare ovu kapiju sa radnim tokom u PAdES potpisivanju i validaciji. Kompletna referenca za preflight API nalazi se na stranici proizvoda losLab PDF Library for Delphi.