Műszaki cikk

PDF/A implementációs korlátok és betűtípus-kódolás-ellenőrzések

A PDFium Component validálja az ISO 19005-1 Annex C implementációs korlátokat — 127 bájtos név-tokenek, 8191 tömbelem, 4095 szótárbejegyzés és 28 szint tároló-beágyazás — és jelent egy olyan szimbolikus TrueType betűtípust, amely /Encoding bejegyzést hordoz. Mindkét ellenőrzés a bájtszkennelési úton fut, így egy Delphi vagy Lazarus alkalmazás DLL betöltése nélkül megkapja az ítéletet

Ezek azok a hibák, amelyek a leginkább meglepik az embereket, mert a dokumentum jónak tűnik. Renderelődik, nyomtat, minden betűtípus be van ágyazva, a kimeneti szándék jelen van. Aztán egy validátor elutasítja egy olyan szótár miatt, amely 4096 bejegyzéssel rendelkezik, és semmi a látható dokumentumban nem magyarázza, miért

Mit védnek valójában az Annex C korlátok?

Az interoperabilitást olyan implementációkkal, amelyek megelőzik a generátorunkat. Az Annex C a PDF Reference implementációs korlátait viszi át minden PDF/A részbe, és a számok nem önkényesek — azt írják le, amit egy megfelelő olvasónak történelmileg kötelező volt kezelnie. Egy olyan fájl, amely túllépi őket, tökéletesen megnyílhat egy modern megjelenítőben, és megbukhat abban az archív olvasóban, amelyre egy iratkezelő rendszer tizenöt éve standardizált, ami pontosan az a helyzet, amelyet a PDF/A megelőzni hivatott

A négy korlát inkluzív. Egy pontosan 127 bájtos név-token validál; 128 nem. Egy pontosan 8191 elemű tömb validál; 8192 nem. A PDFium Component mindkét oldalát minden határnak rögzíti a tesztkészletében ezért, mert egy off-by-one egy korlát-ellenőrzésben a legrosszabb fajta validátort eredményezi: olyat, amely elutasítja a megfelelő fájlokat, és amúgy is elhiszik

uses FPdfPdfa;

var
  Src: TFileStream;
  Res: TPdfAValidationResult;
