Műszaki cikk

PDF/A és PDF/UA preflight Delphi-ben PDF Library for Delphi segítségével

A PDF/A és a PDF/UA két olyan kérdésre felel, amelyeknek semmi közük egymáshoz, és abból, hogy egyetlen „akadálymentesség és archiválás” jelölőnégyzetként kezelik őket, az lesz, hogy hibás fájlok jutnak be az archívumba megfelelőségi címkével a hátukon. A PDF/A azt kérdezi, hogy húsz év múlva is hűen fog-e megjelenni a fájl. A PDF/UA azt kérdezi, hogy a segítő technológia el tudja-e olvasni ma. Egy dokumentum simán átmehet az egyiken, és megbukhat a másikon, így becsületes ítéletet csak mindkettő lefuttatása ad – méghozzá a fájl kiírása előtt, nem pedig azután, hogy valamelyik alsóbb rendszer már megbízott a metaadatba sütött megfelelőségi azonosítóban. Ez az azonosító önbevallás. A formátumban semmi nem követeli meg, hogy igaz legyen, és az az alkalmazás, amely validálás nélkül írja be a „PDF/A-1b” szöveget az XMP-be, olyan fájlt állít elő, amely minden csak címkét olvasó fogadó rendszer szemében megfelelőnek látszik. A losLab PDF Library (PDF Library for Delphi) ezt a rést zárja be Delphi és C++Builder alatt: mindkét validátort beépíti a könyvtárba, így az ellenőrzés folyamaton belül fut, külön szolgáltatás felállítása nélkül

Két szabvány, amely ellentétes okokból buktatja meg a fájlokat

Az ISO 19005 (PDF/A) reprodukciós szerződés. A megfelelő fájlnak évtizedek múlva is azonosan kell megjelennie olyan szoftveren, amely soha nem látta az előállító rendszert, ezért a szabályok a külső függőségekre támadnak: minden betűkészlet beágyazva, a szín beágyazott ICC OutputIntent horgonyához kötve vagy eszközfüggetlen térben kifejezve, semmi titkosítás a PDF/A-1 esetében, semmi JavaScript, és olyan XMP metaadat, amely egyezik a dokumentuminformációs szótárral. Az ISO 14289 (PDF/UA) ezzel szemben szemantikai szerződés. A segítő technológiának be kell járnia a dokumentumot, és jelentéssel kell kijönnie belőle, ez pedig egy teljesen más rétegben lakik: teljes struktúrafa, alternatív szöveg az ábrákon, megjelenítésre beállított dokumentumcím, szintet nem ugró címsorok, és olyan táblázatfejléc-kapcsolatok, amelyek akkor is megmaradnak, amikor az oldal már lekerült a képernyőről

Mivel a két szabvány más-más réteget felügyel, azok a fájlok harapnak, amelyek a kettő közé esnek. Egy archiválási szempontból tökéletes dokumentum néma lehet a képernyőolvasónak. Egy gyönyörűen címkézett dokumentum hivatkozhat olyan asztali betűkészletre, amely tíz év múlva nem fog létezni. A közszféra kiadványai a szokásos hely, ahol mindkét követelmény egyszerre landol, és egy ottani feldolgozósor nem vonhatja össze őket egyetlen kapuvá. Az észrevételek más-más emberekhez tartoznak. A be nem ágyazott betűkészlet a PDF-et előállító kódban lévő hiba, a hiányzó alternatív szöveg viszont azé, aki a tartalomsablonokat birtokolja, és a kettőt keverő jelentést egyszerűen kétszer továbbítják

Legalább annyira számít, hogy a PDF/A melyik részét célozza meg, mint az, hogy eltalálja-e. A PDF/A-1 a PDF 1.4 szintjén befagyott, és elutasítja az átlátszóságot és a JPEG2000-et, holott a mai riportkimenet gondolkodás nélkül nyúl mindkettőhöz. A PDF/A-2 (ISO 19005-2, az ISO 32000-1 alapján) mindkettőt elfogadja, és új archívumhoz ez a józan alapértelmezés. A PDF/A-3 még tovább megy, és tetszőleges típusú beágyazott fájlt enged, erre épülnek a szabályozott elektronikus számlázási formátumok. Az a csapat, amely 2026-ban még mindig a PDF/A-1b szabványra áll rá, rendszerint egy tizenöt éve leírt követelményt cipel magával, és a célzott rész újratárgyalása gyakran olcsóbb, mint kiirtani az átlátszóságot a rendszer által kibocsátott összes diagramból

PDF Library for Delphi diagram: a PDF/A reprodukciós szerződés szemben a PDF/UA szemantikai szerződéssel, plusz megfelel-elbukik mátrix azokról a dokumentumokról, amelyek az egyiknek megfelelnek, a másikon elbuknak
A PDF/A a hűséges megjelenítést biztosítja évtizedekre előre, a PDF/UA a kisegítő olvasást ma, és egyik ítélet sem vonja maga után a másikat

