Techninis straipsnis

PDF/A įgyvendinimo ribos ir šriftų kodavimo tikrinimai

PDFium Component tikrina ISO 19005-1 Annex C įgyvendinimo ribas — 127 baitų pavadinimo leksemos, 8191 masyvo elementų, 4095 žodyno įrašų ir 28 konteinerių įdėjimo lygius — ir praneša apie simbolinį TrueType šriftą, nešantį /Encoding įrašą. Abu tikrinimai vyksta baitų skenavimo kelyje, todėl Delphi ar Lazarus programai verdiktas grįžta neapkrovus PDFium DLL išvis

Tai yra triktys, stebinančios žmones labiausiai, nes dokumentas atrodo geras. Jis atvaizduojamas, spausdinamas, kiekvienas šriftas yra įterptas, išvesties intentas yra. Tada validatorius jį atmeta dėl žodyno, turinčio 4096 įrašus, ir niekas matomame dokumente nepaaiškina kodėl

Ką iš tikrųjų saugo Annex C ribos?

Suderinamumą su įgyvendinimais, ankstesniais už jūsų generatorių. Annex C perneša PDF nuorodos įgyvendinimo ribas į kiekvieną PDF/A dalį, ir skaičiai nėra savavališki — jie apibūdina, ką istoriškai turėjo apdoroti atitinkamas skaitytuvas. Failas, viršijantis jas, gali atsidaryti tobulai šiuolaikinėje žiūryklėje ir trikti archyviniame skaitytuve, kurį įrašų sistema standartizavo prieš penkiolika metų, kas ir yra būtent tas scenarijus, kurio išvengti egzistuoja PDF/A

Visos keturios ribos yra imtinės. Pavadinimo leksema iš lygiai 127 baitų praeina tikrinimą; 128 — ne. Masyvas su lygiai 8191 elementais praeina; 8192 — ne. PDFium Component pritvirtina abi kiekvienos ribos puses savo testų rinkinyje dėl tos priežasties, nes vienetu paklaida ribų tikrinime gamina blogiausią validatorių: tokį, kuris atmeta atitinkančius failus ir kuriuo vis tiek tikima

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;

Kurie generatoriai iš tikrųjų pasiekia šias ribas?

Tie, kurie stato struktūrą programiškai, o tai yra didžioji verslo išvesties dalis. Forma su keliais tūkstančiais laukų gamina /Annots masyvą ar AcroForm /Fields masyvą, peraugantį 8191. Puslapio, kurio ištekliaus žodynas kaupia vieną įrašą kiekvienam sugeneruotam paveikslui ar šrifto atvejui, kerta 4095. Giliai generuojami struktūros medžiai — pažymėtas dokumentas, statomas rekursija per įdėtą duomenų modelį — pereina 28 lygius, niekam nepastebint, nes niekas nežiūri į įdėjimo gylį

Ilgi pavadinimai ateina iš kitokio ipročio: duomenų kodavimas į pavadinimo leksemas. Dažiklio pavadinimas, statomas iš kliento identifikatoriaus, pasirinktinio turinio grupė, pavadinta pagal pilną failo kelią, formos laukas, kurio pilnai kvalifikuotas pavadinimas sujungia šešis hierarchijos lygius. Pavadinimai pigūs generuoti ir lengvai padaromi ilgi, o 127 baitai dingsta greičiau, nei tikitės, kai įsikiša UTF-8 užkoduota etiketė

Pataisa kiekvienu atveju yra struktūrinė. Skaidykite masyvą, skaidykite žodyną, plokštinkite įdėjimą, trumpinkite pavadinimą — skrydžio prieš tai rekomendacija kiekvienai problemai įvardija konkrečią ribą, užuot sakiusi, kad failas neteisingas. Žymeklių injekcija čia negali padėti: tai nėra metaduomenų pretenzijos, tai yra objektų grafo pavidalas

Kodėl simbolinis TrueType šriftas neturi nešti /Encoding

