Technický článek

Převod PDF na PDF/A a oprava jeho metadat

ConvertToPDFA mění běžný dokument na archivační jediným voláním: odstraní to, co vybraná část zakazuje, přidá to, co část vyžaduje, prohlásí část, kterou dokument deklaruje, a poté výsledek zkontroluje. O tvrzení, že podmínky byly splněny, se hlásí teprve tehdy, když kontrola projde, a GetPDFAConversionReport vypíše, co bylo provedeno a co ještě stojí v cestě

Právě tato poslední vlastnost je rozhodnutí, které stojí za to rozvést. Konvertor, který razítko tvrzení přidá bez kontrory, je horší než žádný konvertor, protože soubor, který tvrdí, že je archivační, a není, projde rovnou systémy, které by ho jinak zachytily. Selhání se projeví o léta později, při auditu, u dokumentu, který už nikdo nedokáže znovu vygenerovat

Proč platně vyhlížející PDF neprojde kontrolou PDF/A?

Nejčastěji proto, že se neshodují dvě místa, jimiž PDF říká, kdo ho napsal. Validátor přečte jak informační slovník dokumentu, tak XMP packet a odmítne soubor, v němž se liší — a většina souborů, které na tomto bodu selžou, prostě nikdy neměla XMP polovinu vůbec zapsánu

RepairDocumentMetadata je uvádí do souladu a vrací počet opravených položek. Tam, kde hodnotu nese jen jedna polovina, se druhá doplní z ní, takže se nic už zaznamenaného nezahodí. Nikdo nemusí rozhodovat, která kopie je autoritativní, protože v praxi je jedna kopie prázdná

Ve stejné volbě je i druhá oprava, která zachytí jemnější případ. Dokument nastavený do režimu PDF/A dostane zpět identifikaci standardu, pokud se ztratila — což se stává kdykoli, kdy volající dodá vlastní XMP packet. Bez té identifikace validátor čte soubor jako běžné PDF a ohlásí každé pravidlo deklarované části jako nesplněné — efektně vyhlížející selhání s jedinou malou příčinou

var
  Lib: TPDFlib;
  Repaired: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('incoming.pdf', '');
    Repaired := Lib.RepairDocumentMetadata;
    Log(Format('%d metadata entries brought into agreement', [Repaired]));
    Lib.SaveToFile('incoming-fixed.pdf');
  finally
    Lib.Free;
  end;
end;

Volba části před převodem

SetPDFAMode a ConvertToPDFA sdílejí stejné číslování režimů a tři z hodnot jsou nedávné. Režim 9 je PDF/A-4, část postavená na PDF 2.0. Režim 10 je PDF/A-4e, který navíc povoluje 3D a bohatá média, a režim 11 je PDF/A-4f, který povoluje vložený soubor libovolného formátu

Část 4 se identifikuje jinak než části před ní: číslem části a rokem vydání své části, bez písmene shody u čistého PDF/A-4 a s písmenem E nebo F u dvou rozšíření. Kontrola rozpozná část 4, posuzuje její soubory podle PDF 2.0 místo 1.7 a ohlásí soubor části 4, který neuvádí rok revize

Každý vložený soubor v dokumentu části 4 uvádí, jak se vztahuje k dokumentu, jak vyžadují části 3 i 4. To je pravidlo, které dříve zachytávalo běžné přílohy: vztah se zapisoval jen pro přílohy po první a nikdy pro poslední, takže dokument s jedinou přílohou — běžný případ — nenese žádný vztah a na tomto bodě selhával v validaci

var
  Verdict: Integer;
begin
  Lib.LoadFromFile('report.pdf', '');
  Verdict := Lib.ConvertToPDFA(9);        // 9 = PDF/A-4, 10 = 4e, 11 = 4f
  Memo1.Lines.Text := Lib.GetPDFAConversionReport;
  if Verdict = 1 then
    Lib.SaveToFile('report-pdfa4.pdf')
  else
    Log('conversion incomplete - see the report for what stands in the way');
end;

K čemu slouží konverzní report

K rozhodnutí, co dál. Konverze, která uspěje, report nepotřebuje; konverze, která neuspěje, je celým důvodem, proč report existuje. Některé překážky dokáže odstranit konvertor a některé ne — šifrování, zakázaný obsah nesoucí význam, program písma, které prostě není nikde v počítači k dispozici. Report rozlišuje, co bylo provedeno, od toho, co zůstává, čímž se „konverze selhala" mění v pracovní položku

S verdiktem zacházejte jako s branou v dávkové rouře. Převeďte, přečtěte verdikt a podle něj soubor rozdělte: úspěšné archivujte, zbytek zařaďte člověku s přiloženým reportem. To, co byste dělat neměli, je ukládat výstup neúspěšné konverze do archivu, jen protože vypadá lépe než vstup — nyní nese tvrzení, které kontrola odmítla potvrdit

Čtení značky, kterou soubor už nese

Před jakýmkoli převodem byste měli vědět, co dokument říká sám o sobě. Kontrola PDF/A, která neumí přečíst existující značku standardu, posuzuje každý soubor podle části 1 bez ohledu na to, co deklaruje, takže naprosto platný dokument PDF/A-2 nebo PDF/A-3 je ohlášen jako bez značky a s příliš vysokou verzí — opak pravdy

Značka se čte bez ohledu na to, zda ji producent zapsal jako XMP element nebo jako atribut. Obě formy jsou běžné XMP a přijímat jen jednu z nich nechává soubory od jiných producentů vypadat jako neznačkované. Pokud jste se někdy divili, proč dokument, který jinde projde validací, ve vaší vlastní rouře selže, tohle je dobré místo, kde začít hledat

Sanitizace před archivací a chyba, kterou stojí za to znát

Archivační konverze a sanitizace často běží společně, protože obsah, který chce odstranit bezpečnostní zásada, se silně překrývá s obsahem, který PDF/A zakazuje. SanitizeDocument odstraňuje JavaScript a odstranění posledního skriptu rovněž odstraňuje prázdný strom jmen, který po sobě zanechá — strom, který by jinak čtečce stále říkal, že dokument skripty nese

Druhá polovina byla odpracována tvrdě: chyba off-by-one v seznamu balíčků znamenala, že sanitizace hlásila odstranění skriptů, aniž by jakýkoli odstranila, takže sanitizovaný dokument při otevření stále spouštěl své skripty. Je to dobrý argument pro obecný princip, na kterém stojí celý tento článek — výsledek ověřte raději, než abyste spoléhali na operaci, a to jak v knihovně, tak ve vlastní rouře

Okolní archivační práci pokrývají průvodci preflightem PDF/A a PDF/UA, skutečnou redakcí a odstraněním obsahu a rozšířenými schématy XMP pro Factur-X v PDF/A-3, který rozebírá stranou metadat, když archivovaný dokument zároveň nese strukturovaná fakturační data

PDFlibPas je nativní Pascal PDF knihovna pro Delphi, C++Builder a Lazarus, takže konverze, oprava i validace běží uvnitř vašeho vlastního procesu bez externího nástroje v řetězci — viz stránka produktu PDFlibPas pro podporované části PDF/A a platformy