Strukturált észrevételek a beérkezés pillanatában

A lapos API belépési pontja a CheckFileCompliance, ahol a tesztválasztó 1 a PDF/A és 2 a PDF/UA esetén. Egy string-lista leírót ad vissza, amelynek elemei soronként egy-egy észrevételt tartalmaznak, és pontosan ez az az alak, amelyet egy automatizált kapu végig akar járni:

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
    // a 0 jelentése "nincs észrevétel" VAGY "olvashatatlan fájl" -- tisztázd, mielőtt átengeded
    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;

Két részlet dönti el, hogy ez felügyelet nélkül is elfut-e. Az első egy visszatérési érték, amely két ellentétes dolgot jelent. A CheckFileCompliance nullát ad vissza akkor, amikor a fájl teljesen megfelelő, és akkor is, amikor a fájlt egyáltalán nem lehetett megnyitni, mert belül az üres eredménylista mindkét esetben nullára esik össze. Az a kapu, amely a nullát átmenőnek olvassa, sérült feltöltéseket integet be egyenesen az archívumba, ezért a nulla megbízása előtt tisztázza a helyzetet a LastErrorCode értékével, ahogy a fenti kapu teszi. A második részlet arról szól, hol tart a fájl az életciklusában. Az ellenőrző a teljes dokumentummodell helyett a könyvtár streamelő olvasóján fut, közvetlenül, olvasási megosztással nyitja meg a fájlt, és soha nem hívja meg a LoadFromFile metódust – ezért képes több gigabájtos bemenetet átrágni objektumfa felépítése nélkül. Ugyanez a streamelő megnyitás viszont elbukik, amíg egy másik folyamat írásra tartja a fájlt, és a folyamatban lévő feltöltés pontosan ez az állapot. A kapu az átvitel befejezése után jöjjön

A streamelő felépítés terhelés alatt még egyszer megtérül. Minden ellenőrzés csak olvasásra nyitja meg a bemenetét, és olvasásra osztja meg, így egy teljes állomány átvizsgálása munkaszálakra vagy folyamatokra skálázható, munkaegységenként egy TPDFlib példánnyal és köztük mindenféle versengés nélkül. Az az erőforrás, amely fegyelmet kíván, maga a leíró. A CheckFileCompliance minden nem nulla eredménye lefoglalva marad, amíg meg nem hívja a ReleaseStringList metódust, és az a hosszan futó kapu, amely elfelejti elengedni őket, nem omlik össze, csak lassan szivárogtatja a memóriát, amíg valaki keresni nem kezdi az okát

Jelentés embereknek, diff a build-kapunak

Az észrevételek listája a kapu számára jó alak, a sabloncsapatnak küldött levélhez viszont rossz. A CreatePreflightReport ugyanazt az elemzést olvasható prózaként adja vissza, a CreatePreflightReportEx egy jelentésformátum-választóval egészíti ki, a SavePreflightReport pedig lemezre írja, hogy a jelentés a kiszállított dokumentumcsomag részeként utazhasson. Bőven van olyan archiválási szerződés, amely ezt a jelentést önálló szállítandóvá teszi, nem csupán belső melléktermékké

A családnak az a tagja, amely csendben kiérdemli a helyét, a ComparePreflightReports. A megfelelőség ugyanolyan regressziós felület, mint bármely más viselkedés. Egy sablonmódosítás, egy frissen licencelt vállalati betűkészlet vagy egy könyvtárfrissítés mind behozhat olyan észrevételt, amely a múlt kiadásban még nem volt ott, és egyik sem jelenti be magát. Tartson referenciajelentéseket néhány jellemző dokumentumról verziókövetés alatt, generálja újra őket minden változtatás után, és futtassa a ComparePreflightReports hívást a különbség kiszámítására. Az üres diff megőrzésre érdemes kiadási melléktermék. A váratlan észrevétel megbuktatja a buildet, és ez sokkal olcsóbb hely a felfedezésére, mint az audit

Elsőre átmenő kimenet előállítása

A preflight a máshonnan érkező fájlokon termeli meg az árát. A saját kód által előállított dokumentumoknál a sértések generálás utáni megtalálása és visszafoltozása a lassú kerülőút. A PDF Library for Delphi mindkét szabványhoz hoz egy generálás oldali módot, és ugyanarra a dokumentumra mindkettő bekapcsolható:

PDF Library for Delphi diagram a skálázott elővizsgálati bevitelről: munkásonként egy streaming könyvtárpéldány, kapuzott megnyitások a feltöltések befejezése után, és felszabadított leletlisták
A kapuk csak az átvitelek befejezése után nyílnak meg, minden munkaszál csak olvasható módon streameli a bemenetet egy privát könyvtárpéldányon keresztül, és minden visszaadott handle tartozik egy felszabadítással
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: a PDF/UA megköveteli
    // ... ide jön a címkézett tartalom rajzolása ...
    Diag := Pdf.GetPDFUADiagnostics;
    if Diag <> '' then
      Writeln('fix before shipping: ', Diag);
    Pdf.SaveToFile('statement.pdf');
    // a mérvadó preflight a mentett fájlon fut:
    Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
  finally
    Pdf.Free;
  end;