Nes ISO 19005-1 §6.3.7 simboliniams TrueType šriftams pripažįsta tik šrifto įmontuotą cmap, o /Encoding įrašas jam prieštarautų. Simbolinis šriftas savo sąlygomis susieja kodus su glifais — tai ir reiškia simbolinis. Pridėkite kodavimo lentelę ir dabar yra du atsakymai į klausimą „kurį glifą parenka baitas 0x41“, be jokios taisyklės faile, sakančios, kuris laimi. Skirtingi skaitytuvai išsprendžia jį skirtingai, ir dokumentas, kuris vienoje žiūryklėje atvaizduojamas kaip tekstas, kitoje atvaizduojamas kaip dingbats

PDFium Component skaito simbolinę vėliavėlę iš /FontDescriptor, nepriklausomai nuo to, ar deskriptorius užrašytas inline šrifto žodyne, ar nurodytas netiesiogiai. Nesimbolinis TrueType šriftas išlaiko savo privalomą /WinAnsiEncoding arba /MacRomanEncoding nepažymėtas, nes nesimboliniams šriftams kodavimas yra lygiai tai, ko reikalauja standartas. Tikrinimas suveikia ant prieštaravimo, o ne ant kodavimo buvimo

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)');

Praktinis šio defekto šaltinis yra šriftų poaibių sudarymas, atliekamas gamintojo, kuris traktuoja kiekvieną TrueType šriftą vienodai. Symbol, Wingdings, brūkšninio kodo šriftai ir piktogramų šriftai yra įprasti nešėjai — būtent šriftai, kuriuos verslo dokumentas naudoja žymimiesiems langeliams, logotipams ir brūkšniniams kodams, ir būtent tie, kurių niekas nebetikrina, kai dokumentas triksta tikrinimą dėl „šriftų“

Kaip problemos patenka į skrydžio prieš tai ataskaitą

Keturios konteinerių ribos klasifikuojamos pagal struktūrą; simbolinio TrueType kodavimo problema klasifikuojama pagal turinį. Tas padalijimas svarbu, kai ataskaita eina dviems skirtingiems žmonėms: struktūros išvados paprastai priklauso tam, kas rašė generatorių, o turinio išvados — tam, kas pateikė turtus

Kiekviena problema neša rekomendaciją, įvardijančią gydymą konkrečiais terminais — trumpinkite pavadinimų leksemas iki 127 baitų ar mažiau, skaidykite masyvus, kad joks nešiotų daugiau nei 8191 elementų, šalinkite /Encoding iš simbolinių TrueType šriftų. Ataskaita, sakanti „neatitinka PDF/A“, pradeda tyrimą. Ataskaita, sakanti, kuri riba buvo viršyta ir kuo, jį užbaigia

Tikrinimas be DLL ir kodėl tai čia svarbu

Visi aukščiau esantys tikrinimai vykdomi prieš failo baitus, todėl jie veikia paslaugoje, kurioje nėra įdiegto PDFium dvejetainio failo, darbo eigos žingsnyje ar kompiuteryje, kuriame natyvaus DLL įkėlimas yra politikos problema. Tai sąmoninga PDFium Component dizaino linija: tikrinimai, į kuriuos galima atsakyti iš struktūros, atsakomi iš struktūros, o DLL rezervuotas tiems, kuriems iš tikrųjų reikia atvaizdavimo variklio

Dėl supančios darbo eigos — tikrinimo vykdymo per aplanką, ataskaitų gamybos ir sprendimo, ką daryti su išvadomis — žr. PDF/A skrydžio prieš tai tikrinimo Delphi ir paketinio skrydžio prieš tai ataskaitos CLI aprašymus. Dėl archyvinio profilio parinkties, esančios virš visų šių tikrinimų, PDF/A archyvinės atitikties pastabos padengia, kurią dalį ir lygį pasirinkti, prieš pradedant taisyti išvadas

PDFium Component apgaubia PDFium variklį, skirtą Delphi, C++Builder ir Lazarus, su aukšto lygio VCL API ir atitikties validatorių rinkiniu, veikiančiu su DLL ar be jos — žr. PDFium Component produkto puslapį dėl palaikomų standartų ir platformų