begin
  Src := TFileStream.Create('archive.pdf', fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfACompliance(Src);
    if pvaiArrayOverLimit in Res.Issues then
      Memo1.Lines.Add('An array carries more than 8191 elements');
    if pvaiDictOverLimit in Res.Issues then
      Memo1.Lines.Add('A dictionary carries more than 4095 entries');
    if pvaiNestingOverLimit in Res.Issues then
      Memo1.Lines.Add('Containers nest deeper than 28 levels');
    if pvaiNameOverLimit in Res.Issues then
      Memo1.Lines.Add('A name token is longer than 127 bytes');
  finally
    Src.Free;
  end;
end;

Mely generátorok érik el valójában ezeket a korlátokat?

Olyanok, amelyek strukturát programozottan építenek, ami a legtöbb üzleti kimenet. Egy több ezer mezővel rendelkező űrlap egy olyan /Annots tömböt vagy AcroForm /Fields tömböt állít elő, amely túlnő 8191-en. Egy olyan oldal, amelynek erőforrás-szótára generált képenként vagy betűtípus-példányonként egy bejegyzést halmoz fel, átlépi a 4095-öt. Mélyen generált szerkezeti fák — egy rekurzíóval, egy beágyazott adatmodell fölött épített tagged dokumentum — 28 szint mellett mennek el észrevétlenül, mert senki sem néz beágyazási mélységet

A hosszú nevek más szokásból fakadnak: adat kódolása név-tokenekbe. Egy ügyfél-azonosítóból épített színezőnév, egy teljes elérési útról elnevezett opcionális-tartalom-csoport, egy űrlapmező, amelynek teljes neve hat szintű hierarchiát fűz össze. A nevek olcsóan generálhatók és könnyen hosszúra tehetők, és a 127 bájt gyorsabban eltűnik, mint várnánk, amint egy UTF-8 kódolású címke is szerepel a képben

A javítás minden esetben strukturális. Osszuk fel a tömböt, osszuk fel a szótárt, laposítsuk a beágyazást, rövidítsük a nevet — az egyes problémákra vonatkozó preflight-ajánlás megnevezi a konkrét korlátot, ahelyett hogy azt mondaná, a fájl érvénytelen. A jelölő-injektálás itt nem segít: ezek nem metaadat-hivatkozások, hanem az objektumgráf alakja

Miért nem hordozhat egy szimbolikus TrueType betűtípus /Encoding-ot?

Mert az ISO 19005-1 §6.3.7 szimbolikus TrueType betűtípusoknál csak a betűtípus beépített cmap-jét engedélyezi, és egy /Encoding bejegyzés ellentmondana neki. Egy szimbolikus betűtípus a saját feltételei szerint képez le kódokat glyphekre — ez az, amit szimbolikus jelent. Adjunk hozzá egy kódolási táblát, és már két válasz van a „melyik glyphe jelöli ki a 0x41-es bájt” kérdésre, a fájlban egyetlen szabály nélkül, amely megmondaná, melyik nyer. Különböző olvasók máshogy oldják fel, és egy olyan dokumentum, amely az egyik megjelenítőben szövegként renderelődik, a másikban dingbatsként

A PDFium Component a szimbolikus jelölőt a /FontDescriptor-ból olvassa, akár a leíró inline van írva a betűtípus-szótárban, akár indirekt hivatkozással. Egy nem szimbolikus TrueType betűtípus megtartja a kötelező /WinAnsiEncoding vagy /MacRomanEncoding bejegyzését megjelölés nélkül, mert a nem szimbolikus betűtípusoknál a kódolás pontosan az, amit a szabvány kér. Az ellenőrzés az ellentmondáson sül el, nem a kódolás jelenlétén

if pvaiSymbolicTrueTypeEncoding in Res.Issues then
  Memo1.Lines.Add(
    'A symbolic TrueType font carries /Encoding; PDF/A admits only its ' +
    'built-in cmap (ISO 19005-1 6.3.7)');

Ennek a hibának a gyakori forrása az a részbetűkészlet-képzés, amelyet egy olyan producer végez, amely minden TrueType betűtípust ugyanúgy kezel. Symbol, Wingdings, vonalkód-betűtípusok és ikon-betűtípusok a szokásos hordozók — pontosan azok a betűtípusok, amelyeket egy üzleti dokumentum checkboxokhoz, logókhoz és vonalkódokhoz használ, és pontosan azok, amelyeket senki sem vizsgál újra, amikor egy dokumentum „betűtípusok” miatt bukik meg a validáción

Hogyan érkeznek a problémák egy preflight-jelentésbe?

A négy tárolókorlót struktúra alá osztályozzák; a szimbolikus TrueType kódolási problémát tartalom alá. Ez a felosztás számít, amikor egy jelentés két különböző emberhez megy: a struktúra-megállapítások általában ahhoz tartoznak, aki a generátort írta, a tartalom-megállapítások ahhoz, aki az eszközöket szolgáltatta

Minden probléma egy ajánlást hordoz, amely konkrét kifejezésekkel nevezi meg az orvoslást — rövidítsük a név-tokeneket 127 bájtra vagy kevesebbre, osszukuk fel a tömböket úgy, hogy egy se hordozzon 8191-nél több elemet, távolítsuk el az /Encoding-et a szimbolikus TrueType betűtípusokból. Egy olyan jelentés, amely azt mondja „nem PDF/A-megfelelő”, vizsgálatot indít. Egy olyan jelentés, amely megmondja, melyik korlát lépődött túl és mivel, lezár egyet

Validálás DLL nélkül, és miért számít ez itt?

A fenti összes ellenőrzés a fájl bájtjai ellen fut, így működnek egy olyan szolgáltatásban, amelyhez nincs PDFium bináris telepítve, egy build-lépésben, vagy egy olyan gépen, ahol a natív DLL betöltése házirendi probléma. Ez a PDFium Component szándékos vonala: azokat az ellenőrzéseket, amelyek struktúrából megválaszolhatók, struktúrából válaszolják meg, a DLL-t pedig fentartják azoknak, amelyeknek valóban renderelőmotorra van szükségük

A körülötte lévő workflow-hoz — validáció futtatása egy mappán, jelentések előállítása és döntés arról, mit tegyünk a megállapításokkal — lásd a PDF/A preflight-validáció Delphiben és a kötegelt preflight-jelentés CLI átjárásait. Az ezen ellenőrzések felett álló archív profilválasztáshoz a PDF/A archív megfelelőség jegyzetei tárgyalják, melyik részt és szintet célozzuk, mielőtt elkezdenénk megállapításokat javítani

A PDFium Component a PDFium motort Delphihez, C++Builderhez és Lazarushoz csomagolja magas szintű VCL API-val és olyan megfelelőség-ellenőrzőkkel, amelyek DLL-lel vagy anélkül futnak — a támogatott szabványokat és platformokat a PDFium Component termékoldal sorolja fel