end;

A csapda a mentés idejére rejtőzik. A megfelelőségi javítások közül több nem a mód bekapcsolásakor, hanem a dokumentum sorosítása közben történik: a nyomtatási jelző kikényszerítése a jegyzeteken, az alapértelmezett AFRelationship kiírása a PDF/A-3 beágyazott fájljaihoz, a tabulátorsorrend és az űrlapmező-leírások normalizálása a PDF/UA kedvéért. A memóriában ülő dokumentum nem bájtazonos azzal, amely a lemezre kerül, ezért az egyetlen valamit is jelentő preflight ítélet az, amely a mentett fájlból származik. Magát a statement.pdf fájlt validálja. Ne következtessen a megfelelőségre a még memóriában lévő objektumból, mert azok a bájtok, amelyeket megítélne, nem azok, amelyeket kiszállított

PDF Library for Delphi diagram a mentéskori megfelelőségi javításokról, amelyek a szerializáció alatt lépnek életbe, ezért az elővizsgálat a mentett PDF fájlhoz tartozik, nem a memóriabeli modellhez
A szerializálás kikényszeríti az annotációs nyomtatási jelzőket, alapértelmezést ad az AFRelationship-nek és normalizálja a tabulátorsorrendet, így a memóriavizsgálat olyan bájtokat ítél meg, amelyeket soha senki nem szállít

Azok a számlázási forgatókönyvek, amelyek a vizuális dokumentum mellett géppel olvasható XML-t is visznek, a ZUGFeRD és a Factur-X mintáját követik, amely a PDF/A-3 formátumra épül. Ezeknek kifejezetten be kell állítaniuk a csatolmány viszonyát a SetPDFA3DefaultAFRelationship hívással, mivel az ISO 19005-3 minden beágyazott fájltól megköveteli, hogy kimondja a dokumentumhoz fűződő szerepét. Hagyja beállítatlanul, és a beágyazott XML csak egy célját nem közlő adatcsomó lesz, amit a validátor észre is vesz

Független bírók: veraPDF és Acrobat

Az előállító ne legyen egyedüli bírája a saját kimenetének. A PDF Library for Delphi ellenőrzői gyors, strukturált ítéleteket adnak folyamaton belül, és pont ez kell a forró útvonalra, de egy archiválási köteg kiadási kapujának akkor is át kell engednie a kimenetet olyan validátoron, amelyet nem a saját csapata írt. A veraPDF a PDF/A közösségi karbantartású referenciamegvalósítása, és az az eszköz, amelyet a legtöbb archívum megnevez az átvételi feltételeiben, tehát ehhez érdemes igazodni. Az Acrobat preflight profiljai hasznos döntőbírók, amikor a veraPDF és a folyamaton belüli ellenőrzés nem ért egyet. Minden eltárolt jelentés mellé jegyezze fel a validátor nevét és verzióját. Az az állítás, hogy egy fájl átment a veraPDF vizsgálatán, nagyon keveset mond a build száma nélkül, amelyik átengedte, hiszen az eszköz kiadásról kiadásra szigorítja a szabályait

A validátorok a szabványok peremén valóban nem értenek egyet, és ilyenkor nem az a válasz, hogy a szimpatikusabb eszközt választjuk. Zsugorítsa a fájlt olyan minimális mintára, amely még mindig kiváltja az eltérést, és olvassa össze a szabvány szövegével. Egy ilyen óra rendszerint a kettő valamelyikét hozza felszínre: vagy valódi eszközhibát, amelyet érdemes bejelenteni a fejlesztőknek, vagy egy olyan bekezdést, amelyet a csapat félreolvasott, és amelyet érdemes leírni a megfelelőségi jegyzetekbe, hogy a következő ember ne pereskedjen újra rajta

A titkosított bemenet rövidebb utat kap. Mindkét ellenőrző elfogad jelszó argumentumot, de a titkosítási szótárral rendelkező PDF/A-1 fájl már eleve nem megfelelő, mert az ISO 19005-1 kereken tiltja a titkosítást, így a titkosított beküldés bármilyen mélyebb elemzés előtt elutasítható. Annak kibogozása, hogy egy titkosítási szótár valójában mit enged meg, önálló feladat, amelyet a PDF-titkosítás és jogosultságok auditálása tárgyal

A PDF/UA észrevételei szinte mindig oda vezetnek vissza, ahogyan a struktúrafát eredetileg megszerkesztették, és az emögötti címkézési technikák a címkézett PDF struktúrafák építése Delphiben cikkben laknak. Azok az archívumok, amelyek digitális aláírást is megkövetelnek, párosítsák ezt a kaput a PAdES-aláírás és -validálás munkamenetével. A teljes preflight API-referencia a losLab PDF Library for Delphi termékoldalon található